5
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Frontend CSS – パート14】Style Query・Container Naming・実践パターンまで徹底解説

5
Posted at

image.png

ご注意
この記事は AI のサポートを受けていますが


1. おさらい:なぜ Container Query が必要か

第13回で話しましたが、media query が知っているのは viewport だけ — カードが sidebar 280px の中にあるのか、4列 grid の中にあるのかは分かりません。結果としてよくあるのは、バリアントを増やす、props でレイアウトを調整する、CSS が膨らむのにコンポーネントが再利用できない、というパターンです。

Container Query はまさにそこを解決します。コンポーネントが 親の幅はいくつか — そして本記事からは 親のテーマは何か — を自分で聞く。画面サイズを聞くのではなく。

第13回をまだ読んでいない方は、レンダリングパイプラインと ProfileCard の基本を先にどうぞ。本記事は「シーズン2」であって、総集編ではありません。


2. Container Query 基本 — 覚えておく構文

Container Query親 container のサイズまたはスタイル に基づいてスタイルを適用します。viewport ではありません。3ステップだけ — 注文するように覚えてください:container-type を宣言 → @container で条件を書く → 条件が真なら子のスタイルが適用される。

2.1. container-type — 重要な値

意味 用途
inline-size (inline 軸)で query 最も一般的 — 横方向の responsive
size 幅と高さの両方で query 両軸が必要なとき
normal size query 用の container ではない デフォルト — size query には使わない
/* container の宣言 */
.card-container {
  container-type: inline-size; /* 幅のみ query */
  /* または */
  container-type: size; /* 幅と高さの両方 */
}

2.2. 基本構文

/* 名前なし — 最も近い container を query */
@container (max-width: 400px) {
  .child {
    /* style */
  }
}

/* 名前あり — 特定の container を query */
@container sidebar (max-width: 400px) {
  .child {
    /* style */
  }
}

/* Style Query — カスタムプロパティで query */
@container style(--theme: dark) {
  .child {
    /* style */
  }
}

3. Container Naming — container に名前を付ける

container が1つなら簡単 — 最も近い container を query すれば OK。でも実際のページは main の中に sidebar、sidebar の中に grid、その中に card... そんなとき 名前を付ける と、query したい container を正確に指定でき、CSS が「間違った親」を掴むのを防げます。

3.1. container-name — 名前の付け方

2つの書き方 — 手慣れの方を選んでください:

/* 方法1: container-name を個別に */
.card-container {
  container-name: card;
  container-type: inline-size;
}

/* 方法2: container のショートハンド */
.card-container {
  container: card / inline-size; /* 名前 / タイプ */
}

3.2. @container で名前を使う

名前があれば query は正確。名前を省略するとブラウザは 最も近い container を使います — 1つだけなら便利、多段ネストだとリスクがあります。

/* container 名 "card" が 500px より広いときだけ適用 */
@container card (min-width: 500px) {
  .card-title {
    font-size: 1.5rem;
  }
}

/* 名前を指定しない → 最も近い container を query */
@container (min-width: 500px) {
  .card-title {
    font-size: 1.5rem;
  }
}

3.3. 複数の container に同じ名前

同じ名前 を複数の container に付けられます — sidebar にも main にもある card すべてに同じルールを適用したいときに便利。1つの @container、複数の場所が反応。便利ですが、必要ないときは使いすぎないでください。

/* 両方とも名前 "card" */
.sidebar-card {
  container: card / inline-size;
}
.main-card {
  container: card / inline-size;
}

/* この query は両方の container に適用される */
@container card (max-width: 300px) {
  .card-image {
    display: none;
  }
}

3.4. Name-only Container Query

CSS Containment Module Level 3 によると、名前だけ で query できます — サイズ条件は不要。「card という名前の container で囲まれているか?」ならスタイルを適用、というイメージです。

/* container 名のみで query */
@container card {
  .card-content {
    /* 名前 "card" の container で囲まれていれば適用 */
    border-left: 4px solid blue;
  }
}

注意: Name-only query は 2026年5月から Baseline Newly available(Chrome 148+、Firefox 151+、Safari 26.5+)。production では必ず動作確認を。


4. Style Query — サイズだけでなくスタイルで query する

Size query は「親は何 px 幅か?」に答えます。Style query はさらに「親は今どんな状態か?」 — dark mode、compact mode、design token... 本記事で一番好きなパートです。React context なしで、コンポーネントがコンテキストの「雰囲気」を読めるようになるから。

4.1. Style Query とは

Style Query は container の スタイル値(多くはカスタムプロパティ)を query できます。サイズだけではありません。

基本アイデア:container を定義し、その computed style に基づいて子孫に条件付きスタイルを適用する。

4.2. ポイント:すべての要素が Style Container

Size query は container-type の宣言が必要。Style query は... 何もいらない — すべての要素がデフォルトで style container。ブラウザが面倒を見てくれます。

すべての要素は style container — style を query するのに container-namecontainer-type は不要。

なぜ? Style query は layout loop を起こしません — 子のスタイルが親に逆流しない。size query とは違い、containment が必須です。

4.3. Style Query の構文

CSS Containment Module Level 3 の仕様では すべての computed style を query できます — ただし現行ブラウザが「本気で対応している」のはカスタムプロパティだけです(4.4 参照)。

/* カスタムプロパティの query — 対応済み */
@container style(--theme: dark) {
  .card {
    background: #1a1a2e;
    color: #eee;
  }
}

/* 論理演算子との組み合わせ */
@container style(--theme: dark) and (min-width: 400px) {
  .card {
    /* dark かつ幅 400px 超のとき */
  }
}
仕様上の例 — production にはコピーしないで(広く未対応)
/* font-style の query — 仕様にはあるが、広く未対応 */
@container style(font-style: italic) {
  em,
  i,
  q {
    font-style: normal;
  }
}

4.4. 現実:Style Query が対応しているのは Custom Properties のみ

ブラウザサポート: カスタムプロパティ向け style query は 2026年5月から Baseline Newly available。deploy 前に Can I UseMDN で確認を — 「Baseline」だからと安心して寝ないでください。

仕様はあらゆる property-value ペアの query を夢見ています。現実のブラウザが対応しているのは Custom Properties — つまり CSS 変数だけ。それ以外は... 上の <details> を眺める程度に。

Chrome for Developers によると、仕様では font-weight: 800 のような query も可能ですが、実装は現時点で カスタムプロパティのみ です。

/* ✅ 有効 — カスタムプロパティの query(対応済み) */
@container style(--size: large) {
  .text {
    font-size: 2rem;
  }
}

/* ❌ 無効(現時点) — プロパティを直接 query */
@container style(font-size: 20px) {
  .text {
    /* ほとんどのブラウザでは動かない */
  }
}

朗報:カスタムプロパティ向け style query は 2026年5月から Baseline Newly available です。

4.5. 実例:コンテキストに応じた dark mode

各カードに className={isDark ? 'dark' : ''} を付ける代わりに、親 container に --theme をセット — 中のカードが自動でわかります。

/* container でテーマを宣言 */
.app {
  --theme: dark;
}

/* テーマに基づく style query */
@container style(--theme: dark) {
  .card {
    background: #1e1e2e;
    border-color: #444;
  }
  .card-title {
    color: #fff;
  }
}

@container style(--theme: light) {
  .card {
    background: #ffffff;
    border-color: #ddd;
  }
  .card-title {
    color: #222;
  }
}

5. ブラウザ:レンダリングパイプラインにおける Container Query

第13回でレンダリングパイプラインは触れました。本記事に直結する部分だけおさらいします:

覚えておくこと: @containercontainer の layout 後 に評価されます — ブラウザは即座にスタイルを適用せず、再計算が必要な子孫にマークを付けます。だから resize 時にコンポーネントが一瞬「跳ねる」ことがある — バグではなく、ブラウザが正しく動いている(少しだけ遅い)証拠です。すべての <div>container-type をシールのように貼る理由でもありません。


6. 実践:React + TypeScript で DashboardCard

第13回の ProfileCard は size query の入門でした。ここでは DashboardCard にアップグレード — named container、意味のある breakpoint、dark mode 用 style query。1コンポーネント、3コンテキスト、variant props なし。

6.1. 要件

シンプルなダッシュボードカード — でもどこに置いても生き残れること:

  • 表示:title、value、icon、trend indicator
  • container > 500px → 横レイアウト(icon 左、テキスト右)
  • container 300–500px → 縦レイアウト、情報はすべて表示
  • container < 300px → trend を非表示、フォント縮小(狭い sidebar に成長グラフは不要)
  • 親に --theme: dark → 自動 dark mode

6.2. コード

DashboardCard.tsx
import React from 'react';
import './DashboardCard.css';

import { TrendingUp, TrendingDown } from 'lucide-react';

interface DashboardCardProps {
  title: string;
  value: string | number;
  icon?: React.ReactNode;
  trend?: {
    value: number;
    direction: 'up' | 'down';
  };
  className?: string;
}

export const DashboardCard: React.FC<DashboardCardProps> = ({
  title,
  value,
  icon,
  trend,
  className = '',
}) => {
  return (
    <div className={`dashboard-card-container ${className}`}>
      <div className="dashboard-card">
        {icon && <div className="card-icon">{icon}</div>}
        <div className="card-content">
          <span className="card-title">{title}</span>
          <span className="card-value">{value}</span>
          {trend && (
            <span
              className={`card-trend ${trend.direction}`}
              aria-label={`${trend.direction === 'up' ? '増加' : '減少'} ${Math.abs(trend.value)}%`}
            >
              {trend.direction === 'up' ? <TrendingUp size={14} /> : <TrendingDown size={14} />}
              {Math.abs(trend.value)}%
            </span>
          )}
        </div>
      </div>
    </div>
  );
};
DashboardCard.css
/* ============================================
   STEP 1: デフォルトスタイル(古いブラウザ向けフォールバック)
   ============================================ */
.dashboard-card {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 1rem;

  background: #ffffff;
  border-radius: 12px;
  padding: 1.25rem 1.5rem;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
  transition: all 0.3s ease;

  /* 重要: コンテンツの縮小を許可 */
  min-width: 0;
}

.card-icon {
  flex-shrink: 0;
  width: 48px;
  height: 48px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #f0f4ff;
  border-radius: 10px;
  color: #4f46e5;
}

.card-content {
  display: flex;
  flex-direction: column;
  min-width: 0;
  flex: 1;
}

.card-title {
  font-size: 0.8rem;
  font-weight: 500;
  color: #6b7280;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.card-value {
  font-size: 1.5rem;
  font-weight: 700;
  color: #111827;
  line-height: 1.2;

  /* Production 向け: 長いテキスト — どちらか一方を選択 */
  /* Strategy 1: 複数行に折り返し */
  overflow-wrap: break-word;
  word-break: break-word;

  /* Strategy 2: 1行 + ellipsis(使う場合はコメント解除) */
  /* white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis; */
}

.card-trend {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  font-size: 0.75rem;
  font-weight: 600;
  margin-top: 0.25rem;
}

.card-trend.up {
  color: #10b981;
}

.card-trend.down {
  color: #ef4444;
}

/* ============================================
   STEP 2: @supports フォールバック付き Container Query
   ============================================ */
@supports (container-type: inline-size) {
  .dashboard-card-container {
    container-type: inline-size;
    container-name: dashboard-card;
    padding: 4px;
  }

  /* --- Query 1: 中サイズ container (300-500px) --- */
  @container dashboard-card (max-width: 500px) and (min-width: 301px) {
    .dashboard-card {
      flex-direction: column;
      text-align: center;
      padding: 1rem;
    }

    .card-icon {
      width: 56px;
      height: 56px;
      font-size: 1.75rem;
    }

    .card-value {
      font-size: 1.25rem;
    }

    .card-title {
      font-size: 0.7rem;
    }
  }

  /* --- Query 2: 小さい container (< 300px) --- */
  @container dashboard-card (max-width: 300px) {
    .dashboard-card {
      flex-direction: column;
      text-align: center;
      padding: 0.75rem;
      gap: 0.5rem;
    }

    .card-icon {
      width: 40px;
      height: 40px;
      font-size: 1.25rem;
    }

    .card-value {
      font-size: 1rem;
    }

    .card-title {
      font-size: 0.6rem;
    }

    /* 狭すぎるときは trend を非表示 */
    .card-trend {
      display: none;
    }
  }

  /* --- Query 3: 広い container (> 500px) --- */
  @container dashboard-card (min-width: 501px) {
    .dashboard-card {
      flex-direction: row;
      padding: 1.25rem 1.5rem;
    }

    .card-value {
      font-size: 1.75rem;
    }
  }

  /* --- Query 4: Style Query — Dark Mode --- */
  @container dashboard-card style(--theme: dark) {
    .dashboard-card {
      background: #1e1e2e;
      box-shadow: 0 2px 8px rgba(0, 0, 0, 0.4);
    }

    .card-title {
      color: #9ca3af;
    }

    .card-value {
      color: #f3f4f6;
    }

    .card-icon {
      background: #2d2d44;
      color: #a5b4fc;
    }
  }

  /* --- Query 5: Size + Style Query の組み合わせ --- */
  @container dashboard-card style(--theme: dark) and (max-width: 300px) {
    .dashboard-card {
      background: #16162a;
      border: 1px solid #2d2d44;
    }

    .card-value {
      color: #e0e7ff;
    }
  }
}

6.3. コンポーネントの使い方(Production 向け)

Style query と継承: DarkThemeContainer が親に --theme: dark をセット。変数は .dashboard-card-containercontainer-name: dashboard-card)に 継承 されるので、カード側で再セットしなくても @container dashboard-card style(--theme: dark) が動きます。CSS 継承 — 古い機能ですが、style query と組み合わせると美味しいです。

App.tsx & App.css — 3コンテキストのデモレイアウト
App.tsx
import React from 'react';
import { DashboardCard } from './DashboardCard';
import { DollarSign, Users, BarChart } from 'lucide-react';

// inline style の代わりにレイアウトコンポーネント
const MainContent: React.FC<{ children: React.ReactNode }> = ({ children }) => {
  return <div className="main-content">{children}</div>;
};

const Sidebar: React.FC<{ children: React.ReactNode }> = ({ children }) => {
  return <div className="sidebar">{children}</div>;
};

// dark テーマの container
const DarkThemeContainer: React.FC<{ children: React.ReactNode }> = ({ children }) => {
  return (
    <div
      className="dark-theme-container"
      style={{ '--theme': 'dark' } as React.CSSProperties}
    >
      {children}
    </div>
  );
};

export const App: React.FC = () => {
  return (
    <div className="app">
      {/* main content 内のカード(幅広) */}
      <MainContent>
        <h3>Main Content</h3>
        <DashboardCard
          title="売上"
          value="12.5億"
          icon={<DollarSign size={24} />}
          trend={{ value: 15, direction: 'up' }}
        />
      </MainContent>

      {/* sidebar 内のカード(狭い) */}
      <Sidebar>
        <h3>Sidebar</h3>
        <DashboardCard
          title="アクセス数"
          value="45.2K"
          icon={<Users size={24} />}
          trend={{ value: 8, direction: 'up' }}
        />
      </Sidebar>

      {/* dark mode container 内のカード */}
      <DarkThemeContainer>
        <h3 style={{ color: 'white' }}>Dark Sidebar</h3>
        <DashboardCard
          title="コンバージョン率"
          value="3.2%"
          icon={<BarChart size={24} />}
          trend={{ value: 2, direction: 'down' }}
        />
      </DarkThemeContainer>
    </div>
  );
};
App.css
.main-content {
  width: 800px;
  padding: 20px;
  background: #f5f5f5;
}

.sidebar {
  width: 250px;
  padding: 20px;
  background: #f5f5f5;
  margin-top: 20px;
}

.dark-theme-container {
  width: 400px;
  padding: 20px;
  background: #1a1a2e;
  margin-top: 20px;
}

6.4. 結果

同じ DashboardCard、3つのコンテキスト — variant なし、場所ごとの media query もなし:

コンテキスト container 幅 レイアウト 備考
Main content 〜800px 横並び、value 大 Size query min-width: 501px
Sidebar 〜250px 縦並び、フォント小 trend indicator 非表示
Dark container 〜400px 縦並び + dark theme Style query --theme: dark

image.png


7. 実務で使えるパターン

よく使うパターンをいくつか — コピーして design system に合わせて breakpoint を調整してください。

7.1. Container Query による Responsive Grid

grid の列数が container に応じて変わる — viewport ではない。sidebar が狭ければ1列、main が広ければ4列 — 同じ grid コンポーネント。

.product-grid {
  container-type: inline-size;
  container-name: grid;
  display: grid;
  gap: 1rem;
}

/* container 幅に応じて列数を自動調整 */
@container grid (min-width: 800px) {
  .product-grid {
    grid-template-columns: repeat(4, 1fr);
  }
}

@container grid (min-width: 500px) and (max-width: 799px) {
  .product-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

@container grid (max-width: 499px) {
  .product-grid {
    grid-template-columns: 1fr;
  }
}

7.2. Container に応じた Fluid Typography

cqi + clamp() — フォントが container にスケール、画面全体ではない。sidebar のカードがランディングページの hero と同じ文字サイズになることはありません。

.article-container {
  container-type: inline-size;
}

@container (min-width: 600px) {
  .article-title {
    font-size: clamp(1.5rem, 4cqi, 3rem);
  }
}

@container (max-width: 599px) {
  .article-title {
    font-size: clamp(1.2rem, 6cqi, 2rem);
  }
}

7.3. ネストした Container Query

Container query は ネスト できます — outer が全体レイアウト、inner が内部を微調整。ただし深くネストしすぎると、パフォーマンスも頭もつらくなります。

.outer {
  container: outer / inline-size;
}

.inner {
  container: inner / inline-size;
}

/* outer container を query */
@container outer (min-width: 600px) {
  .inner {
    display: flex;
  }

  /* inner container を query(ネスト) */
  @container inner (min-width: 300px) {
    .inner-child {
      flex: 1;
    }
  }
}

8. Container Query Units — cqi、cqb など

第13回で fluid layout の cqi に触れました。ここでは一覧表 — 第15回clamp() と viewport units を使った ページ全体 の fluid typography を深掘りします。本記事はコンポーネントレベルまで。

単位 意味 類似
cqi container の inline-size の1% vi(viewport inline)
cqb container の block-size の1% vb(viewport block)
cqw container の width の1% vw
cqh container の height の1% vh
cqmin cqi と cqb の小さい方 vmin
cqmax cqi と cqb の大きい方 vmax

vw/vh との違い: cqi/cqbquery container 基準で、viewport ではありません。タイポグラフィと spacing がコンポーネント単位 — sidebar が hero セクションと同じフォントサイズになることはありません。

.card-title {
  /* フォントサイズ = container 幅の 2〜4% */
  font-size: clamp(1rem, 3cqi, 2.5rem);
}

.card-padding {
  /* container に比例した padding */
  padding: 2cqi;
}

9. Media Query、Container Query、Style Query — どれを使う?

Container Query を始めたばかりのときの定番質問。要約:それぞれ別の問いに答える — どれもがどれもを置き換えるわけではない。間違えるとネジで釘を打つようなもの — できるけど、長期的にはつらい。

状況 使うもの 理由
ページ全体の responsive(header、footer、メイングリッド) Media Query viewport が適切なコンテキスト
再利用コンポーネント(card、sidebar、widget) Container Query 親 container に適応する必要がある
コンテキストに応じたテーマ・Design Token Style Query 親 container のスタイルを query
React のロジック変更(state、props) JavaScript CSS はロジックの代替にならない
Media Query Container Query Style Query
query の基準 Viewport 親 container container のスタイル
適用先 ページ全体 特定コンポーネント コンテキスト別コンポーネント
コンポーネント再利用 難しい 容易 非常に容易
ブラウザサポート 広い Baseline(2026) Baseline(2026)

原則: Container Query は Media Query を 補完 する — 置き換えではない。コンポーネントが固定レイアウトにしか置かれないなら @media の方がシンプル。over-engineer しないで。


10. パフォーマンス & Production のベストプラクティス

Container Query はタダではありません — container-type ごとにブラウザが maintain する context が増えます。container を resize → @container を再評価。アニメーションで resize が続く → ブラウザもあなたもつらい。

状況 影響度
component boundary に数個の container 無視できる
すべての div に container-type 多数の context、遅い
container の連続 resize(アニメーション) 連続再評価
多数の container を持つ大きな DOM context 維持で CPU 消費

黄金律: container-typecomponent boundary — 最外側の wrapper だけに置く。すべての <div> を query container にしないで。DOM はクリスマスツリーではありません。

10.1. @supports によるフォールバック

/* 古いブラウザ向けフォールバック */
.dashboard-card {
  /* デフォルトスタイル */
}

/* 対応ブラウザ向け */
@supports (container-type: inline-size) {
  .dashboard-card-container {
    container-type: inline-size;
  }

  @container (max-width: 500px) {
    .dashboard-card {
      /* responsive スタイル */
    }
  }
}

10.2. 意味のある breakpoint

387px という breakpoint は、特定の画面で trial-and-error した結果であることが多い — 半年後誰も理由を覚えていません。意味のある名前を:compactmediumexpanded

/* ✅ 良い — 意味のある breakpoint */
@container (max-width: 300px) {
  /* compact */
}
@container (min-width: 301px) and (max-width: 500px) {
  /* medium */
}
@container (min-width: 501px) {
  /* expanded */
}

/* ❌ 悪い — 謎の数字 */
@container (max-width: 387px) {
}
@container (min-width: 423px) {
}

10.3. Media Query と Container Query の併用

/* ページ全体レイアウト用 Media Query */
@media (max-width: 768px) {
  .dashboard-grid {
    grid-template-columns: 1fr;
  }
}

/* 内部コンポーネント用 Container Query */
@container dashboard (max-width: 300px) {
  .card-trend {
    display: none;
  }
}

10.4. 意味のある container 名

/* ✅ 良い */
.sidebar {
  container-name: sidebar;
}
.card-grid {
  container-name: card-grid;
}
.widget-area {
  container-name: widget;
}

/* ❌ 悪い */
.container-1 {
  container-name: c1;
}
.wrapper {
  container-name: w;
}

10.5. contain プロパティを理解する

container-type は対応する containment を自動で有効化 — inline-sizecontain: layout inline-sizesizecontain: layout size。Container Query は CSS Containment エコシステムの一部で、単独の浮いた機能ではありません。


11. チェックリスト:Container Query を諦める前に

query が動かない? ブラウザのせいにする前にこのチェックリスト — 90% は container-type の書き忘れか container 名のミスです。

  • container-type を宣言したか?
    Size query には container-type: inline-sizesize が必要。忘れると query は黙る — CSS はエラーを出さず、ただ何もしません。

  • container 名は正しいか?
    @container sidebar (...) なのに container-name: sidebar がない → 動きません。

  • Style Query は Custom Property を使っているか?
    現状はカスタムプロパティのみ。@container style(font-style: italic) を仕様から production にコピーしないで。

  • @supports でフォールバックを用意したか?
    古いブラウザはまだいる — デフォルトスタイルだけで十分使えること。

  • overflow: hidden の影響はないか?
    container のサイズが変わり → query の結果が期待と違うことがある。

  • ブラウザサポートを確認したか?
    Size + style query(カスタムプロパティ)は 2026年5月から Baseline Newly available — それでも ship 前に MDNCan I Use を確認を。

  • 構文は正しいか?

    /* 正しい */
    @container (min-width: 400px) {
    }
    @container sidebar (min-width: 400px) {
    }
    @container style(--theme: dark) {
    }
    
    /* 間違い */
    @container sidebar min-width: 400px {
    } /* 括弧がない */
    
  • layout loop は起きないか?
    Container query は containment により loop しません。Style query も同様 — 安心してください、今回はあなたのせいではない(たぶん)。


12. まとめと参考資料

12.1. 要点

本記事は第13回を、production でよく使う3つで補完します:

  1. Container Naming — DOM がネストしているとき正しい container を query
  2. Style Query — カスタムプロパティによる responsive(テーマ、トークン)
  3. DashboardCard — size + style query、@supports フォールバック付き

12.2. 3つのツール — 1つのエコシステム

Media Query → ページは広いか狭いか?
Container Query → コンポーネントはいくつ分の場所があるか?
Style Query → コンテキストのテーマは何か?

詳細な比較表は セクション9 へ。

12.3. 参考資料


おわりに

「768px の画面でカードはどう見えるか」と聞くのはやめましょう。「container が 300px のとき、カードに何が必要か」— そして「親が dark のとき、カードは自分でわかるか」と聞く。

それが、コンポーネントが本当に再利用できる Design System の作り方 — 1つのコードベース、あらゆるコンテキスト。魔法ではなく、正しい問いをしているだけです。


👉 次回

【Frontend CSS – パート15】Fluid Typography完全ガイド — clamp()・viewport単位・スケーラブルな文字サイズ設計

5
4
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
5
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?