WIP: [CSS設計] YUKICSS - ITCSSベースのCSSアーキテクチャ

YUKICSS(ユキックス)は、様々な CSS 設計思想を取り入れた CSS 設計である。

ブログや EC サイトなど幅広い用途で不足なく使用することができる。

主に影響を受けている CSS 設計・思想

下記の CSS 設計に影響を受けている。

ITCSS

ITCSSの構造
ITCSSの構造

ディレクトリ構造は ITCSS のレイヤーをベースに構築している。
ITCSS のベースでは補いきれない部分を追加レイヤーとして定義している。

参考:

BEM (MindBEMding)

命名規則は MindBEMding を採用。

参考:


命名規則

クラス名は基本的にシングルクラスで命名するために、MindBEMdingを利用した命名を行う。

<!-- https://yandex.com/company/ - code -->
<div class="widget">
  <div class="widget__title"></div>
  <div class="widget__post">
    <a class="widget__post-header"></a>
    <div class="widget__date"></div>
  </div>
</div>

クラス名は下記の要素で構成する。

  • .Block
    コンポーネントの親要素 / 独立した要素
  • .Block__Element
    Block に紐付いた要素 / Block 内でいくつも存在できる
  • .Block--Modifier / .Block__Element--Modifier
    バリエーションや状態を変化させるときに指定する

組み合わせとしては、MindBEMding のルールに則っていれば問題ないが、block__element__elementblock__element--modifier--modifierのような形になるようであれば見直した方が良い。

ステート(状態)

MindBEMding のルールをそのまま踏襲すると、ステートを表現する際に

<div class="c-modal"></div>
<!-- ↕ -->
<div class="c-modal--open"></div>

といった命名となり、可読性や JavaScript などの切り替えに難がある。

そこで本設計では、状態を表すクラスの場合において「マルチクラス」を許容し、接頭辞としてis-を付ける。

<div class="c-modal"></div>
<!-- ↕ -->
<div class="c-modal is-open"></div>

構成レイヤー

下記のようなレイヤー構造になっている。基本的には ITCSS のレイヤー構造に準拠した形で付け加えている。(太字のものが既存の ITCSS から追加したレイヤー)

レイヤー 役割
1 Settings グローバル変数や全体の設定
2 Tools animationmixinfunctionなど
3 Icons アイコンの定義
4 Generic リセットスタイル定義
5 Elements 素の HTML 要素(a, h1…6 など)定義
6 Layouts レイアウト定義
7 Objects 装飾を持たないレイアウト定義(OOCSS)
8 Vendor npm などサードパーティ系ライブラリのスタイル定義
9 Components コンポーネント(UI パーツ)を定義
10 Parts コンポーネント同士の組み合わせなどの定義
11 Project グローバルヘッダーやグローバルフッターなど
12 Pages ページ固有の定義
13 Utilities (Trumps) ヘルパー・ユーティリティ系の定義

詳細度の広い順に定義をしていくため、下のレイヤーに行くにつれ詳細度は上がっていく。
上のレイヤーが下のレイヤーの定義へ影響を与えることはできない。

Settings

プリプロセッサなどで利用するグローバル変数や全体の設定を置く。

$font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
  "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji",
  "Segoe UI Symbol", "Noto Color Emoji" !default;

$white: #fff !default;
$black: #000 !default;
$gray: #f8f9fa !default;

Tools

プリプロセッサで利用する mixin や function などの定義を置く。

@function str-replace($string, $search, $replace: "") {
  $index: str-index($string, $search);

  @if $index {
    @return str-slice($string, 1, $index - 1) + $replace + str-replace(str-slice($string, $index +
            str-length($search)), $search, $replace);
  }

  @return $string;
}

@mixin text-truncate() {
  text-overflow: ellipsis;
  white-space: nowrap;
  overflow: hidden;
}

Settings, Tools までのレイヤーで CSS を記述しない。

Icons

ITCSS には無い新規追加のレイヤー

再利用可能なアイコンを定義する。
できるだけプレーンな状態で定義し、サイズや装飾は利用される Pages レイヤーなどで上書きをする。

.icon-required {
  display: inline-block;
  width: 1em;
  height: 1em;

  &::before {
    content: "";
    display: inline-block;
    width: 100%;
    height: 100%;
    background: url("~@src/image/icon-required.svg") no-repeat left top/contain;
  }

  // or
  svg {
    fill: currentColor;
  }
}

Generic

リセットスタイル(normalize.css など)や固有のリセットスタイル定義を置く。

@import "~normalize.css/normalize.css";
*,
*::before,
*::after {
  box-sizing: border-box;
}

h1,
h2,
h3,
h4,
h5,
h6 {
  margin-top: 0;
  margin-bottom: 0;
}

Elements

素の HTML 要素(a, h1…6 など)のスタイルを定義する。クラスセレクターなどは使用せず、要素セレクターのみで定義する。

a {
  color: #333;
  text-decoration: none;
}

h2 {
  color: #666;
}

Layouts

ITCSS には無い新規追加のレイヤー

装飾を持たないレイアウトを定義する。
後述の Objects レイヤーとは異なり、大きな粒度のレイアウトを定義する。

.l-single {
  margin: 0 auto;
  width: 64rem;
}

.l-multiple {
  display: flex;
  width: 32rem;
}

プレフィックス: .l-

Objects

装飾を持たないレイアウトを定義する。
Layout レイヤーよりも小さな粒度のレイアウトを定義する。

例えば、「フォームのインプット要素の組み合わせ」や「タイトルと説明の組み合わせ」のレイアウト。

.o-form-group {
  &__title {
    margin-bottom: 1rem;
  }

  &__input {
    margin-bottom: 2rem;
  }
}
.o-page-header {
  &__title {
    margin-bottom: 1rem;
  }

  &__description {
    text-align: center;
  }
}

プレフィックス: .o-

Vendor

ITCSS には無い新規追加のレイヤー

npm 経由で取得したサードパーティ系のスタイルの読み込みや個別スタイルを定義する。

// Swiper
@import "~swiper/swiper.scss";

// override
.swiper-button-prev {
  &:after {
    content: "←";
  }
}

.swiper-button-next {
  &:after {
    content: "→";
  }
}
// Vue.js
[v-cloak] {
  display: none;
}

他のレイヤーに影響を受けないように上位レイヤーで定義する。(下位のレイヤーで上書きをする)

Components

再利用可能で機能的なモジュールを定義する。

サイト内のコンポーネント(UI パーツ)を定義する。
さまざまな箇所で使えるようにするため、marginなどは持たせない。

.c-alert {
  padding: 1rem 2rem;
  border: 1px solid #343a40;
  background: #e9ecef;
}

プレフィックス: .c-

Parts

ITCSS には無い新規追加のレイヤー

一部の共通ページでの利用など再利用性が少なく、機能性的ではないものを定義する。

.pt-price {
  display: flex;
  line-height: 1;

  &__proper {
    @include yen-sign;
  }

  &__sale {
    color: #c92a2a;
  }
}
.pt-confirm-content {
  &__header {
    display: block;
    margin-bottom: 1rem;
    color: #343a40;
    font-size: 1.25rem;
    font-weight: bold;
  }

  .c-alert {
    margin: 0 1rem;
  }
}

Project

ITCSS には無い新規追加のレイヤー

.pj-header {
  background: #fff;

  @include desktop {
    display: flex;
    flex-direction: column;
    height: 100%;
  }
}

.pj-header-main {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  padding: 0 1rem;
  border-bottom: 1px solid #d1d1d1;
}

プレフィックス: .pj-

Pages

ITCSS には無い新規追加のレイヤー

.pg-login-form {
  margin-top: 2rem;
  padding-top: 2.5rem;
}

.pg-login-form-password {
  &__link {
    color: #474747;
    text-decoration: underline;
  }
}

プレフィックス: .pg-

Utilities (Trumps)

ヘルパー・ユーティリティ系のスタイルを定義する。

!importantの利用を許可するレイヤー。

.u-hide {
  display: none !important;
}

プレフィックス: .u-

おわり