記事カード一覧(グリッド)
記事一覧向けのカードグリッド。カラム数は auto-fill で自動調整、画像は aspect-ratio で比率固定、カード全体がクリック領域になります。JavaScript不要。
プレビュー
<ul class="card-grid">
<li>
<article class="card">
<figure class="card__figure">
<img
class="card__image"
src="https://picsum.photos/seed/webgl/640/360"
alt=""
width="640"
height="360"
loading="lazy"
/>
</figure>
<div class="card__body">
<div class="card__meta">
<span class="card__tag">WebGL</span>
<time class="card__date" datetime="2026-08-20">2026.08.20</time>
</div>
<h3 class="card__title">
<a class="card__link" href="/columns/webgl-basics">
WebGLサイトのスクロール演出は、どこまでリアルタイムでやるべきか
</a>
</h3>
<p class="card__excerpt">
事前レンダリングとリアルタイム描画の境界線を、実際の受賞サイトの実装から整理します。
</p>
</div>
</article>
</li>
<li>
<article class="card">
<figure class="card__figure">
<img
class="card__image"
src="https://picsum.photos/seed/gltf/640/360"
alt=""
width="640"
height="360"
loading="lazy"
/>
</figure>
<div class="card__body">
<div class="card__meta">
<span class="card__tag">glTF</span>
<time class="card__date" datetime="2026-08-14">2026.08.14</time>
</div>
<h3 class="card__title">
<a class="card__link" href="/columns/gltf-pipeline">
Draco と KTX2 で、3Dモデルの転送量を10分の1にする
</a>
</h3>
<p class="card__excerpt">
ジオメトリ圧縮とGPUテクスチャ圧縮を、実際のファイルサイズの数字とあわせて解説します。
</p>
</div>
</article>
</li>
<li>
<article class="card">
<figure class="card__figure">
<img
class="card__image"
src="https://picsum.photos/seed/webgpu/640/360"
alt=""
width="640"
height="360"
loading="lazy"
/>
</figure>
<div class="card__body">
<div class="card__meta">
<span class="card__tag">WebGPU</span>
<time class="card__date" datetime="2026-08-05">2026.08.05</time>
</div>
<h3 class="card__title">
<a class="card__link" href="/columns/webgpu-fallback">
WebGPUで書いてWebGLで動かす、TSLという選択肢
</a>
</h3>
<p class="card__excerpt">
ノードベースで書いたシェーダを両バックエンドに出し分ける、現実的な移行戦略。
</p>
</div>
</article>
</li>
</ul>/* このスニペット配下だけ box-sizing を揃える(既存のリセットとは競合しません) */
.card-grid,
.card-grid *,
.card-grid *::before,
.card-grid *::after {
box-sizing: border-box;
}
.card-grid {
--card-bg: #ffffff;
--card-fg: #111827;
--card-muted: #6b7280;
--card-border: #e5e7eb;
--card-accent: #2563eb;
--card-min: 260px;
display: grid;
grid-template-columns: repeat(auto-fill, minmax(var(--card-min), 1fr));
gap: 1.5rem;
margin: 0;
padding: 0;
list-style: none;
}
.card {
display: flex;
flex-direction: column;
height: 100%;
overflow: hidden;
border: 1px solid var(--card-border);
border-radius: 12px;
background: var(--card-bg);
color: var(--card-fg);
transition: box-shadow 0.2s, border-color 0.2s;
}
.card:hover {
border-color: var(--card-muted);
box-shadow: 0 8px 24px rgb(0 0 0 / 8%);
}
.card__figure {
margin: 0;
aspect-ratio: 16 / 9;
overflow: hidden;
/* 画像が読み込まれるまでの下地 */
background: linear-gradient(135deg, #e5e7eb, #f3f4f6);
}
.card__image {
display: block;
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 0.3s;
}
.card:hover .card__image {
transform: scale(1.05);
}
.card__body {
display: flex;
flex: 1;
flex-direction: column;
padding: 1rem 1.125rem 1.25rem;
}
.card__meta {
display: flex;
align-items: center;
gap: 0.625rem;
font-size: 0.75rem;
color: var(--card-muted);
}
.card__tag {
padding: 0.15rem 0.5rem;
border-radius: 999px;
background: color-mix(in srgb, var(--card-accent) 12%, transparent);
color: var(--card-accent);
font-weight: 600;
}
.card__date {
font-variant-numeric: tabular-nums;
}
.card__title {
margin: 0.625rem 0 0;
font-size: 0.9375rem;
font-weight: 700;
line-height: 1.6;
}
/* カード全体をクリック領域にする */
.card__link {
color: inherit;
text-decoration: none;
}
.card__link::after {
content: "";
position: absolute;
inset: 0;
}
.card {
position: relative;
}
.card__link:hover {
color: var(--card-accent);
}
.card__link:focus-visible {
outline: 2px solid var(--card-accent);
outline-offset: 3px;
}
.card__excerpt {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
line-clamp: 2;
overflow: hidden;
margin: 0.5rem 0 0;
color: var(--card-muted);
font-size: 0.8125rem;
line-height: 1.8;
}
@media (prefers-color-scheme: dark) {
.card-grid {
--card-bg: #1f2937;
--card-fg: #f9fafb;
--card-muted: #9ca3af;
--card-border: #374151;
--card-accent: #60a5fa;
}
.card__figure {
background: linear-gradient(135deg, #374151, #1f2937);
}
}
/* ここから下はプレビュー表示用です。コピーして使うときは不要です */
body {
margin: 0;
background: #ffffff;
font-family: system-ui, -apple-system, "Segoe UI", "Hiragino Sans",
"Noto Sans JP", sans-serif;
color: #111827;
}
@media (prefers-color-scheme: dark) {
body {
background: #111827;
color: #f9fafb;
}
}
