1 月末にリニューアルした本サイトについて、今回は CSS を取り上げます。

本サイトでの CSS 設計や、実用的だと感じた CSS 指定、そして今後使用していきたい CSS について書いていきます。

「CSS」の文字をブロックで表現したイラスト

これまでのプロジェクトであれば、Sass をベースとして、出力した CSS に対して Autoprefixer をかけていたのですが、今回はこれらは使用せずに純粋に CSS だけで実装しました。

理由としては、フレームワークとして使用している Astro でコンポーネント化できているのと、ブラウザのサポート状況(相互運用性の向上)から -webkit- のようなプレフィックスを付ける機会も減ってきているためです。

今のところ Sass を使用しないことで不便に感じるのは、メディアクエリには CSS 変数を指定できないので、毎回値を記入しなければならないことぐらいです。
(Sass を使用する場合には @mixin で一元管理します)

:root {
  --breakpoint: 768px;
}

/* ❌ メディアクエリには CSS 変数を指定できない */
@media (min-width: var(--breakpoint)) {
  /* ... */
}

将来的に @custom-media が使用できるようになれば、メディアクエリに CSS 変数を指定できない問題は解消します。

@custom-media --breakpoint (width >= 768px);

@media (--breakpoint) {
  /* ... */
}

現状は、PostCSS のプラグインによって同様の機能を試すことができます。

Astro 側ではサイト全体に適用したい CSS を src/styles 以下に格納し、ベースレイアウトに import で読み込み、それ以外はコンポーネントごとに個別に指定しています。

サイト全体に適用する CSS の構成
src/
└── styles/
    ├── fonts.css      // `@font-face` (独自フォント指定)
    ├── variables.css  // CSS 変数(カスタムプロパティ)
    ├── reset.css      // リセット
    └── global.css     // それ以外のグローバルな指定
Astro のベースレイアウトファイル
---
import '@styles/fonts.css';
import '@styles/variables.css';
import '@styles/reset.css';
import '@styles/global.css';
---

Astro 編」でも書きましたが、コンポーネントで記述した CSS のスコープは擬似的に閉じられるので、BEM のような命名規則を用いた、CSS セレクタの管理からは解放されます。

ただ、ブログ記事は Markdown 記法を使用しているため、出力されるコードは <h2><p> など、class 属性の付かない HTML 要素です。

Astro でこれらの要素にスタイルを適用するには、<style is:global> でスコープを無効にするか、部分的に :global() セレクタを使用することになりますが、このとき、他の要素に影響しないように注意しなければなりません。

CSS スコープを無効にする例
<!-- `<style>` 全体でスコープを無効にする例 -->
<style is:global>
.markdown h2 {
  margin-bottom: 24px;
}
</style>

<!-- 部分的にスコープを無効にする例 -->
<style>
.markdown :global(h2) {
  margin-bottom: 24px;
}
</style>

もしくは、MDX を使用すれば、カスタムコンポーネントを HTML 要素に割り当てることができるので、コンポーネントでのスコープを徹底したい場合には、この方法を採用するとよいでしょう。

リニューアル作業をとおして実用的だと感じた、以下の 5 つの CSS 指定について取り上げます。

  • fit-content
  • inset
  • revert
  • currentColor
  • scroll-behavior

なお、CSS 変数(カスタムプロパティ)や CSS Grid Layout についても積極的に使用しており、十分にその恩恵を受けていますが、この記事では扱いきれないので割愛します。

width: fit-content と指定することで、コンテンツ幅を横幅としてレイアウトしてくれます。

例えば display: block を指定した要素は、通常は幅いっぱいまで広がりますが、width: fit-content の指定ではコンテンツ幅にとどまるので、背景スタイルやリンク範囲といった領域の制御が容易になります。

また、margin: auto を使用した左右のセンタリングでは、従来は 600px のように値を明示する必要がありましたが、fit-content を使用することで、コンテンツ幅のままセンタリングすることができます。

fit-content の使用例
.elem {
  margin-right: auto;
  margin-left: auto;
  width: fit-content;
  display: block;
  background-color: lightblue;
}

insettop right bottom left を一括指定できます。

特に、擬似要素を position: absolute で配置する際によく使います。

inset の使用例
.elem::after {
  content: '';
  position: absolute;
  inset: 0;
  /* `top: 0; right: 0; bottom: 0; left: 0;` を指定したのと同じ効果 */
}

revert はプロパティの値を、親から継承された値や、User-Agent のスタイルシートまでロールバックするキーワードです。

メディアクエリを使ってモバイル用とデスクトップ用の指定を切り替えるときに、前の指定を取り消したいときがありますが、display: blockmargin: 0 のような明示的に値を指定するのではなく、revert を使用することで、自然なカスケーティングを保つことができます。

例えば以下は、ビューポート幅が狭いときにのみ表示するユーティリティクラスの例ですが、display: none で非表示にしておいて、ビューポート幅 767px 以下の場合に、display: revert で本来持っていた値にロールバックさせています。

revert の使用例
.is-narrow {
  display: none;
}

@media (max-width: 767px) {
  .is-narrow {
    display: revert;
  }
}

このとき、通常は div 要素であれば display: block になり、span 要素であれば display: inline になります。

以前より広くサポートされていますが、currentColor キーワードを使用することで、color プロパティで指定した値を適用できます。

特に SVG の単色のアイコンのカラーを指定するときや、ホバーやダークモードでそのカラーを変更するときに重宝します。

currentColor の使用例
---
// Astro コンポーネントの例
---

<button type="button" class="btn">
  ボタン
  <svg width="27" height="27" viewbox="0 0 27 27" class="btn-icon">
    <path d="M20.035 13.5 13.5 19.802l-1.307-1.26 4.37-4.214H6.965v-1.782h9.466l-4.238-4.087 1.307-1.26 6.535 6.301Z"/>
  </svg>
</button>

<style>
.btn {
  /* 親要素にカラーを指定 */
  color: #cfdddd;
}
.btn-icon {
  /* このとき SVG の `fill` が `#cfdddd` になる */
  fill: currentColor;
}
.btn:hover {
  background-color: #cfdddd;
  /* ホバーで変更したカラーは `currentColor` にも反映される */
  color: #042020;
}
</style>

scroll-behavior: smooth を指定することで、簡単にスムーススクロールが実現できます。

あわせて、スクロール先の要素に scroll-margin-top を指定することで、アンカーリンクで遷移したときのスクロール位置の余白を調整できます。

scroll-behavior と scroll-margin-top の使用例
html {
  scroll-behavior: smooth;
}
:where(h2, h3, h4) {
  scroll-margin-top: 24px;
}

スクロール時の細かい速度調整はできませんが、CSS のみでアクセシブルなスムーススクロールが実装できるのは喜ばしい限りです。

今後使用していきたい CSS

見出し「今後使用していきたい CSS」

ここ最近の CSS の進化は目覚ましく、フォローするだけでも大変ですが、その反面、新しい機能や表現を使えるのも楽しみでもあります。

今後、本サイトを実験場として以下で紹介されている CSS も試していきたいです。

JS との併用になりますが、画面遷移のアニメーションを制御する View Transitions API も気になるところです。
まだ Google Chrome の試験運用版の段階なので、実用化は先になりそうですが Chrome 111 でサポートされました)