NULLなCSS変数によるCSSグリッドレイアウト

JavaScript や PHP といったプログラミング言語には値がないことを意味する NULL というものがあります。この NULL をCSS変数 (カスタムプロパティ) に設定できることを知っていますか?

今回は、NULL なCSS変数を活用したグリッドレイアウトを紹介します。

NULLなCSS変数とは

未定義のCSS変数を代替値もなくプロパティに設定すると、そのプロパティは無効になります。

/* --background-repeat が未定義なら、background プロパティは無効になる。 */
.example-1 {
  background: linear-gradient(red 0% 100%) var(--background-repeat) center / 1rem 1rem;
  /* ≈ background: linear-gradient(red 0% 100%) undefined center / 1rem 1rem; */
}
/* --background-repeat が未定義なら、代替値の no-repeat により、要素中央に赤い正方形が表示される。 */
.example-2 {
  background: linear-gradient(red 0% 100%) var(--background-repeat, no-repeat) center / 1rem 1rem;
  /* = background: linear-gradient(red 0% 100%) no-repeat center / 1rem 1rem; */
}

しかし、var(--x,) のように NULL な代替値を設定したり、--x:; のように NULL なCSS変数を設定すると、プロパティを無効にすることなく適用することができます。

/* --background-repeat が未定義なら、NULL な代替値により、初期値の repeat が適用され、背景が赤く塗りつぶされる。 */
.example-1 {
  background: linear-gradient(red 0% 100%) var(--background-repeat,) center / 1rem 1rem;
  /* = background: linear-gradient(red 0% 100%) center / 1rem 1rem; */
}
/* NULL な --background-repeat により、初期値の repeat が適用され、背景が赤く塗りつぶされる。 */
.example-2 {
  --background-repeat:;
  background: linear-gradient(red 0% 100%) var(--background-repeat) center / 1rem 1rem;
  /* = background: linear-gradient(red 0% 100%) center / 1rem 1rem; */
}

CSSグリッドレイアウトの使いづらさ

CSSグリッドは、配置する要素が決まっている場合は特に不便さを感じません。

/* ヘッダー, メインコンテンツ, ナビゲーション, サイドコンテンツ, フッターの5要素をレイアウトする。 */
.example {
  & {
    display: grid;
      grid:
          "header" auto
          "main" minmax(auto, 1fr)
          "nav" auto
          "side" auto
          "footer" auto
          / 1fr;
      gap: 32px;
  }
  & > .header {
    grid-area: header;
  }
  & > .main {
    grid-area: main;
  }
  & > .nav {
    grid-area: nav;
  }
  & > .side {
    grid-area: side;
  }
  & > .footer {
    grid-area: footer;
  }
  @media (width > 720px) {
    & {
      grid:
          "header header" auto
          "main nav" auto
          "main side" minmax(auto, 1fr)
          "footer footer" auto
          / 2fr 1fr;
    }
  }
}

しかし、配置する要素が一定ではない場合、途端に使いづらくなります。上記のCSSコードでは、ナビゲーションやサイドコンテンツが無い場合を想定していません。

それらを想定するのであれば、ナビゲーションがある場合、サイドコンテンツがある場合、両方がある場合、両方がない場合の4パターンのCSSコードが必要です。

.example {
  & {
    display: grid;
      grid:
          "header" auto
          "main" minmax(auto, 1fr)
          "footer" auto
          / 1fr;
      gap: 32px;
  }
  &:where(:has(> .nav)) {
    grid:
        "header" auto
        "main" minmax(auto, 1fr)
        "nav" auto
        "footer" auto
        / 1fr;
  }
  &:where(:has(> .side)) {
    grid:
        "header" auto
        "main" minmax(auto, 1fr)
        "side" auto
        "footer" auto
        / 1fr;
  }
  &:where(:has(> .nav):has(> .side)) {
    grid:
        "header" auto
        "main" minmax(auto, 1fr)
        "nav" auto
        "side" auto
        "footer" auto
        / 1fr;
  }
  & > .header {
    grid-area: header;
  }
  & > .main {
    grid-area: main;
  }
  & > .nav {
    grid-area: nav;
  }
  & > .side {
    grid-area: side;
  }
  & > .footer {
    grid-area: footer;
  }
  @media (width > 720px) {
    &:where(:has(> .nav)) {
      grid:
          "header header" auto
          "main nav" minmax(auto, 1fr)
          "footer footer" auto
          / 2fr 1fr;
    }
    &:where(:has(> .side)) {
      grid:
          "header header" auto
          "main side" minmax(auto, 1fr)
          "footer footer" auto
          / 2fr 1fr;
    }
    &:where(:has(> .nav):has(> .side)) {
      grid:
          "header header" auto
          "main nav" auto
          "main side" minmax(auto, 1fr)
          "footer footer" auto
          / 2fr 1fr;
    }
  }
}

ヘッダーとフッターは、ナビゲーションとサイドコンテンツの有無に関わらず、ほぼ変化がなく、同じ記述の繰り返しがあり冗長です。また、要素を追加する場合の拡張性まで考慮するとCSSコードは更に多くなり、メンテナンス性も低下します。

NULLなCSS変数を使用したCSSグリッドレイアウト

CSSグリッドレイアウトの使いづらさを解消するために NULL なCSS変数を活用すると次のようになります。

.example {
  & {
    --row-1: "header header" auto;
    --row-2: "main main" minmax(auto, 1fr);
    --row-3:;
    --row-4:;
    --row-5: "footer footer" auto;
    --column-1: 2fr;
    --column-2: 1fr;
    display: grid;
      grid: var(--row-1) var(--row-2) var(--row-3) var(--row-4) var(--row-5) / var(--column-1) var(--column-2); 
      gap: 32px;
  }
  &:where(:has(> .nav)) {
    --row-3: "nav nav" auto;
  }
  &:where(:has(> .side)) {
    --row-4: "side side" auto;
  }
  & > .header {
    grid-area: header;
  }
  & > .main {
    grid-area: main;
  }
  & > .nav {
    grid-area: nav;
  }
  & > .side {
    grid-area: side;
  }
  & > .footer {
    grid-area: footer;
  }
  @media (width > 720px) {
    &:where(:has(> .nav)) {
      --row-2: "main nav" minmax(auto, 1fr);
      --row-3:;
      --row-4:;
    }
    &:where(:has(> .side)) {
      --row-2: "main side" minmax(auto, 1fr);
      --row-3:;
      --row-4:;
    }
    &:where(:has(> .nav):has(> .side)) {
      --row-2: "main nav" auto;
      --row-3: "main side" minmax(auto, 1fr);
      --row-4:;
    }
  }
}

想定される行と列の数だけ --row-N:;--column-N:; を用意し、必要に応じて埋めるというやり方です。この方法であれば、行と列を増やし要素を追加するといった拡張性も得られます。

CodePen

See the Pen CSS grid layout and NULL variables by nov (@numerofive) on CodePen.

CSS変数の NULL は最近知りました。CSSグリッドレイアウトだけでなく、省略可能な値がある他のプロパティにも応用できそうです。

関連記事