Skip to content
Published on

Web 標準 & CSS 2026 — Container Queries / View Transitions / Popover / Anchor Positioning / Scroll-driven Animations 徹底ガイド

Authors

1. 2026 年のウェブプラットフォーム — ついに到着した標準たち

10 年前、私たちは「もうすぐ標準になる」と言いながらポリフィルを入れていた。2026 年、私たちは 標準がそのまま日常 となった時代に生きている。

今この瞬間、Chrome 130+、Safari 18+、Firefox 130+ がすべて安定サポートしている:

  • Container Queries — コンポーネント時代のメディアクエリ
  • View Transitions API — 単一ページ版 (2023) + クロスドキュメント版 (2024)
  • Popover API — ネイティブモーダル (2024 年に全ブラウザで安定化)
  • Anchor Positioning — Chrome 125 (2024.4)、Safari/Firefox 2025
  • Scroll-driven Animations — Chrome 115 (2023.7)、Safari/Firefox 2025
  • CSS Nesting — 2023 年に安定化
  • :has() セレクタ — 普遍的サポート
  • color-mix() / light-dark() — 普遍的サポート
  • @scope / @layer — Chrome/Safari/Firefox すべてサポート
  • Subgrid — Chrome 117、Safari 16、Firefox 71 (普遍的サポート)
  • Speculation Rules API — 次ページの prerender
  • WebGPU / WebTransport — 安定化

「今新規プロジェクトを始めるなら何を使うべきか?」の答えはついに簡潔になった。標準をそのまま使えばいい。 この記事はその新しいベースラインを一章ずつ追う。

この記事のコードは一行たりともポリフィルを必要としない。2026 年の evergreen ブラウザの最新安定版を基準に書いている。


2. Container Queries — コンポーネント時代のメディアクエリ

なぜメディアクエリでは不十分か

メディアクエリは ビューポート基準 だ。しかしコンポーネントはサイドバーやモーダル、カードグリッド、サイドパネルの中で生きている。同じカードコンポーネントがサイドバーに入ると狭く、メイン領域に入ると広くなる。ビューポート幅は同じ。コンテナ幅だけが違う。

.card-container {
  container-type: inline-size;
  container-name: card;
}

@container card (min-width: 400px) {
  .card {
    display: grid;
    grid-template-columns: 1fr 2fr;
    gap: 1.5rem;
  }
}

@container card (max-width: 399px) {
  .card {
    display: flex;
    flex-direction: column;
  }
}

container-type の 3 つの値

意味
inline-sizeインライン(横幅)のみクエリ可能 — 最もよく使う
size両軸クエリ可能 — パフォーマンスコストが大きい
normalコンテナでない (デフォルト)

size は子要素の高さが親に影響しないよう遮断する必要があり、コストが大きい。99% のケースで inline-size で十分。

Container Query 単位

.hero-title {
  font-size: clamp(1.5rem, 5cqi, 3rem);
}

cqi (container query inline-size)、cqb (block-size)、cqwcqhcqmincqmax。ビューポート単位 vw/vh のコンテナ版だ。

実戦パターン

.product-grid {
  container-type: inline-size;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(280px, 100%), 1fr));
  gap: 1rem;
}

@container (min-width: 900px) {
  .product-card .image {
    aspect-ratio: 4 / 3;
  }
}

@container (max-width: 600px) {
  .product-card .price {
    font-size: 0.875rem;
  }
}

同じカードがモーダル、サイドバー、メイン領域のどこに入っても自分のコンテナ幅に応じて自動適応する。コンポーネントが本当のコンポーネントになる。


3. View Transitions API — 単一ページからクロスドキュメントへ (2024)

Same-document 版 (2023)

状態が変わるとき、ブラウザが自動的にスムーズな遷移を作ってくれる。

function updateList(newItems) {
  if (!document.startViewTransition) {
    renderList(newItems)
    return
  }
  document.startViewTransition(() => renderList(newItems))
}
::view-transition-old(root) {
  animation: fade-out 200ms ease-out;
}
::view-transition-new(root) {
  animation: fade-in 200ms ease-in;
}

@keyframes fade-out { to { opacity: 0; } }
@keyframes fade-in  { from { opacity: 0; } }

名前付き遷移

特定要素だけ別の遷移を:

.product-card .image {
  view-transition-name: product-image;
}

::view-transition-old(product-image),
::view-transition-new(product-image) {
  animation-duration: 400ms;
}

商品カードをクリックして詳細ページへ移動するとき、画像がそのまま拡大される ネイティブモバイルアプリ風の遷移ができる。

Cross-document 版 (2024)

ここが本当の革命だ。MPA (Multi-Page App) でもページ遷移をスムーズに できる。

@view-transition {
  navigation: auto;
}

.hero-image {
  view-transition-name: hero;
}

前ページの .hero-image と新ページの .hero-image が同じ名前を共有していれば、ブラウザが自動的に両者の間を遷移させる。SPA ルータも、Next.js の Link も要らない。<a href> のクリックだけで。

MPA 遷移の意味

過去 10 年、私たちが SPA を使った最大の理由のひとつが「ページ遷移を滑らかにしたい」だった。View Transitions の cross-document 版はその理由を消す。Next.js、Astro、SvelteKit すべてが自動的に活用している。

注意点

  • 遷移中はユーザー入力が一瞬ブロックされうる → 短く (200~300ms)
  • prefers-reduced-motion: reduce ユーザー向けの遮断オプションを用意
  • view-transition-name はページ内で ユニーク でなければならない

4. Popover API (2024) — ネイティブモーダル

なぜ私たちはモーダルで毎回失敗したか

  • フォーカストラップ
  • ESC で閉じる
  • 外側クリックで閉じる
  • バックドロップ
  • z-index 地獄
  • アクセシビリティ (role、aria、focus 管理)

これらすべてを ブラウザがやってくれる。2024 年から。

<button popovertarget="my-popover">Open</button>

<div id="my-popover" popover>
  <h2>Hello</h2>
  <button popovertarget="my-popover" popovertargetaction="hide">Close</button>
</div>

これだけで:

  • ESC で閉じる
  • 外側クリックで閉じる (auto モード)
  • フォーカス自動移動
  • 常に top layer にレンダー (z-index は関係ない)

popover の 2 モード

動作
auto (デフォルト)ESC、外側クリック、別 popover が開くと閉じる
manual明示的にのみ閉じる (トースト、通知用)

バックドロップスタイリング

[popover]::backdrop {
  background: oklch(0% 0 0 / 0.6);
  backdrop-filter: blur(8px);
}

<dialog> との違い

<dialog> はフォーム統合と modal/non-modal の区別がある。Popover はより軽量で任意の要素に適用できる。一般的には:

  • フルモーダル(フォーム送信など)<dialog>
  • メニュー、ツールチップ、カード hover → popover

5. Anchor Positioning (Chrome 125、2024.4) — ツールチップ・ポップオーバー配置

かつての悪夢

ツールチップライブラリ一つ使うために Floating UI (旧 Popper.js) を入れ、ビューポート衝突を検出し、scroll イベントを聞き、ResizeObserver を仕掛けて… 本当に狂気の沙汰だった。

今では:

<button id="trigger" style="anchor-name: --my-button">Hover me</button>

<div popover id="tooltip">
  Tooltip content
</div>

<style>
  #tooltip {
    position-anchor: --my-button;
    top: anchor(bottom);
    left: anchor(center);
    translate: -50% 0;
  }
</style>

ブラウザがトリガー要素の位置を自動追跡する。スクロールしてもリサイズしても付いてくる。

position-try-fallbacks — 自動的なビューポート衝突回避

#tooltip {
  position-anchor: --my-button;
  position-area: bottom;
  position-try-fallbacks: top, right, left;
}

デフォルトは下に表示、空間が足りなければ上 → 右 → 左の順で自動試行。Floating UI の 1 行もなしに。

position-area — 9 分割の省略記法

#tooltip {
  position-area: top span-all;
}

topbottomleftrightcenterspan-allstartend などで表現。頭の中に 9 分割グリッドを置くと直感的になる。

できないこと

  • 一つの要素が複数のアンカーを同時参照 (CSS Anchor Positioning Level 2 で検討中)
  • position: fixedabsolute でなければ動作しない

Floating UI の運命

依然として有効だ — 複雑な衝突検出や矢印の自動配置のような高度機能はまだライブラリが優れている。ただし 80% のシンプルなツールチップ・ポップオーバーは CSS だけで十分になった。


6. Scroll-driven Animations (Chrome 115) — JS なしのスクロール演出

2 種類のスクロールタイムライン

タイムライン意味
scroll()スクロールコンテナ全体のスクロール進行度
view()特定要素がビューポートを横切る進行度

scroll() — 進捗インジケータ

@keyframes grow-progress {
  from { transform: scaleX(0); }
  to   { transform: scaleX(1); }
}

.progress-bar {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: 4px;
  background: oklch(70% 0.2 250);
  transform-origin: left;
  animation: grow-progress linear;
  animation-timeline: scroll();
}

スクロールすると自動的に埋まる。JavaScript 一行もなし。

view() — ビューポート進入時のフェードイン

@keyframes fade-in {
  from { opacity: 0; transform: translateY(40px); }
  to   { opacity: 1; transform: translateY(0); }
}

.card {
  animation: fade-in linear;
  animation-timeline: view();
  animation-range: entry 0% cover 40%;
}

要素がビューポート下端に入り始めるときに開始し、40% 見えたら終了。Intersection Observer のコード一行もなし。

prefers-reduced-motion 対応

@media (prefers-reduced-motion: no-preference) {
  .card {
    animation: fade-in linear;
    animation-timeline: view();
  }
}

アクセシビリティを忘れずに。

パフォーマンス

スクロール駆動アニメーションは コンポジタスレッド で実行される。JavaScript scroll ハンドラと違ってメインスレッドを止めない。60fps が基本で 120fps も可能。


7. CSS Nesting (2023) — Sass なしのネスト

標準の文法

.card {
  padding: 1rem;
  border-radius: 0.5rem;

  & .title {
    font-size: 1.5rem;
    font-weight: 600;
  }

  & .description {
    color: oklch(50% 0 0);
  }

  &:hover {
    transform: translateY(-2px);
  }

  @media (min-width: 768px) {
    padding: 1.5rem;
  }
}

Sass との違いはわずか。& がより頻繁に必要 (2023 年初期は必須、後に緩和)。

Sass との差分

  • 変数 は標準ではない → CSS Custom Properties (--var) を使う
  • ミックスイン はまだ検討中
  • @extend は標準化される可能性が低い

マイグレーション

/* Before (Sass) */
.btn {
  &.primary { background: blue; }
  &.danger { background: red; }
}

/* After (native CSS nesting) */
.btn {
  &.primary { background: oklch(60% 0.2 250); }
  &.danger  { background: oklch(60% 0.25 25); }
}

ほぼそのまま動く。


8. :has() — 親セレクタ

「CSS に親セレクタがない理由」は終わった

/* カードに画像があれば異なるレイアウト */
.card:has(img) {
  display: grid;
  grid-template-columns: 1fr 2fr;
}

/* フォーム内に invalid 入力があれば送信ボタンを無効風に */
form:has(input:invalid) button[type="submit"] {
  opacity: 0.5;
  pointer-events: none;
}

/* html に light クラスがなければダークモード */
html:not(.light) {
  color-scheme: dark;
}

実戦パターン

1) 親子の同時条件

.dropdown:has(:focus-visible) {
  outline: 2px solid currentColor;
}

2) 兄弟ベースのスタイリング

label:has(+ input:required)::after {
  content: ' *';
  color: oklch(60% 0.25 25);
}

3) 空状態の処理

.list:not(:has(.list-item)) {
  display: none;
}

パフォーマンス

:has() は総当たりではなく無効化追跡を持っている。非常に大きな DOM でも実用的。


9. color-mix() / light-dark() — 色の演算

color-mix() — 2 色を混ぜる

.btn {
  background: color-mix(in oklch, blue, white 20%);
}

.btn:hover {
  background: color-mix(in oklch, blue, white 30%);
}

in oklch / in lab / in srgb / in hsl などで色空間を明示。一般に oklch が最も自然 (人間の知覚に近い均等空間)。

デザイントークンとの結合

:root {
  --brand: oklch(60% 0.2 250);
}

.btn {
  background: var(--brand);
}
.btn:hover {
  background: color-mix(in oklch, var(--brand), white 15%);
}
.btn:active {
  background: color-mix(in oklch, var(--brand), black 15%);
}

色のバリエーションをひとつひとつ定義する必要なく、一つの brand から派生

light-dark() — ダークモードを 1 行で

:root {
  color-scheme: light dark;
  --bg: light-dark(white, oklch(15% 0 0));
  --fg: light-dark(oklch(15% 0 0), white);
}

body {
  background: var(--bg);
  color: var(--fg);
}

prefers-color-scheme メディアクエリを 2 回書く必要なく 1 行。ただし color-scheme: light dark を必ず宣言 すること。

なぜ OKLCH が標準になりつつあるか

#hexrgb() は RGB 色空間で人間の知覚と一致しない。oklch(60% 0.2 250) は:

  • L = 明度 (0~100%)
  • C = 彩度 (0~0.4)
  • H = 色相 (0~360)

色同士の補間が自然で、明度変化が直感的。2026 年のデザインシステムは事実上 OKLCH ベース。


10. @scope / @layer — カプセル化とカスケード

@scope — CSS の本当のスコープ

@scope (.card) to (.card-content) {
  h2 {
    font-size: 1.25rem;
  }
}

.card の内側だが .card-content までは適用されない。lower boundary を持つ本物のスコープ。

@scope (.dark-section) {
  a {
    color: white;
  }
}

.dark-section 内の <a> だけが白になる。

@layer — カスケードレイヤー

@layer reset, base, components, utilities;

@layer reset {
  * { margin: 0; padding: 0; }
}

@layer base {
  body { font-family: system-ui; }
}

@layer components {
  .btn { padding: 0.5rem 1rem; }
}

@layer utilities {
  .text-center { text-align: center; }
}

レイヤー順序が後ろほど優先。詳細度とは無関係。

重要な理由: Tailwind/UnoCSS の utility-first は詳細度戦争を引き起こした。@layer utilities に置けば常に最後 → utility は詳細度の戦いなしに常に勝つ。

Cascade Layers + Tailwind 4

Tailwind 4 は内部的に @layer を使う。自分の CSS を別のレイヤーに置けば、優先順位がきれいに整理される。


11. Subgrid — ついに普遍的サポート

問題の定義

<ul class="cards">
  <li class="card">
    <h2>Short title</h2>
    <p>Description</p>
    <button>Buy</button>
  </li>
  <li class="card">
    <h2>A much longer title that wraps to two lines</h2>
    <p>Description</p>
    <button>Buy</button>
  </li>
</ul>

カード内のタイトル・説明・ボタンがカード間で 横方向に揃って ほしい。親 grid のグリッドラインを子が継承する必要がある。

Subgrid による解決

.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 1rem;
}

.card {
  display: grid;
  grid-template-rows: subgrid;
  grid-row: span 3;
}

grid-template-rows: subgrid で親の行構造を継承。タイトルたちが自動的に同じ高さに揃う。

Subgrid が解決したもの

  • カードグリッドのタイトル・画像・ボタン整列
  • フォームのラベル・入力整列
  • 表のようなコンポーネントのマス目整列
  • デザインシステムの一貫した spacing

12. Speculation Rules — 次ページの prerender

何か

ユーザーがクリックしそうなリンクを 事前にレンダー する。prefetch より強力で、DOM や JavaScript 実行まで含む。

<script type="speculationrules">
{
  "prerender": [
    {
      "where": { "href_matches": "/articles/*" },
      "eagerness": "moderate"
    }
  ]
}
</script>

/articles/ で始まるすべてのリンクについて、ユーザーが hover や touch start といった意図信号を見せたら、ページが事前レンダリングされる。

eagerness レベル

意味
immediate即座 (慎重に使う必要あり)
eagerビューポートに入ったら
moderatehover 200ms または mousedown
conservativemousedown のみ

効果

次ページの LCP が 数ミリ秒 に落ちる。ユーザーの目からは「クリックと同時に次のページが既にそこにある」。

Next.js との関係

Next.js App Router は自動で prefetch する (コード/データ)。Speculation Rules の prerender は DOM まで レンダーするのでさらに強力。Next.js 15+ ではオプトイン可。


13. WebGPU / WebTransport — 安定化

WebGPU

  • Chrome 113 (2023.5)、Safari 18、Firefox 121+ で安定サポート
  • シェーダ言語: WGSL
  • 機械学習 (transformers.js、MediaPipe、ONNX Runtime Web)、高度なグラフィック、GPU コンピュート
  • WebGL と違い、コンピュートシェーダや modern GPU 機能を露出

ブラウザで LLM 推論 (WebLLM)、画像処理、シミュレーションを GPU 加速で実行できる。ChatGPT 風モデルをブラウザタブ内でローカルに動かす時代が本当に来た。

WebTransport

  • HTTP/3 ベースの双方向通信
  • WebSocket の後継 (UDP ベースの信頼性オプション)
  • 複数ストリーム、head-of-line blocking なし
  • リアルタイムゲーム、WebRTC データチャネル代替
const transport = new WebTransport('https://example.com/wt')
await transport.ready
const stream = await transport.createBidirectionalStream()
const writer = stream.writable.getWriter()
await writer.write(new TextEncoder().encode('hello'))

その他の安定化された API

  • Custom Highlight API — ブラウザ selection 以外のユーザー定義ハイライト
  • content-visibility: auto — 画面外コンテンツのレンダリングコスト削減
  • Performance.measureUserAgentSpecificMemory — 正確なメモリ計測
  • Storage Access APICHIPS — サードパーティ Cookie 時代対応

14. 韓国 / 日本のウェブ標準コンテンツ — Naver D2、html5.jp、mizchi

韓国

  • Naver D2 (d2.naver.com) — ウェブ標準、ブラウザ内部、パフォーマンス最適化記事が安定的にアップされる。2024-2025 年の View Transitions、Container Queries 関連分析が良質。
  • TOAST UI ブログ — 標準 + 自社ライブラリ実装ノウハウ
  • Frontender Kakao オープンチャット / Frontier カンファレンス — 韓国語で標準を追うのに良いコミュニティ
  • MDN 韓国語訳 — まだ一部だが、新機能の韓国語化が以前より早くなった

日本

  • html5.jp — 古いサイトだが、仕様翻訳が最も早く正確
  • mizchi ブログ — フロントエンドトレンド/仕様動向の分析。批判的視点が強く、標準の限界も見せてくれる
  • Web Developer Conference (Tokyo) — 毎年標準関連発表が豊富
  • CodeGrid (Pixel Grid) — 有料だが深い CSS 標準解説
  • MDN 日本語 — 英語版とほぼ同時更新

英語圏

  • web.dev — Google 公式、新機能ガイドの本拠地
  • CSS Tricks — 依然良い (2025 年から新記事のペースは減ったが)
  • Smashing Magazine — 深い記事多数
  • State of CSS / State of JS — 毎年のトレンド調査
  • Una Kravets、Adam Argyle、Bramus のブログ — Chrome DevRel の一次情報源

日本の標準活動の特異性

W3C 日本ノードの活動が非常に活発。韓国と違って日本は仕様翻訳の文化が強く、仕様について一文一文噛み砕く記事が多い。標準の「なぜ」を知りたければ html5.jp の記事を読むことを勧める。


15. マイグレーション戦略 — どこから導入するか

優先順位

Tier 1 — 今すぐ導入可 (普遍的サポート)

  • Container Queries
  • CSS Nesting
  • :has()
  • color-mix()light-dark()
  • @layer
  • Subgrid
  • Popover API
  • View Transitions (same-document)

Tier 2 — 段階的導入 (大半サポート、graceful fallback 推奨)

  • View Transitions (cross-document)
  • Anchor Positioning
  • Scroll-driven Animations
  • @scope

Tier 3 — オプトイン (特定シナリオ)

  • Speculation Rules API
  • WebGPU (ML/グラフィック)
  • WebTransport (リアルタイム)

Progressive enhancement の典型

.tooltip {
  /* fallback: basic absolute positioning */
  position: absolute;
  top: 100%;
  left: 50%;
  transform: translateX(-50%);
}

@supports (position-anchor: --x) {
  .tooltip {
    position-anchor: --trigger;
    top: anchor(bottom);
    left: anchor(center);
    transform: translateX(-50%);
  }
}

@supports で分岐。新機能があれば強化、なければ既存動作。

デザインシステムのマイグレーション・チェックリスト

  1. OKLCH 色マイグレーション — デザイントークンから color-mix(in oklch, ...) ベースに
  2. モーダルライブラリ → Popover API — フォームが入るなら dialog、それ以外は popover
  3. Floating UI → Anchor Positioning — シンプルなツールチップ・ポップオーバーから移行
  4. Intersection Observer → Scroll-driven Animations — fade-in 系から
  5. Tailwind/Sass 変数 → @layer 整理 — 優先順位の衝突終了
  6. レスポンシブコンポーネント → Container Queries — メディアクエリをコンテナクエリへ
  7. SPA ルータ遷移 → View Transitions (cross-document) — 段階的導入

よく踏む罠

  • view-transition-name はページ内ユニーク必須 → 動的リストなら ID ベース
  • Anchor Positioning は position: absolute/fixed のみ動作
  • Scroll-driven Animations には prefers-reduced-motion 分岐必須
  • Popover の popovertarget は ID 参照 → React で動的 ID は慎重に
  • Container Queries は container-type が layout containment を強制 → 一部レイアウトが崩れうる

結論 — 2026 年の基礎

この記事のすべての機能は 2026 年 evergreen ブラウザの基礎 だ。「高度な CSS」ではなくただの CSS。もう一つライブラリを入れる前に「これ標準にあるんじゃないか?」と一度確認しよう。大半の答えは「ある」だ。

2026 年のウェブ開発は、標準にベットすれば勝てる時代だ。


参考 / References