本日もデザイナーさんからいただいたデザインを、システムに反映する作業を進めていた。
もちろん、デザイナーさんが作成した当初から画面仕様が全く同じわけではなく、単純にクラス名置き換えれば解決、というわけにはいかない。
今回、特につまずいたのは、ある一覧画面で、特定の検索時にだけ表示される要素があり、それが存在しないときにレイアウトが崩れてしまう、という問題が発生していた。
最初は「タグの閉じ忘れ」や「別コンポーネントの干渉」を疑ってコードを追っていたが、原因は CSSにあった。
デザイナーさんが用意してくれたCSSは「要素が常に存在する」前提で作られていたため、特定のケースで非表示になると、幅の指定が合わずに崩れが生じていたのだ。
実際には width の違いだけだが…これがハマる原因だった
今回はそのときのコードを整理してまとめておく。
コード全体
.demo-layout {
$self: &;
padding: 16px 24px 40px;
min-width: 1276px;
&__header {
font-size: 22px;
font-weight: 500;
margin-bottom: 16px;
}
&.--top { //「ピリオド」は「かつ」。つまり<div class="demo-layout --top"></div>
#{$self}__grid {
grid-template-areas: "a a" "b c" "d d";
grid-template-columns: repeat(2, 1fr);
}
.demo-card {
&:first-child {
grid-area: a;
}
&:nth-child(2) { //nth = n番目
grid-area: b;
border-radius: 8px;
}
&:nth-child(3) {
grid-area: c;
border-radius: 8px;
}
&:nth-child(4) {
grid-area: d;
}
}
// 2番目の .demo-card が最後の子の場合は全幅にする
.demo-card:nth-child(2):last-child {
grid-area: d;
}
}
&__grid {
display: grid;
gap: 16px;
}
}
⸻
ポイント
1. BEM記法とネスト
-
.demo-layout
が「ブロック」 -
&__header
や&__grid
が「エレメント」 -
&.--top
が「モディファイア」(ただし正統BEMなら&--top
)
→ SCSSのネストを使うと、BEM記法を自然に整理できる。
BEMとは
BEM = Block(ブロック) / Element(エレメント) / Modifier(モディファイア)。
ロシアのYandex社が提唱したCSSの命名規則。
目的:大規模開発でも「クラス名がわかりやすく」「競合しにくく」「再利用しやすい」CSSを書く
構成要素
Block
UIの独立した部品そのもの
<div class="card">...</div>
→ .card がブロック
Element
ブロックに属する子要素
<div class="card">
<h2 class="card__title">タイトル</h2>
<p class="card__text">説明文</p>
</div>
→ card__title, card__text がエレメント
書き方:ブロック名__エレメント名
modifier
バリエーションや状態を表す
<button class="btn btn--primary">OK</button>
<button class="btn btn--secondary">Cancel</button>
→ btn--primary, btn--secondary がモディファイア
書き方:ブロック名--修飾子
2. $self: &; の活用
$self: &;
#{$self}__box-group { ... }
- $self に親セレクタを代入しておくテクニック。
- ネストの深い場所でも 「.demo-layout__grid」 を正しく参照できる。
- 大規模なBEM構造では特に便利らしい
3. Gridレイアウト
- grid-template-areas を使って .demo-card の配置を管理。
- 子要素ごとに grid-area を割り当てることで、HTMLの並び順に依存せず自由に配置できる。
4. 擬似クラスで条件分岐
.demo-card:nth-child(2):last-child {
grid-area: d;
}
- 「2番目の .demo-card が最後の子」= 特定条件のときに全幅にする
- UI要件に応じてCSSだけでレイアウトを切り替えられるのは強み。
⸻
出力されるCSSイメージ
.demo-layout {
padding: 16px 24px 40px;
min-width: 1276px;
}
.demo-layout__header {
font-size: 22px;
font-weight: 500;
margin-bottom: 16px;
}
.demo-layout.--top .demo-layout__grid {
grid-template-areas: "a a" "b c" "d d";
grid-template-columns: repeat(2, 1fr);
}
⸻
今回は4の疑似クラスで条件分岐を行った。
幅いっぱいで d に表示していたグリッドが、 b と c が表示されないときに b として扱われて、幅がおかしくなっていたのだ。