Skip to content

CSS ガイドライン

🔰 当ドキュメントは「コーディングガイドライン」の一部です。 基本的なガイドライン・ルールについては先にそれから確認してください。

🎯 CSS ガイドラインの目的

CSSのガイドラインは次の3つを主な目的として策定されています。

  • 確実性
    • 影響範囲が明瞭であること
    • 確実に場所を特定して追加・変更ができること
  • 機能性
    • 命名規則が機能的でその機能が予測し易くあること
    • プロジェクトにヘルプアサインされてもほとんどが判断がつくこと
  • 一貫性
    • 一貫した汎用ルールがあることでプロジェクト独自ルールの氾濫を避けられること
    • プロジェクトをまたいでも混乱することがないこと

作用をきちんと理解する

「何故か解らないけど出来た」は一番やってはいけません。プロパティひとつひとつ、セレクタひとつひとつが、どういった作用をするかきちんと理解してコーディングすることを心掛けてください。

別解を用意すること

ほとんどの場合、表現の方法はひとつではありません。メンテナンス性を優先させた方法、パフォーマンスを優先させた方法など、そのときそのときで最適な方法を探す必要があります。常にいくつかのパターンを考えながらコーディングできるように心掛けてください。また、万が一にブラウザの予期せぬバグに遭遇した際にも別解で解決する必要があります。

💅 コードスタイル

editorconfigStylelintPrettier それぞれに設定されているルールに則って記述します。エディタやコマンド実行時に警告が出た場合は必ず修正してください

各設定は以下のパッケージを利用しています。

リントエラーについて

例外なく必ずリントエラーを修正してください。リンターのルールが現状にそぐわない場合はルールの見直し、つまりConfigファイルの変更を行ってください

Stylelintのdisableコメント

disableコメントを利用することで、ルールを無視することができますが原則行わないでください。

scss
.c-header {
	/* ❌ 実装上やむを得ない場合を除いてdisableコメントは使用しないこと */
	width: 100px !important; // stylelint-disable-line declaration-no-important
}

🍴 プリプロセッサー・コンパイル環境

11tyのTransform機能からViteのCSS変換を利用します。プリプロセッサーはSASSを利用します。

ベンダープレフィックス

Autoprefixerを利用するのでベンダープレフィックス付きのプロパティは必要ありません。

scss
selector {
	transition: opacity 300ms;
	-webkit-transition: opacity 300ms; // ❌ 不要
	-moz-transition: opacity 300ms; // ❌ 不要
}

ただしCSSの標準規格でないものについては必要なケースがあります。Stylelintはその点を考慮して警告を出すので心配はありません。

scss
selector {
	-moz-osx-font-smoothing: grayscale; // ✅ ブラウザ固有のプロパティのためプレフィックは必要
	-webkit-font-smoothing: antialiased; // ✅ ブラウザ固有のプロパティのためプレフィックは必要
}

🔧 自動修正可能

このルールはStylelintによって自動修正されます。

📂 ファイル構成

ファイルは以下の構成で管理します。

# リソース管理
📂 __assets/
├── 📂 htdocs/
│   └── 📂 theme/
│       ├── style.scss
│       └── bge_style.scss
└── 📂 _libs/
        ├── 📂 component/
        │   ├── c-component-name-a.scss
        │   ︙
        │   └── c-component-name-z.scss
        └── 📂 style/
            ├── 📂 theme/
            │   ├── index.scss
            │   ├── color.scss
            │   ├── demension.scss
            │   └── font.scss
            ├── 📂 base/
            │   ├── reset.scss
            │   └── root.scss
            └── 📂 general/
                ├── tag-name-a.scss

                └── tag-name-z.scss

# 公開ファイル
📂 htdocs/css/
├── style.css
└── bge_style.css

__assets/htdocsフォルダの内容はフォルダ構造をそのままにドキュメントルートのhtdocsにCSSファイルとしてコンパイルされ出力されます。

SASSの機能に従って@useする断片ファイルは_で始まるファイル名とします。

__assets/htdocs/css/style.scss

style.cssにコンパイルするSCSSファイルです。@importを利用して各断片ファイルをインポートし、ここにスタイルは定義しないようにしてください。@importはViteのCSS変換によりインライン化されます。パスは@で始めることにより__assets/_libsフォルダをルートとして指定します(ビルド設定によっては変わります)。

scss

CSSレイヤーを利用してインポートするファイルを分類します。

```scss
@import 'destyle.css' layer(reset);

@layer base {
	@import '@/style/base/root.scss';
}

@layer general {
	@import '@/style/general/all.scss';
	@import '@/style/general/body.scss';
	@import '@/style/general/button.scss';
	@import '@/style/general/img.scss';
}

@layer components {
	@import '@/component/c-page-home.scss';
	@import '@/component/c-page-sub.scss';
	@import '@/component/c-header.scss';
	@import '@/component/c-footer.scss';
	@import '@/component/c-nav-global.scss';
	@import '@/component/c-nav-breadcrumb.scss';
	@import '@/component/c-title-page.scss';
	@import '@/component/c-pagination.scss';
	@import '@/component/c-content-main.scss';
}

@layer reset, base, general, components;

__assets/_libs/style/theme/

カラー・数値など、SASS変数やミックスインを定義します。

  • _color.scss: カラーコードのSASS変数の定義
  • _demension.scss: フォントサイズ・ラインハイト、レスポンシブレイアウトのブレイクポイントのSASS変数の定義と、カスタムメディアの定義
  • _font.scss: @font-face・フォントファミリーのSASS変数の定義

カスタムプロパティ(CSS変数は)はbase/root.scssなどのスコープに応じたファイルに定義してください。

他のSCSSファイル上での変数の利用

@use '../theme' as *;を記述することでtheme/_index.scssを参照しtheme/フォルダ内で定義した変数やミックスインを利用することができます。

scss
@use 'sass:math';
@use '../theme' as *;

:root {
	// 配色
	--base-font-color: #{$darkest-color};
	--base-font-size: #{$base-font-size * 1px};
	--base-line-height: #{$base-line-height};

	// コンテンツ幅
	--content-width: #{math.div($breakpoint-sm, $base-font-size) * 1rem};
	--wide-layout-width: #{math.div($breakpoint-md, $base-font-size) * 1rem};
}

プレースホルダーの禁止

カスケード(定義の順番)が期待通りにしにくい問題があるのでプレースホルダー__assets/_libs/style/theme/内に定義するは原則禁止とします。

scss
// ❌ プレースホルダーの利用は原則禁止
%any-style {
	any-property: any-value;
}

// ✅ ミックスインを利用する
@mixin anyMixin {
	any-property: any-value;
}

👮‍♀️ 自動検知

このルールはStylelintによって警告されます。

:::

ミックスインの利用時の注意

タグやクラスに依存するミックスインは作らないようにしてください。影響範囲を予測できなくなるため@mixinのスコープ内に子孫セレクタをつくらないようにしてください。

scss
// ❌ 特定のタグでしか利用できないミックスインは作らない
@mixin anyList {
	display: flex;

	// ❌ ミックインのスコープ内に子孫セレクタをつくらない
	li {
		flex: 0 1 auto;
	}
}

__assets/_libs/style/base/root.scss

ルート要素に対するスタイル定義を定義します。セレクタは:rootだけで、他のセレクタを含めないようにしてください。

カスタムプロパティの定義

グローバルスコープのカスタムプロパティを定義する場合は、:rootセレクタ内で行なってください。

__assets/_libs/style/general/

クラスやIDの付かない素の要素に対してスタイルを定義します。ファイル名はタグ名(要素名)となります。セレクタは当然タイプセレクタのみとなります。

  • 例) <body>body.scss
  • 例) <a>a.scss

コンポーネントをまたいだ各要素、つまりページ全体に影響があることに注意してください。そのため必要最小限の定義に留めることを心掛けてください。コンポーネントで定義できるものはコンポーネント内で定義してください。

全要素対象の場合はall.scssファイルに*(全称セレクタ)で定義します。

scss
// all.scssの例
* {
	&,
	&::before,
	&::after {
		box-sizing: border-box;
	}
}

また、定義をしてよい理由は主に以下に限定します。

  • サイト全体で共通すると断定できる場合。 ただし、ほとんどの場合、その判断は失敗に終わるので推奨しない。
  • CMSなどから入力された要素を、セレクターで判定できない場合(判定できない構造は、HTMLとCSSの設計を見直す方を優先する)

__assets/_libs/style/component/

要素はコンポーネント単位に分割して管理する。(👉HTMLガイドライン > コンポーネント) ファイル名はコンポーネント名とする。 ひとつのファイルの中に複数のコンポーネントを定義してはいけない

  • 例) <header class="c-header-page">c-header-page.scss
  • 例) <nav class="c-nav-global">c-nav-global.scss

🚫 IDの利用の禁止

詳細度で問題を起こすのでIDをセレクタとしてスタイルを定義しないでください。

📐 ルールの定義規則

headerコンポーネントの場合を例に解説します。

1階層目のセレクタはコンポーネントの定義となり、SCSSファイル内に一度だけ登場するようにします。 ファイルパスは __assets/_libs/style/component/c-header.scss となります。

scss
.c-header {
	/* declaration */
}
/* EOF */

次にエレメントは、それにネストする形で&を利用したセレクタをつくります。

scss
.c-header {
	/* declaration */

	&__body {
		/* declaration */
	}

	&__title {
		/* declaration */
	}

	&__site-name {
		/* declaration */
	}
}
/* EOF */

こうすることで、このファイルに記述されたスタイルの影響範囲が、コンポーネント内であることを保証します。

状態変化を表す場合も&を利用してネストして定義します。メディアクエリの定義も、ユーザエージェントの状態変化と捉えて同様にネストして定義します。

状態変化がエレメントを巻き込む場合はコードを後ろにまわして記述します。また、&がコンポーネントのクラスを表さないようなネストの状態になる場合があるので変数化して定義します。

scss
.c-header {
	/* declaration */

	@media (--sm-lte) { /* declaration */ } // メディアクエリ
	&:hover { /* declaration */ } // 疑似クラス
	&--compact-mode { /* declaration */ } // 状態クラス
	&[data-compact-mode="true"] { /* declaration */ } // data属性
	&[aria-hidden="true"] { /* declaration */ } // aria属性

	&__body {
		/* declaration */

		// 子孫要素も同様のルールになる
		@media (--sm-lte) { /* declaration */ } // メディアクエリ
		&:hover { /* declaration */ } // 疑似クラス
		&--compact-mode { /* declaration */ } // 状態クラス
		&[data-compact-mode="true"] { /* declaration */ } // data属性
		&[aria-hidden="true"] { /* declaration */ } // aria属性
	}

	// 影響がエレメントを巻き込む場合は、後ろに記述する
	&[data-fat-mode="true"] {
		/* declaration */

		.c-header__body { // ⚠️ `&` が使用できないスコープでは直接クラスを記述する
			/* declaration */
		}
	}
}
/* EOF */

疑似要素は子孫要素の前に定義し、これも&を利用する。疑似要素セレクタは::で定義してください。

scss
.c-header {
	/* declaration */

	&[data-compact-mode="true"] { /* declaration */ }

	&::before { /* declaration */ }
	&::after { /* declaration */ }

	&__body {
		/* declaration */
	}
}
/* EOF */

&でクラス名を連結する是非について

フルのクラス名が検索にヒットしない理由から忌避されることがありますが、コンポーネントのクラス名とファイル名が一致していることを前提にしているため、&を利用してネストして記述するルールを採用しています。

👮‍♀️ 自動検知

このルールはStylelintによって警告されます。

📌 タイプセレクタの利用

重要

タイプセレクタの利用は可能ですがコンポーネントはコンポーネントを内包できる点に注意してください。

scss
.c-header {
	/* declaration */

	ul {
		/* declaration */
	}
	li {
		/* declaration */
	}
}
html
<header class="c-header">
	<ul>
		<li><a>...</a></li>
		<!-- 👌ここには意図したスタイルが反映される -->
	</ul>
	<div class="c-header-page__c-nav-global">
		<nav class="nav-global">
			<ul>
				<li><a>...</a></li>
				<!-- 💀意図していないheader-pageで定義しているスタイルが影響する -->
			</ul>
		</nav>
	</div>
</header>

回避方法としては次の方法を検討してください。

  • エレメントにクラスきちんと付けて対象を限定する
  • >結合子を利用して影響範囲を限定する(ただしHTMLの構造変更に弱いのでメンテナンス性が落ちることに注意が必要です)

🔢 記述順番

以下のような順番で定義します。

scss
.component-name {
	// 1. 変数定義
	// 2. コンポーネント自体のスタイル
	// 3. 疑似要素
	// 4. 状態変化(※)
	//    4-1. メディアクエリ
	//    4-2. 疑似クラス(:hover :disabled :nth-child :empty など)
	//    4-3. 属性
	//    4-4. 状態クラス (&--[状態])
	// 5. エレメント
	// 6. 結合子セレクタを利用したエレメント(E+E E~E など)
	// 7. 子孫要素に影響のある状態変化
}
/* EOF */

また、プロパティについてはStylelintの設定に基づいて種類順に記述します。

👮‍♀️ 自動検知

このルールはStylelintによって警告されます。

クラス名の例外

JavaScript のライブラリの利用など、クラス命名規則に当てはまらないセレクタにスタイルを当てないといけない場合があります。その場合は、.stylelintrcファイルにてselector-class-patternを変更してください。

scss
.c-hero {
	// ⚠️ 通常はstylelintによる警告がでる
	.any-js-lib-class-name {
		/* declaration */
	}
}

.c-hero {
	// ✅ .stylelintrcの設定変更によって警告がなくなる
	.any-js-lib-class-name {
		/* declaration */
	}
}

💲 カスタムプロパティ・カスタムクエリー・変数・関数・ミックスイン・プレースホルダー

カスタムプロパティ

積極的に採用してください。

カスタムクエリー

PostCSSによりカスタムクエリーは値に展開されます。

css
/* コンパイル前 */
@media (--sm-lte) { /* ... */ }

/* コンパイル後 */
@media (max-width: 576px) { /* ... */ }

デフォルトテンプレート内に次のカスタムクエリーを準備しているので、レスポンシブコンポーネントのブレークポイントの設定に利用してください。

カスタムクエリー内容
--xsxs のみ
--smsm のみ
--mdmd のみ
--lglg のみ
--xlxl のみ
--xs-ltexs 以下 = xs のみ
--sm-ltesm 以下
--md-ltemd 以下
--lg-ltelg 以下
--xl-ltelg 以下
--xs-gtxs 超え
--sm-gtsm 超え
--md-gtmd 超え
--lg-gtlg 超え
--hr高解像度(レティナディスプレイ対応他)

図: ビューポートとブレークポイント

--hrは高解像度判定のクエリーなるので、低解像度と高解像度での出し分けを実装する差に利用することができます。

scss
.c-anonymous {
	background: url("/img/bg-anonymous.png");

	@media (--hr) {
		background: url("/img/bg-anonymous@2x.png");
	}
}

image-setの利用

もしくは解像度による出し分けはimage-setを利用しても構いません。

scss
.c-anonymous {
	background-image: image-set(
		url('/img/bg-anonymous.png') 1x,
		url('/img/bg-anonymous@2x.png') 2x
	);
}

変数

$で始まるSASSの変数が使用できます。色や数値は基本的に変数化してください。

👮‍♀️ 自動検知

このルールはStylelintによって警告されます。

関数

関数の定義は原則禁止です。

使用できるのはCSS標準によって規定されている関数や、SASSが標準機能としてもっている関数、PostCSSによりコンパイル時に変数を計算するresolve関数が使用できます。

👮‍♀️ 自動検知

このルールはStylelintによって警告されます。

ミックスイン

宣言

scss
@mixin mixin-name {
	/* declaration */
}

展開

scss
selector {
	@include mixin-name; // ここで展開
}

プレースホルダー

コンポーネントファイル内であれば%で始まる識別子でプレースホルダー機能を使用できます。プロパティが展開されるのは%を宣言した場所になるため、カスケーディングには十分に気をつけてください。

WARNING

scss
// ❌ コンポーネント外の利用は禁止
%any-style {
	any-property: any-value;
}

// ✅ コンポーネント内で利用する
.c-component {
	%any-style {
		any-property: any-value;
	}

	&__element {
		@extend %any-style;
	}
}

👮‍♀️ 自動検知

このルールはStylelintによって警告されます。

⚖️ 値のルール

数値

scss
selector {
	// 少数点の前の `0` は省略しない
	opacity: 0.5; // ✅
	opacity: .5; // ❌
}

👮‍♀️ 自動検知

このルールはStylelintによって警告されます。

単位

種類によって統一できる単位はひとつに統一してください。

種類各単位統一する単位
長さの絶対的単位px cm mm q in pt pc mozmmpx
長さの相対的単位em ex chem
角度の単位deg rad grad turndeg
時間の単位ms sms

👮‍♀️ 自動検知

このルールはStylelintによって警告されます。

font-size

基本的に相対値を指定し、どういった意図で指定しているのかを明示的に計算式で表現します。

scss
selector {
	// 単位は `em` `rem` `vw` を使用する
	font-size: 1em; // ✅
	font-size: 1.6rem; // ✅

	// ただし `em` `vw` の場合は何を基準にしているのかを明示的に `calc()` を使って指定する
	// ※ `calc()` は算出が可能な場合はPostCSSのプラグインによって実数に変換される
	font-size: 3em; // ❌
	font-size: 1.2em; // ❌
	font-size: 0.5em; // ❌
	font-size: 4vw; // ❌
	font-size: calc(14 / 16 * 1em); // ✅ 親要素が16pxだったときに14pxになる相対値を表わす 「.875em」に変換される
	font-size: calc(36 / 320 * 100vw); // ✅ ビューポートが320pxだったときに35pxになるvw値を表わす 「11.25vw」に変換される
	font-size: calc(36 / $width * 100vw); // ✅ ビューポートが変数$widthだったときに35pxになるvw値を表わす 値は$widthの内容によって変化する
	font-size: calc($font-size / $width * 100vw); // ✅ ビューポートが変数$widthだったときに$font-sizeになるvw値を表わす 値は$widthと$font-sizeの内容によって変化する
}

👮‍♀️ 自動検知

このルールはStylelintによって警告されます。

コンポーネント内のfont-sizeの扱い

メンテナンス性を考慮して、次の設計を推奨します。

  • コンポーネントのルートは親要素からの影響を受けにくくするためにremを指定する
  • 全体のサイズ調整を容易にするためエレメントはemで指定する
scss
.c-header {
	font-size: 1.8rem;

	@media (--sm-lte) {
		font-size: calc(18 / 320 * 100vw);
	}

	&__el1 {
		font-size: calc(12 / 18 * 1em);
	}

	&__el2 {
		font-size: calc(36 / 18 * 1em);
	}
}
/* EOF */

フォントウェイト

400 700 の場合はそれぞれ normal bold キーワードにする

scss
selector {
	font-weight: 400; // ❌
	font-weight: bold; // ✅
	font-weight: 500; // ✅ `400` `700` 以外はキーワードはないので数値のままでよい
}

👮‍♀️ 自動検知

このルールはStylelintによって警告されます。

幅・高さ

width height max-width max-height min-width min-height flex-basis を対象としたルール

scss
selector {
	// ゼロは単位を付けない
	width: 0px; // ❌
	width: 0; // ✅

	// 単位は `px` `%` `em` `rem` `vw` `vh` を使用する
	width: 100px; // ✅
	height: 5em; // ✅
	max-width: 50rem; // ✅
	max-height: 100vw; // ✅
	min-height: 100vh; // ✅
	flex-basis: 100%; // ✅

	// ただし `%` `vw` `vh` の場合は何を基準にしているのかを明示的に `calc()` を使って指定する
	width: 5%; // ❌
	width: 50%; // ❌
	flex-basis: 33.3%; // ❌
	flex-basis: calc(100% / 3); // ✅ 明示的な三等分 「33.33333%」に変換されます
	height: calc(160 / 320 * 100vw); // ✅ ビューポートが320pxだったときに160pxになるvw値を表わす 「50vw」に変換される

	// `100%` `100vw` `100vh` 以外の基準は意図がわかりにくいので避ける
	max-width: calc(160 / 320 * 54.2vw); // ❌
	min-height: calc(2vw / 2); // ❌
	min-height: calc(50vh / 2); // ❌
	flex-basis: calc(105% / 3); // ❌
	flex-basis: calc(120% / 3); // ❌
	flex-basis: calc(200% / 3); // ❌
	flex-basis: calc(1000% / 3); // ❌

	// その他の単位は混乱を避けるため使用しない
	width: 16ex; // ❌
	width: 16pt; // ❌
	width: 16cm; // ❌
}

👮‍♀️ 自動検知

このルールはStylelintによって警告されます。

flex

scss
selector {
	// growとshrinkは0か1を指定する
	// basisは「幅・高さのルール」に準じる
	flex: 0 0 calc(100% / 3); // ✅
	flex: 0 1 calc(100% / 3); // ✅
	flex: 0 2 calc(100% / 3); // ❌
	flex-grow: 0; // ✅
	flex-grow: 1; // ✅
	flex-grow: 2; // ❌
	flex-shrink: 0; // ✅
	flex-shrink: 1; // ✅
	flex-shrink: 2; // ❌
}

👮‍♀️ 自動検知

このルールはStylelintによって警告されます。

Licensed under CC BY-NC-SA 4.0