CSS-only Masonry風グリッド

column-count と break-inside: avoid だけで、高さの異なるタイルを石積み状に並べる Masonry 風ギャラリー。JSのライブラリ不要。

#css#masonry#grid

ライブデモ

使用例(お題: アイドルグループ Sakura)

この技法を「アイドルグループ Sakura」というテーマのダミーサイトで実際に使った例です。

HTML
<!-- Sakura フォトギャラリー:column-count の Masonry風で高さ違いの写真を石積み -->
<section class="sk-gal">
  <header class="sk-gal__head">
    <h2 class="sk-gal__title">🌸 Sakura フォトギャラリー</h2>
    <span class="sk-gal__sub">5th LIVE「春一会」オフショット</span>
  </header>

  <div class="sk-gal__masonry">
    <figure class="sk-card sk-card--tall">
      <div class="sk-card__img" style="background-image:url('https://picsum.photos/300/420?random=51')"></div>
      <figcaption>みはる|衣装あわせ</figcaption>
    </figure>
    <figure class="sk-card">
      <div class="sk-card__img" style="background-image:url('https://picsum.photos/300/220?random=52')"></div>
      <figcaption>ことね|リハ前</figcaption>
    </figure>
    <figure class="sk-card sk-card--mid">
      <div class="sk-card__img" style="background-image:url('https://picsum.photos/300/300?random=53')"></div>
      <figcaption>あおい|楽屋にて</figcaption>
    </figure>
    <figure class="sk-card">
      <div class="sk-card__img" style="background-image:url('https://picsum.photos/300/240?random=54')"></div>
      <figcaption>ゆな|笑顔ショット</figcaption>
    </figure>
    <figure class="sk-card sk-card--tall">
      <div class="sk-card__img" style="background-image:url('https://picsum.photos/300/400?random=55')"></div>
      <figcaption>みはる&ことね</figcaption>
    </figure>
    <figure class="sk-card sk-card--mid">
      <div class="sk-card__img" style="background-image:url('https://picsum.photos/300/300?random=56')"></div>
      <figcaption>5人集合</figcaption>
    </figure>
    <figure class="sk-card">
      <div class="sk-card__img" style="background-image:url('https://picsum.photos/300/210?random=57')"></div>
      <figcaption>ステージ袖から</figcaption>
    </figure>
    <figure class="sk-card sk-card--mid">
      <div class="sk-card__img" style="background-image:url('https://picsum.photos/300/280?random=58')"></div>
      <figcaption>アンコール</figcaption>
    </figure>
  </div>
</section>
CSS
/* Sakura:column-count と break-inside:avoid だけで Masonry風フォトギャラリー */
:root {
  --pink: #ffd1e0;
  --pink-deep: #ff8fb3;
  --gray: #fbf7f9;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  height: 400px;
  font-family: "Hiragino Kaku Gothic ProN", "Segoe UI", system-ui, sans-serif;
  background: linear-gradient(165deg, #fff5f9, var(--gray));
  color: #6a2740;
  overflow: hidden;
}

.sk-gal {
  height: 400px;
  display: flex;
  flex-direction: column;
  padding: 14px 16px 0;
}

.sk-gal__head { margin-bottom: 10px; }
.sk-gal__title { margin: 0; font-size: 16px; font-weight: 800; }
.sk-gal__sub { font-size: 11px; color: #c06088; }

/* Masonry風:列数を指定し、各タイルの段割れを禁止 */
.sk-gal__masonry {
  flex: 1;
  min-height: 0;
  overflow: auto;
  column-count: 4;
  column-gap: 10px;
  padding-bottom: 14px;
}
@media (max-width: 520px) { .sk-gal__masonry { column-count: 2; } }

.sk-card {
  break-inside: avoid;
  margin: 0 0 10px;
  border-radius: 12px;
  overflow: hidden;
  background: #fff;
  border: 1px solid #ffe0ea;
  box-shadow: 0 6px 16px rgba(214, 94, 140, 0.14);
  transition: transform 0.2s ease, box-shadow 0.2s ease;
  cursor: pointer;
}
.sk-card:hover {
  transform: translateY(-3px);
  box-shadow: 0 12px 24px rgba(214, 94, 140, 0.24);
}

/* 高さの異なるタイル(石積みのリズムを作る) */
.sk-card__img { height: 110px; background-size: cover; background-position: center; }
.sk-card--mid .sk-card__img { height: 150px; }
.sk-card--tall .sk-card__img { height: 210px; }

.sk-card figcaption {
  padding: 7px 10px;
  font-size: 10.5px;
  color: #8a4a64;
  font-weight: 600;
}

@media (prefers-reduced-motion: reduce) {
  .sk-card { transition: none; }
}
JavaScript
// 写真カードをクリックで「いいね♡」をキャプションにトグル(ファン操作の演出)
const cards = document.querySelectorAll(".sk-gal__masonry .sk-card");

cards.forEach((card) => {
  const cap = card.querySelector("figcaption");
  if (!cap) return;
  const base = cap.textContent;
  card.addEventListener("click", () => {
    const liked = card.dataset.liked === "1";
    card.dataset.liked = liked ? "0" : "1";
    cap.textContent = liked ? base : base + " ♡";
  });
});

コード

HTML
<!-- CSS-only Masonry風グリッド:column-count で高さの違うカードを石積み配置 -->
<div class="mason">
  <h1 class="mason__head">Masonry <span>Wall</span></h1>
  <div class="mason__grid" id="masonGrid">
    <!-- カードはJSで生成(高さの異なるタイル) -->
  </div>
</div>
CSS
/* 全体:ダークグレー地にネオン系タイル */
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
  font-family: "Hiragino Sans", system-ui, sans-serif;
  background: radial-gradient(120% 120% at 50% -10%, #2a2540, #141221 70%);
  color: #f4f3ff; min-height: 100vh; padding: 18px 16px;
}

.mason__head {
  text-align: center; font-size: clamp(18px, 3.4vw, 26px);
  font-weight: 800; letter-spacing: .04em; margin-bottom: 14px;
}
.mason__head span {
  background: linear-gradient(90deg, #f0abfc, #818cf8);
  -webkit-background-clip: text; background-clip: text; color: transparent;
}

/* CSS Multicolumn で Masonry を実現:column 内で要素が積み上がる */
.mason__grid {
  column-count: 4;
  column-gap: 12px;
  width: min(900px, 100%);
  margin: 0 auto;
}
@media (max-width: 720px) { .mason__grid { column-count: 3; } }
@media (max-width: 480px) { .mason__grid { column-count: 2; } }

/* タイル:break-inside で途中分割を防ぐ */
.tile {
  break-inside: avoid;
  margin: 0 0 12px;
  border-radius: 12px;
  padding: 14px;
  color: #15121f;
  font-weight: 700;
  position: relative; overflow: hidden;
  box-shadow: 0 8px 22px -12px rgba(0,0,0,.6);
  animation: pop .5s ease backwards;
}
.tile small { display: block; font-size: 10px; opacity: .6; letter-spacing: .14em; }
.tile b { font-size: 15px; }
.tile::after { /* 光沢 */
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(135deg, rgba(255,255,255,.35), transparent 50%);
  pointer-events: none;
}

@keyframes pop {
  from { opacity: 0; transform: translateY(10px) scale(.96); }
  to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .tile { animation: none; }
}
JavaScript
// 高さ・色が異なるタイルを生成して Masonry 風の見た目を作る
(() => {
  const grid = document.getElementById('masonGrid');
  if (!grid) return;

  // パステル系グラデのペア
  const palettes = [
    ['#a7f3d0', '#6ee7b7'], ['#fbcfe8', '#f9a8d4'],
    ['#bfdbfe', '#93c5fd'], ['#fde68a', '#fcd34d'],
    ['#ddd6fe', '#c4b5fd'], ['#fecaca', '#fca5a5'],
    ['#99f6e4', '#5eead4'], ['#fed7aa', '#fdba74'],
  ];
  const labels = ['UI', 'TYPE', 'COLOR', 'MOTION', 'GRID', 'ICON', '3D', 'PHOTO',
                  'BRAND', 'WEB', 'CODE', 'ART'];

  const frag = document.createDocumentFragment();
  for (let i = 0; i < 14; i++) {
    const tile = document.createElement('div');
    tile.className = 'tile';
    const [c1, c2] = palettes[i % palettes.length];
    // ランダムな高さで石積み感を出す
    const h = 70 + Math.floor(Math.random() * 90);
    tile.style.minHeight = h + 'px';
    tile.style.background = `linear-gradient(160deg, ${c1}, ${c2})`;
    tile.style.animationDelay = (i * 0.04) + 's';
    tile.innerHTML =
      `<small>#${String(i + 1).padStart(2, '0')}</small>` +
      `<b>${labels[i % labels.length]}</b>`;
    frag.appendChild(tile);
  }
  grid.appendChild(frag);
})();

🤖 AIエージェント用プロンプト

このままコピーしてAIに貼り付け「追加する場所」だけ書き換えればOK
あなたは熟練のフロントエンドエンジニアです。私のWebサイトに「CSS-only Masonry風グリッド」の効果を追加してください。

# 追加してほしい効果
CSS-only Masonry風グリッド(レイアウト & グリッド)
column-count と break-inside: avoid だけで、高さの異なるタイルを石積み状に並べる Masonry 風ギャラリー。JSのライブラリ不要。

# 追加する場所
👉【ここに対象箇所を記入:例「トップのヒーローセクション」「お問い合わせボタン」「記事カードの一覧」など】

# 参考実装(この見た目・挙動を再現してください)
【HTML】
<!-- CSS-only Masonry風グリッド:column-count で高さの違うカードを石積み配置 -->
<div class="mason">
  <h1 class="mason__head">Masonry <span>Wall</span></h1>
  <div class="mason__grid" id="masonGrid">
    <!-- カードはJSで生成(高さの異なるタイル) -->
  </div>
</div>

【CSS】
/* 全体:ダークグレー地にネオン系タイル */
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
  font-family: "Hiragino Sans", system-ui, sans-serif;
  background: radial-gradient(120% 120% at 50% -10%, #2a2540, #141221 70%);
  color: #f4f3ff; min-height: 100vh; padding: 18px 16px;
}

.mason__head {
  text-align: center; font-size: clamp(18px, 3.4vw, 26px);
  font-weight: 800; letter-spacing: .04em; margin-bottom: 14px;
}
.mason__head span {
  background: linear-gradient(90deg, #f0abfc, #818cf8);
  -webkit-background-clip: text; background-clip: text; color: transparent;
}

/* CSS Multicolumn で Masonry を実現:column 内で要素が積み上がる */
.mason__grid {
  column-count: 4;
  column-gap: 12px;
  width: min(900px, 100%);
  margin: 0 auto;
}
@media (max-width: 720px) { .mason__grid { column-count: 3; } }
@media (max-width: 480px) { .mason__grid { column-count: 2; } }

/* タイル:break-inside で途中分割を防ぐ */
.tile {
  break-inside: avoid;
  margin: 0 0 12px;
  border-radius: 12px;
  padding: 14px;
  color: #15121f;
  font-weight: 700;
  position: relative; overflow: hidden;
  box-shadow: 0 8px 22px -12px rgba(0,0,0,.6);
  animation: pop .5s ease backwards;
}
.tile small { display: block; font-size: 10px; opacity: .6; letter-spacing: .14em; }
.tile b { font-size: 15px; }
.tile::after { /* 光沢 */
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(135deg, rgba(255,255,255,.35), transparent 50%);
  pointer-events: none;
}

@keyframes pop {
  from { opacity: 0; transform: translateY(10px) scale(.96); }
  to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .tile { animation: none; }
}

【JavaScript】
// 高さ・色が異なるタイルを生成して Masonry 風の見た目を作る
(() => {
  const grid = document.getElementById('masonGrid');
  if (!grid) return;

  // パステル系グラデのペア
  const palettes = [
    ['#a7f3d0', '#6ee7b7'], ['#fbcfe8', '#f9a8d4'],
    ['#bfdbfe', '#93c5fd'], ['#fde68a', '#fcd34d'],
    ['#ddd6fe', '#c4b5fd'], ['#fecaca', '#fca5a5'],
    ['#99f6e4', '#5eead4'], ['#fed7aa', '#fdba74'],
  ];
  const labels = ['UI', 'TYPE', 'COLOR', 'MOTION', 'GRID', 'ICON', '3D', 'PHOTO',
                  'BRAND', 'WEB', 'CODE', 'ART'];

  const frag = document.createDocumentFragment();
  for (let i = 0; i < 14; i++) {
    const tile = document.createElement('div');
    tile.className = 'tile';
    const [c1, c2] = palettes[i % palettes.length];
    // ランダムな高さで石積み感を出す
    const h = 70 + Math.floor(Math.random() * 90);
    tile.style.minHeight = h + 'px';
    tile.style.background = `linear-gradient(160deg, ${c1}, ${c2})`;
    tile.style.animationDelay = (i * 0.04) + 's';
    tile.innerHTML =
      `<small>#${String(i + 1).padStart(2, '0')}</small>` +
      `<b>${labels[i % labels.length]}</b>`;
    frag.appendChild(tile);
  }
  grid.appendChild(frag);
})();

# 外部ライブラリ
なし(追加ライブラリ不要)

# 守ってほしいこと
- 既存のHTML構造・レイアウト・デザインを壊さないこと。必要に応じてクラス名・色・サイズを私のサイトに合わせて調整してよい。
- クラス名やidが既存と衝突しないよう、必要なら接頭辞で名前空間を分けること。
- レスポンシブ対応と prefers-reduced-motion への配慮を入れること。
- 私のサイトのフレームワーク(React / Vue / 素のHTML など)に合わせて実装すること。不明な場合は素のHTML/CSS/JSで提示し、組み込み手順も説明すること。
- 変更後の確認手順も簡潔に教えてください。