0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

SCSS×BEM×Gridでレイアウト崩れを解決した話

Posted at

本日もデザイナーさんからいただいたデザインを、システムに反映する作業を進めていた。

もちろん、デザイナーさんが作成した当初から画面仕様が全く同じわけではなく、単純にクラス名置き換えれば解決、というわけにはいかない。

今回、特につまずいたのは、ある一覧画面で、特定の検索時にだけ表示される要素があり、それが存在しないときにレイアウトが崩れてしまう、という問題が発生していた。

最初は「タグの閉じ忘れ」や「別コンポーネントの干渉」を疑ってコードを追っていたが、原因は 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 に表示していたグリッドが、 bc が表示されないときに b として扱われて、幅がおかしくなっていたのだ。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?