modern-css について
modern-cssは、モダンで堅牢なCSSを書くためのリファレンススキルです。レスポンシブな画面やインタラクティブなコンポーネントを作る開発者向けに、レイアウト、色、タイポグラフィ、アニメーション、ブラウザー対応を扱い、段階的な拡張とユーザー設定への配慮を重視します。
主な機能
- 01コンテナクエリとレスポンシブレイアウト
- 02モダンな色空間とテーマ設定
- 03流動的なタイポグラフィと動的ビューポート単位
- 04スクロールアニメーションとビュー遷移
- 05ポップオーバー、アンカー配置、フォーム拡張
- 06段階的拡張とブラウザー対応の確認
活用シーン
- 01コンテナサイズに応じたコンポーネントのスタイル作成
- 02モダンな配色でライト・ダークテーマを設計
- 03アニメーション、ポップオーバー、フォーム操作を構築
- 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 年以内にサポートされています
- 新たに利用可能: すべての主要ブラウザーで利用できます
- 限定的に利用可能: まだすべてのブラウザーで利用できるわけではありません
ベースラインのステータスを確認する方法
- 最適な方法: https://web-platform-dx.github.io/web-features-explorer/groups/ を取得して機能を探し、その詳細ページを取得します。
- Can I Use: caniuse.com では、各機能の上部にベースラインバッジが表示されます
- MDN: ブラウザー互換性テーブルでベースラインバッジを確認します
- 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>
正規リソース
- CSS Wrapped 2025 - 今年の CSS 機能
- The Coyier CSS Starter - 意見を盛り込んだモダンなベースライン
- Adam Argyle's CascadiaJS 2025 Deck - (ローカルの ./argyle-cacadia-2025-deck.md で Markdown 化済み)
- Modern CSS in Real Life - 実践的な活用例
使用ガイドライン
-
安定性を優先する:
- 本番コードには Newly Available または Widely Available の機能を推奨します。
- Limited Availability の機能は、プログレッシブエンハンスメント、グレースフルデグラデーション、または
@supportsと併用してください。あるいは、どのように扱いたいかをユーザーに確認してください。
-
Web プラットフォームを活用する:
- レイアウト、アニメーション、インタラクションには、JavaScript ライブラリよりも常に標準の CSS ソリューションを優先してください (例: Masonry.js の代わりに CSS Masonry、カスタムツールチップスクリプトの代わりに Popover API)。
-
コードスタイル:
- 新しいパレットにはモダンな色空間 (
oklch) を使用してください。
- 新しいパレットにはモダンな色空間 (