mcpField
M
modern-css

modern-css

github.com/paulirishデザイン・UI4.4k549 回インストール4 週間前に更新
リポジトリ

modern-css について

modern-cssは、モダンで堅牢なCSSを書くためのリファレンススキルです。レスポンシブな画面やインタラクティブなコンポーネントを作る開発者向けに、レイアウト、色、タイポグラフィ、アニメーション、ブラウザー対応を扱い、段階的な拡張とユーザー設定への配慮を重視します。

主な機能

  1. 01コンテナクエリとレスポンシブレイアウト
  2. 02モダンな色空間とテーマ設定
  3. 03流動的なタイポグラフィと動的ビューポート単位
  4. 04スクロールアニメーションとビュー遷移
  5. 05ポップオーバー、アンカー配置、フォーム拡張
  6. 06段階的拡張とブラウザー対応の確認

活用シーン

  1. 01コンテナサイズに応じたコンポーネントのスタイル作成
  2. 02モダンな配色でライト・ダークテーマを設計
  3. 03アニメーション、ポップオーバー、フォーム操作を構築
  4. 04新しいCSS機能のブラウザー対応を評価

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/paulirish/dotfiles --skill modern-css

インストール後、Claude Code で/modern-cssを入力して読み込まれたか確認します。

同梱ファイルreferences/argyle-cacadia-2025-deck.md

詳細

モダン CSS

このスキルでは、モダンで堅牢かつ効率的な CSS を記述するためのリファレンスを提供します。


レイアウトとレスポンシブデザイン

コンテナクエリ
.card {
  container: --my-card / inline-size;
}

@container --my-card (width < 40ch) {
  /* Component-based responsive design */
}

@container (20ch < width < 50ch) {
  /* Range syntax */
}

コンテナ単位: cqi、cqb、cqw、cqh - コンテナの寸法に対する相対サイズ

アンカー付きコンテナクエリ: アンカーのフォールバック状態に基づいて、位置指定された要素をスタイル設定します

.tooltip {
  container-type: anchored;
}

@container anchored(top) {
  /* Styles when positioned at top */
}
メディアクエリの範囲構文
@media (width <= 1024px) { }
@media (360px < width < 1024px) { }
グリッドの拡張
  • サブグリッド: 親グリッドのラインを継承して、ネストされたレイアウトを作成します
  • メイソンリー: display: grid-lanes を使って、論理的なタブ順序を持つ Pinterest 風のレイアウトを作成します。(以前は grid-template-rows: masonry として提案されていました。)

色とテーマ設定

カラースキームとライト・ダーク関数
:root {
  color-scheme: light dark;
  --surface-1: light-dark(white, #222);
  --text-1: light-dark(#222, #fff);
}
モダンな色空間
/* OKLCH: uniform brightness, P3+ colors */
.vibrant {
  background: oklch(72% 75% 330);
}

/* Display-P3 for HDR displays */
@media (dynamic-range: high) {
  .neon {
    --neon-red: color(display-p3 1 0 0);
  }
}

/* Better gradients with in oklch */
.gradient {
  background: linear-gradient(
    to right in oklch,
    color(display-p3 1 0 .5),
    color(display-p3 0 1 1)
  );
}
色の操作
/* color-mix() */
.lighten {
  background: color-mix(in oklab, var(--brand), white);
}

/* Relative color syntax */
.lighter {
  background: oklch(from blue calc(l + .25) c h);
  background: oklch(from blue 75% c h); /* Set to specific lightness */
}

.semi-transparent {
  background: oklch(from var(--color) l c h / 50%);
}

.complementary {
  background: hsl(from blue calc(h + 180) s l);
}
アクセントカラー
:root {
  accent-color: hotpink; /* Tints checkboxes, radios, range inputs */
}

タイポグラフィ

テキストの折り返し
h1 {
  text-wrap: balance; /* Balanced multi-line headings */
  max-inline-size: 25ch;
}

p {
  text-wrap: pretty; /* No orphans */
  max-inline-size: 50ch;
}
テキストボックスのトリミング
h1, p, button {
  text-box: trim-both cap alphabetic; /* Optical vertical centering */
}
流動的なタイポグラフィ
.heading {
  font-size: clamp(1rem, 1rem + 0.5vw, 2rem); /* Respects user preferences */
}
動的ビューポート単位
  • dvh / dvw - 動的(モバイルブラウザーの UI を考慮します)
  • svh / svw - 小(ビューポートの最小サイズ)
  • lvh / lvw - 大(ビューポートの最大サイズ)

アニメーションとモーション

スクロール駆動アニメーション
/* Animate on scroll position */
.parallax {
  animation: slide-up linear both;
  animation-timeline: scroll();
}

/* Animate on viewport intersection */
.fade-in {
  animation: fade linear both;
  animation-timeline: view();
  animation-range: cover -75cqi contain 20cqi;
}
ビュートランジション

ステータス: ベースラインで新たに利用可能(同一ドキュメント)。 ドキュメント間のトランジションは、限定的に利用可能です(Chrome/Safari 18.2 以降)。

@view-transition {
  navigation: auto; /* Automatically animate page transitions (MPAs) */
}

nav {
  view-transition-name: --persist-nav; /* Persist specific elements */
  view-transition-class: --site-header; /* Group transitions with classes */
}

/* Style the active transition */
html:active-view-transition {
  overflow: hidden;
}

ネストされたビュートランジショングループ: トランジション中に 3D 変換とクリッピングを維持します。

linear() による高度なイージング
.springy {
  --spring: linear(
    0, 0.14 4%, 0.94 17%, 1.15 24% 30%, 1.02 43%, 0.98 51%, 1 77%, 1
  );
  transition: transform 1s var(--spring);
}
@starting-style
.dialog {
  transition: opacity .5s, scale .5s;

  @starting-style {
    opacity: 0;
    scale: 1.1;
  }
}

カスタムプロパティと高度な機能

@property

型安全でアニメーション可能なカスタムプロパティ:

@property --gradient-angle {
  syntax: "<angle>";
  inherits: false;
  initial-value: 0deg;
}

.animate {
  transition: --gradient-angle 1s ease;

  &:hover {
    --gradient-angle: 360deg;
  }
}
数学関数と calc-size()

新たに利用可能: calc-size() を使うと、固有サイズ(auto、min-content)に対する計算やトランジションが可能になります。

/* Finally: Animate to auto height! */
.accordion-content {
  height: 0;
  overflow: hidden;
  transition: height 0.3s ease;
}

.accordion-item.open .accordion-content {
  height: calc-size(auto);
}

.radial-layout {
  --_angle: calc(var(--sibling-index) * var(--_offset));
  translate:
    calc(cos(var(--_angle)) * var(--_circle-size))
    calc(sin(var(--_angle)) * var(--_circle-size));
}
ツリーカウント関数(近日公開)
.staggered {
  animation-delay: calc(sibling-index() * .1s);
  background-color: hsl(sibling-count() 50% 50%);
}
if() による条件付き CSS(近日公開)
.dynamic {
  color: if(
    style(--theme: dark),
    white,
    black
  );
}

アーキテクチャと整理

カスケードレイヤー
@layer reset, design-system, components, utilities;

@import "open-props/colors" layer(design-system);
@import "components/nav/base.css" layer(components.nav);

@layer components.nav.primary {
  nav {
    position: sticky;
    inset-block-start: 0;
  }
}

利点:

  • サードパーティの CSS を低い詳細度でインポートできます
  • セレクターの重みではなく、関心事ごとにスタイルを整理できます
  • ネストされたレイヤーによって明確な階層を作成できます

インタラクティブコンポーネント

ダイアログ
<dialog id="modal">
  <form method="dialog">
    <button value="cancel">Cancel</button>
    <button value="confirm">Confirm</button>
  </form>
</dialog>

<button commandfor="modal" command="showModal">Open</button>
<button commandfor="modal" command="close">Close</button>

新機能: closedby 属性により、外側をクリックして閉じる動作が可能になります

ポップオーバー
<button popovertarget="menu">Show Menu</button>
<div popover id="menu">...</div>

popover=hint: ほかのポップオーバーを閉じない、一時的なツールチップ

[popover] {
  transition:
    display .5s allow-discrete,
    overlay .5s allow-discrete,
    opacity .5s;

  @starting-style {
    &:popover-open {
      opacity: 0;
    }
  }
}
アンカー位置指定
.tooltip-anchor {
  anchor-name: --tooltip;
}

.tooltip[popover] {
  position-anchor: --tooltip;
  position-area: block-start;
  position-try-fallbacks: flip-block;
  position-try-order: most-height;
}

疑似要素: anchor()、::scroll-button()、::scroll-marker()

排他的アコーディオン
<details name="accordion">...</details>
<details name="accordion">...</details>

カスタマイズ可能なセレクト
select {
  appearance: base-select; /* Full CSS control */
}

/* Style options with rich HTML */
select option::before {
  content: ""; /* Can include images, icons */
}
検索要素
<search>
  <form>
    <input type="search" name="q">
    <button type="submit">Search</button>
  </form>
</search>

フォームの拡張

フィールドのサイズ設定
textarea, select, input {
  field-sizing: content; /* Auto-grow to content */
}

textarea {
  min-block-size: 3lh; /* Line-height units */
  max-block-size: 80dvh;
}
改善された検証用疑似クラス
/* Wait for user interaction before showing errors */
:user-invalid {
  outline-color: red;
}

:user-valid {
  outline-color: green;
}

label:has(+ input:user-invalid) {
  text-decoration: underline wavy red;
}
セレクト内の HR
<select>
  <option>Option 1</option>
  <hr>
  <option>Option 2</option>
</select>

視覚効果

スクロールバーのスタイル設定
.custom-scrollbar {
  scrollbar-color: hotpink transparent;
  scrollbar-width: thin;
}
形状関数
.complex-clip {
  clip-path: shape(
    from 0% 0%,
    curve by 50% 25% via 25% 50%,
    line to 100% 100%
  );
}
コーナー形状
.fancy-corners {
  corner-shape: squircle;
  corner-shape: notch;
  corner-shape: scoop;
  corner-shape: superellipse(0.7);
}

プログレッシブエンハンスメントのパターン

機能検出
@supports (animation-timeline: view()) {
  .fade-in {
    animation: fade linear both;
    animation-timeline: view();
  }
}

@supports (container-type: inline-size) {
  .responsive-card {
    container-type: inline-size;
  }
}
ユーザー設定を尊重する
@media (prefers-reduced-motion: no-preference) {
  .animated {
    animation: slide 1s ease;
  }
}

@media (prefers-color-scheme: dark) {
  :root {
    --surface: #222;
  }
}

@media (prefers-contrast: more) {
  .text {
    font-weight: 600;
  }
}

ブラウザー対応状況の確認: ベースライン

ベースラインとは? ブラウザー間の機能対応状況を把握するための統一的な方法です。機能は次のように分類されます。

  • 幅広く利用可能: すべての主要ブラウザーで、過去 2.5 年以内にサポートされています
  • 新たに利用可能: すべての主要ブラウザーで利用できます
  • 限定的に利用可能: まだすべてのブラウザーで利用できるわけではありません
ベースラインのステータスを確認する方法
  1. 最適な方法: https://web-platform-dx.github.io/web-features-explorer/groups/ を取得して機能を探し、その詳細ページを取得します。
  2. Can I Use: caniuse.com では、各機能の上部にベースラインバッジが表示されます
  3. MDN: ブラウザー互換性テーブルでベースラインバッジを確認します
  4. web.dev: 機能に関する記事にベースラインのステータスが記載されています

覚えておきましょう: 常にベースラインのステータスを確認し、最先端の機能には @supports を使い、メディアクエリでユーザー設定を尊重してください。モダン CSS とは、プログレッシブエンハンスメントを実現し、誰もが使える堅牢なインターフェースを構築することです。


実例: モダンなコンポーネント

ここでは、多くのモダン CSS 機能を使ったカードコンポーネントを紹介します。

/* Cascade layer for organization */
@layer components.card {

  /* Custom properties with @property */
  @property --card-hue {
    syntax: "<number>";
    inherits: false;
    initial-value: 200;
  }

  .card {
    /* Container for responsive design */
    container: card / inline-size;

    /* Logical properties */
    inline-size: 100%;
    padding-inline: var(--space-md);
    padding-block: var(--space-lg);

    /* Modern color system */
    background: light-dark(
      oklch(98% 0.02 var(--card-hue)),
      oklch(20% 0.02 var(--card-hue))
    );

    /* Border with relative color */
    border: 1px solid oklch(from var(--surface) calc(l * 0.9) c h);

    /* Smooth corners */
    border-radius: var(--radius-md);

    /* View transition */
    view-transition-name: --card;

    /* Scroll-driven animation */
    animation: fade-in linear both;
    animation-timeline: view();
    animation-range: entry 0% cover 30%;

    /* Anchor for tooltips */
    anchor-name: --card-anchor;

    /* Transition custom property */
    transition: --card-hue 0.5s var(--ease-spring-3);

    &:hover {
      --card-hue: 280;
    }

    /* Responsive typography in container */
    @container card (width > 30ch) {
      .card__title {
        font-size: clamp(1.5rem, 3cqi, 2.5rem);
        text-wrap: balance;
      }
    }

    @container card (width < 30ch) {
      .card__image {
        aspect-ratio: 16 / 9;
        object-fit: cover;
      }
    }
  }

  .card__title {
    /* Text box trim for optical alignment */
    text-box: trim-both cap alphabetic;
    text-wrap: balance;

    /* Logical margin */
    margin-block-end: var(--space-sm);
  }

  .card__body {
    text-wrap: pretty;
    max-inline-size: 65ch;
  }

  .card__cta {
    /* Inherit font */
    font: inherit;

    /* Accent color */
    accent-color: var(--brand);

    /* Field sizing */
    field-sizing: content;

    /* Logical properties */
    padding-inline: var(--space-md);
    padding-block: var(--space-sm);

    /* Modern color with relative syntax */
    background: oklch(from var(--brand) l c h);
    color: oklch(from var(--brand) 95% 0.05 h);

    &:hover {
      background: oklch(from var(--brand) calc(l * 1.1) c h);
    }

    &:user-invalid {
      outline: 2px solid light-dark(red, #ff6b6b);
    }
  }

  /* Popover tooltip anchored to card */
  .card__tooltip[popover] {
    position-anchor: --card-anchor;
    position-area: block-start;
    position-try-fallbacks: flip-block;

    /* Entry animation */
    @starting-style {
      opacity: 0;
      scale: 0.9;
    }

    transition:
      opacity 0.2s,
      scale 0.2s,
      display 0.2s allow-discrete,
      overlay 0.2s allow-discrete;
  }

  /* Scroll state container queries */
  @supports (container-type: scroll-state) {
    .card__sticky-header {
      container-type: scroll-state;
      position: sticky;
      inset-block-start: 0;

      @container scroll-state(stuck: top) {
        box-shadow: 0 2px 8px oklch(0% 0 0 / 0.1);
      }
    }
  }

  /* Respect user preferences */
  @media (prefers-reduced-motion: reduce) {
    .card {
      animation: none;
      transition: none;
    }
  }

  @media (prefers-contrast: more) {
    .card {
      border-width: 2px;
    }
  }
}

/* Keyframes for scroll animation */
@keyframes fade-in {
  from {
    opacity: 0;
    scale: 0.95;
  }
  to {
    opacity: 1;
    scale: 1;
  }
}
サンプル用の HTML
<article class="card">
  <img
    class="card__image"
    src="image.jpg"
    alt="Description"
    loading="lazy"
  >

  <h2 class="card__title">Card Title</h2>

  <p class="card__body">
    Card description with pretty text wrapping that avoids orphans.
  </p>

  <button
    class="card__cta"
    popovertarget="card-tooltip"
  >
    Learn More
  </button>

  <div
    class="card__tooltip"
    popover="hint"
    id="card-tooltip"
  >
    Additional information appears here
  </div>
</article>

正規リソース

使用ガイドライン

  1. 安定性を優先する:

    • 本番コードには Newly Available または Widely Available の機能を推奨します。
    • Limited Availability の機能は、プログレッシブエンハンスメント、グレースフルデグラデーション、または @supports と併用してください。あるいは、どのように扱いたいかをユーザーに確認してください。
  2. Web プラットフォームを活用する:

    • レイアウト、アニメーション、インタラクションには、JavaScript ライブラリよりも常に標準の CSS ソリューションを優先してください (例: Masonry.js の代わりに CSS Masonry、カスタムツールチップスクリプトの代わりに Popover API)。
  3. コードスタイル:

    • 新しいパレットにはモダンな色空間 (oklch) を使用してください。

コメント