こんにちは、フロントエンドチームです。
今週のフロントエンド定例の内容を記載します。
フロントエンド定例について、以前の記事(ランサーズのフロントエンドチームが取り組んでいること)でお伝えしたのですが、毎週金曜日に開催しており、実際の業務で取り組んでいることや気になった技術情報等をシェアしあう会になっています。
以下、今週の内容です。
@syo_igarashi
独自のStylelint拡張をかいた
デザインシステムを進めていく上でカラーコードなども定数化されているのでコードの値参照を共通のファイルからするように警告を表示させる対応をしました。
作り方はstylelint-pluginを作ってみる会の内容がわかりやすくテストコード経由にlintの実装が進められやすかったです。
実装のコードを記載すると
// eslint-disable-next-line @typescript-eslint/no-var-requires
const stylelint = require('stylelint');
// eslint-disable-next-line @typescript-eslint/no-var-requires
/**
* sassで管理しているカラーコードをJSON管理したファイル
* @var {
* '#fff': 'colorWhite',
* ...
* } colorsJSON
*/
const colorsJSON = require('@lancers/design_guideline/scripts/colors.json');
const ruleName = '@lancers/design-guideline';
const messages = stylelint.utils.ruleMessages(ruleName, {
expected: 'Expected...',
});
module.exports = stylelint.createPlugin(ruleName, function () {
return function (root, result) {
const validOptions = stylelint.utils.validateOptions(result, ruleName, {});
root.walkDecls((decl) => {
const matched = decl.value.match(/#.*/);
if (!matched) {
return;
}
const definedColor = colorsJSON[decl.value.toLowerCase()];
if (definedColor) {
stylelint.utils.report({
ruleName,
result,
message: `${messages.expected} ${decl.value} -> ${definedColor} [see colors.scss]`,
node: decl,
});
}
});
if (!validOptions) {
return;
}
};
});
module.exports.ruleName = ruleName;
module.exports.messages = messages;
上記のコードをテストファイルを経由に検証します
// eslint-disable-next-line @typescript-eslint/no-var-requires
const { ruleName } = require('.');
// eslint-disable-next-line no-undef
testRule({
plugins: ['./index.js'],
ruleName,
config: true,
fix: false,
accept: [
{
code: `.class {
margin: 0;
color: $hoge;
}`,
},
],
reject: [
{
code: `.class {
margin: 0;
color: #fff;
}`,
message:
'Expected... (@lancers/design-guideline) #fff -> colorWhite [see colors.scss]',
},
{
code: `.class {
margin: 0;
color: #FFF;
}`,
message:
'Expected... (@lancers/design-guideline) #FFF -> colorWhite [see colors.scss]',
},
],
});
こんな感じの実装感覚で進められたので他に共通で使用したい関数なども拡張に入れていきたいと思います。
@stylelint/postcss-css-in-js によるemotionでのStylelintも検討しましたがESLint (TypeScript)での検知も可能な状態にしようかなと思います
補足等追記してます
https://zenn.dev/igara/articles/custom_stylelint
@high_g_engineer
デザインを実装する際に齟齬がうまれやすい「余白」
ランサーズのデザインシステムで策定している新しい余白ルールについて
- 基本8の倍数のpxで定義(maxは64px)
- 56pxは使用しない(64pxと比較時にデザイン的な意味の差が無かった為、64pxを採用)
- 例外的に4px、12pxだけは使用可能とする
- それ以外pxの余白は認めない
※上記ルールをデザイナーやエンジニア間の共通認識とする
※上記ルール以外でデザインが組まれている場合は、実装時ルールを適用後、デザイナーへ伝える
※今後、eslintでmargin, padding, grid-gapで指定されている値に関して、上記ルールが適用されていなければwarningを表示する仕組み化予定
8px指定のメリットは以下です。
- 要素のサイズや余白に秩序を持たせやすくなり、デザインの品質が向上するため。
- デザインルールを徹底しやすくなるため。
- 8の倍数で設計することで端数が発生しにくく、コンテンツのレイアウトや余白の秩序が維持しやすくなり、コーディングが進めやすくなるため。
- デザインとコーディングの両方の品質と速度が高まり、結果的にWebサイトやアプリ全体の品質が向上するため。
- 多くのデバイスの基準となる解像度に8の倍数が用いられており、汎用的なスクリーンサイズの基準に合わせやすいため。
参考:https://yuyakinoshita.com/blog/2019/02/10/design-by-multiple-of-8/
また、グリッドシステムという概念があるかと思いますが、そのレイアウトを意識的に組もうとすると、デザイナーもエンジニアも負荷が高まるのですが、8px縛りにすることで自然と目に見えないグリッドが発生するので、デザイン・レイアウトに秩序が生まれます。
上記の余白のルールに加えて、ボタンなどUIパーツの高さにも8pxルールを適用しています。
大きいものは、48pxで設計されていて、
小さいものは、32pxで設計されています。
ここまで定義すると一見良さそうに見えるのですが、余白や高さだけを定義しただけなので、実際に実際にデザインを作ったり、UIを実装したり際に、どの様に要素同士を組み合わせて利用するかの具体例が重要なので、下記のようなレベルのサンプルを作成できれば良いと考えています。
参考:https://style.monday.com/?path=/docs/foundations-spacing–page
また、こういったレイアウトを配置する際に、テキスト要素に設定されるline-heightのせいで、
上下の余白が計算しにくいといった問題がありますが、
そういった問題は、before, afterの疑似要素にネガティブマージンを入れれば解消できますので、デザインシステムのTextコンポーネントで吸収しようと思います。
↓こういった余計な余白を・・・
↓こうするということです。これにより、marginの計算が正確になります。
ちなみに、現状のランサーズのUIを実際に見てみると、
左右のmarginに5pxが指定されていたり、paddingに20pxが使われていたり
全体の高さは48pxになっているものの heightとmarginを複合した書き方になっていたり
ボタンの高さが48pxになっていなかったりします。
今後、Reactで作られていない部分もメンテナンスしていかないといけないと思いつつも
まずは、目の前のプロジェクトをReact + デザインシステムを使った構成で完成させることを目標に頑張っています。
次回の更新予定は、6/10(金)になります!
前回の定例内容はこちらから確認可能ですのでご興味いただければ下記のリンクから閲覧いただければと思います。