海外のデザインシステムに見る、気になる実装 〜 SassのMixin`exports` 〜

デザインシステムは、IT系サービスのトレンドとして注目を集め続けております。そんなデザインシステムですが、世間で言及される内容は、デザインシステムの役割や意義、内包されるデザインパターンと行った、デザインよりの話がほとんどのように感じます。
でも、実装だって面白いんです。海外のデザインシステムは、Github上でソースコードを管理されていることが多いです。つまり、タダで覗き見できるのですねぇ。

ということで、不定期ですが、僕がデザインシステムのコードを覗いて、気になった実装をピックアップしてご紹介しようと思います。
ピックアップの対象は "HTML・CSS(Sass)・JS" でございます。
初回はGOV.UKからピックアップ。

SassのMixin `exports`

// このコードはGOV.UKのコードを引用し、コメントを削除しています。

$_govuk-imported-modules: () !default;

@mixin govuk-exports($name) {
  @if (index($_govuk-imported-modules, $name) == null) {
    $_govuk-imported-modules: append($_govuk-imported-modules, $name) !global;
    @content;
  }
}
出典元:GOV.UK frontend
※ IBMのCarbon Design systemでも同様の仕組みを実装しています。
https://github.com/IBM/carbon-components/blob/master/src/globals/scss/_import-once.scss

今回はGOV.UKの実装からご紹介します。
上記はSassのMixinです。分割したSassファイルを安全にimportする仕組みを作ります。

Note: Sassはスタイルシートを書くためのスクリプト言語です。
Sassファイルはビルドして、最終的にはCSSに変換してWebアプリに使用されます。詳細については、Sassでググるとたくさんヒットするので、そちらをご覧ください。

さて、何が安全なのか説明するためには、Sassの "@import" に触れる必要がございます。

Sassの "@import" 機能は貧弱

Sassは "@import" という機能を提供しております。これを利用することで、分割したSassファイルを別のファイルから読み込むことが可能となります。

この機能は大変便利ですが、使用には注意が必要です。
なぜなら、読み込むSassファイルに重複がある場合、重複がそのままCSSに反映されてしまうのです。
例えば、以下のコードをご覧ください。Sassファイルの中で、"button"を挟んで、"text" を2回読み込んでいます。

// 例: Sassファイルの重複
@import 'components/text';   // 中身は .text { color: red; }
@import 'components/button'; // 中身は .button { background: #ccc; }
@import 'components/text';

ビルド結果は下のようになります。

// ビルドしたCSSファイル
.text { color: red; }
.button { color: red; }
.text { color: red; }

"text" のスタイルが重複して読み込まれてしまいます。
これは、ファイルサイズの肥大化を招きます。さらには、重複したスタイル同士が競合するリスクも潜んでいます。

この貧弱な機能を、改善しようとしているのが、exports なのです。

exportsの仕組み

再度、GOV.UKのmixinを見てみましょう。

// mixin.scss
// このコードはGOV.UKのコードを引用し、コメントを削除しています。

$_govuk-imported-modules: () !default;

@mixin govuk-exports($name) {
  @if (index($_govuk-imported-modules, $name) == null) {
    $_govuk-imported-modules: append($_govuk-imported-modules, $name) !global;
    @content;
  }
}

govuk-exportsは、呼び出された時に、引数に挿入されたコンポーネント名が $_govuk-imported-modules に登録されていないかチェックします。もし登録済であれば、処理をストップします。一方で、未登録の場合は、コンポーネント名を$_govuk-imported-modulesに登録し、内包するスタイルをビルドに含めます。

簡単に言うと、重複してimportされても、CSSには一度しか反映されない、と言うことです。
使うときは下のようになります。

// _button.scss

// 必要な
@import 'common/mixin'; // 上のmixinを読み込む
@import 'common/settings'; // 変数の設定ファイル(あれば)


@include govuk-exports('button') { // $nameにコンポーネント名を挿入する
  .button {
    background: red;
  }
}

// ---

// buttonを使うときは、利用先ファイルでいつも通りimport
@import 'button';

このMixin、本当によく出来ててます。
これを利用することで、Node.jsのrequireのように、必要なモジュールを明示的に示すことができるようになります。
これは、実際のレポジトリを覗いていただいた方が分かりやすいと思います。

最後に

こんな感じでたまにデザインシステムの実装を紹介していこうと思います。
(だんだん説明が雑になってますが、ご容赦くださいまし。)

次回は、Carbon Design Systemの中からピックアップしようと考えています。でわー。

この記事が気に入ったらサポートをしてみませんか?