クレイモーフィズム
内外の二重シャドウでぷっくり膨らんだ粘土風カード。やわらかく親しみやすいUIやSNS系コンポーネントに向きます。
ライブデモ
使用例(お題: カフェ MOON BREW)
この技法を「カフェ MOON BREW」というテーマのダミーサイトで実際に使った例です。
<!-- MOON BREW:クレイモーフィズムのおすすめメニュー -->
<section class="mc-menu">
<header class="mc-menu__head">
<p class="mc-menu__eyebrow">TODAY'S PICK</p>
<h2 class="mc-menu__title">本日のおすすめ</h2>
</header>
<div class="mc-cards">
<!-- カード1 -->
<article class="mc-card" data-name="カフェラテ">
<span class="mc-card__emoji mc-card__emoji--latte">☕</span>
<h3 class="mc-card__name">月見カフェラテ</h3>
<p class="mc-card__desc">なめらかミルクと深煎り</p>
<div class="mc-card__foot">
<span class="mc-card__price">¥620</span>
<button class="mc-card__add" type="button" aria-label="カートに追加">+</button>
</div>
</article>
<!-- カード2 -->
<article class="mc-card" data-name="ドリップ">
<span class="mc-card__emoji mc-card__emoji--drip">🫖</span>
<h3 class="mc-card__name">本日のドリップ</h3>
<p class="mc-card__desc">エチオピア/華やかな酸</p>
<div class="mc-card__foot">
<span class="mc-card__price">¥540</span>
<button class="mc-card__add" type="button" aria-label="カートに追加">+</button>
</div>
</article>
<!-- カード3 -->
<article class="mc-card" data-name="スコーン">
<span class="mc-card__emoji mc-card__emoji--scone">🍪</span>
<h3 class="mc-card__name">焙煎スコーン</h3>
<p class="mc-card__desc">コーヒー香る自家製</p>
<div class="mc-card__foot">
<span class="mc-card__price">¥380</span>
<button class="mc-card__add" type="button" aria-label="カートに追加">+</button>
</div>
</article>
</div>
<p class="mc-cart" id="mcCart">カートは空です</p>
</section>
/* MOON BREW:ぷっくりクレイモーフィズムのメニュー */
:root {
--cream: #f5ede1;
--brown: #2b1d12;
--amber: #c98a3b;
--clay: #fbf3e7;
}
* { box-sizing: border-box; }
body {
margin: 0;
height: 400px;
display: grid;
place-items: center;
background: var(--cream);
font-family: "Hiragino Kaku Gothic ProN", "Segoe UI", system-ui, sans-serif;
color: var(--brown);
overflow: hidden;
}
.mc-menu {
width: min(540px, 94vw);
padding: 8px;
}
.mc-menu__head { text-align: center; margin-bottom: 16px; }
.mc-menu__eyebrow { margin: 0; font-size: 10px; letter-spacing: 0.3em; color: var(--amber); font-weight: 700; }
.mc-menu__title { margin: 4px 0 0; font-size: 20px; font-weight: 800; }
.mc-cards {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 14px;
}
/* クレイカード:内外の二重シャドウでぷっくり */
.mc-card {
padding: 16px 14px 14px;
border-radius: 26px;
background: var(--clay);
box-shadow:
8px 8px 18px rgba(43,29,18,0.14),
-6px -6px 14px rgba(255,255,255,0.9),
inset 4px 4px 8px rgba(255,255,255,0.7),
inset -5px -5px 10px rgba(201,138,59,0.14);
text-align: center;
transition: transform 0.28s cubic-bezier(0.34,1.4,0.64,1);
}
.mc-card:hover { transform: translateY(-4px); }
/* 絵文字を入れる丸いクレイバッジ */
.mc-card__emoji {
display: inline-grid;
place-items: center;
width: 50px; height: 50px;
border-radius: 50%;
font-size: 22px;
margin-bottom: 8px;
box-shadow:
inset 3px 3px 6px rgba(255,255,255,0.9),
inset -4px -4px 8px rgba(43,29,18,0.12),
4px 4px 10px rgba(43,29,18,0.1);
}
.mc-card__emoji--latte { background: #f3e3cf; }
.mc-card__emoji--drip { background: #ecd9c2; }
.mc-card__emoji--scone { background: #f6e8d3; }
.mc-card__name { margin: 0 0 3px; font-size: 13.5px; font-weight: 700; }
.mc-card__desc { margin: 0 0 12px; font-size: 10.5px; color: #8a7560; line-height: 1.5; }
.mc-card__foot { display: flex; align-items: center; justify-content: space-between; }
.mc-card__price { font-size: 14px; font-weight: 800; color: var(--amber); }
/* +ボタン:小さなぷっくりクレイ */
.mc-card__add {
width: 30px; height: 30px;
border: none;
border-radius: 50%;
font-size: 16px;
line-height: 1;
cursor: pointer;
color: #fff;
background: var(--amber);
box-shadow:
4px 4px 9px rgba(201,138,59,0.4),
-3px -3px 7px rgba(255,255,255,0.8),
inset 2px 2px 4px rgba(255,255,255,0.5),
inset -2px -2px 5px rgba(43,29,18,0.18);
transition: transform 0.18s ease;
}
.mc-card__add:hover { transform: scale(1.12); }
.mc-card__add:active { transform: scale(0.92); }
.mc-cart {
margin: 16px 0 0;
text-align: center;
font-size: 12px;
color: #8a7560;
min-height: 1em;
}
@media (prefers-reduced-motion: reduce) {
.mc-card, .mc-card__add { transition: none; }
}
// +ボタンで簡易カート(個数を数えて文章に反映)
const cart = document.getElementById("mcCart");
const adds = document.querySelectorAll(".mc-card__add");
let count = 0;
let lastName = "";
adds.forEach((btn) => {
btn.addEventListener("click", () => {
// 親カードから商品名を取得(null安全)
const card = btn.closest(".mc-card");
lastName = card?.dataset.name || "商品";
count += 1;
if (cart) cart.textContent = `カートに「${lastName}」を追加(合計 ${count} 点)`;
// ぷにっと弾むフィードバック
if (card) {
card.style.transform = "scale(0.96)";
setTimeout(() => { card.style.transform = ""; }, 160);
}
});
});
実装ガイド
使いどころ
親しみやすさを前面に出したいSNS系コンポーネント、子ども向け/カジュアルなアプリ、ウェルカムカードや空状態(エンプティステート)の通知カードに向きます。ぷっくりした質感で『触れたくなる』ボタンやアイコンを作れます。
実装時の注意点
クレイ感は『外側の落ち影+反対向きの淡い外側ハイライト+内側の二重 inset シャドウ(明と暗)』を一つの box-shadow に4層重ねて作るのが核心です。大きめの border-radius(30px前後)で角を丸め、cubic-bezier のオーバーシュート(1.56等)でぽよんとした弾みを付けると粘土らしさが増します。色味はパステル基調で、影は背景に馴染む彩度を選ぶと自然です。
対応ブラウザ
多層 box-shadow(inset 併用)と linear-gradient、transform/animation だけで成立し、backdrop-filter は不使用のため全モダンブラウザで安定して再現できます。プレフィックスや対応バージョンの懸念はありません。
よくある失敗
影を4層も重ねるため、明暗のバランスを誤ると膨らみ過ぎて安っぽく見えたり、逆に潰れて立体感が消えたりします。パステル背景にパステル文字でコントラスト不足(4.5:1割れ)になりやすく、要素が小さいと内側シャドウのぼかしが食い合って濁ります。落ち影を濃くしすぎると粘土ではなく古い影付きカードになります。
応用例
アイコンに pop アニメ(scale+rotate)を足してタップフィードバックを強める、prefers-reduced-motion でアニメを無効化する(本デモ対応済み)、グラデのアクセントボタンと組み合わせてプライマリ/セカンダリを差別化する、ダークなクレイ(暗い base+柔らかい inset)へ展開する、などが応用例です。
コード
<!-- クレイモーフィズム:ぷっくりした粘土風カード -->
<div class="clay-stage">
<article class="clay-card">
<!-- ぷにっとしたアイコン -->
<div class="clay-icon" id="clayIcon">
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 2l2.6 6.3L21 9l-5 4.3L17.5 20 12 16.5 6.5 20 8 13.3 3 9l6.4-.7z"/></svg>
</div>
<h2 class="clay-title">Claymorphism</h2>
<p class="clay-text">内側と外側の影でぷっくり膨らんだ粘土のような質感。やわらかなUIにぴったり。</p>
<div class="clay-actions">
<button class="clay-btn clay-btn--primary" id="clayLike" type="button">
<span class="clay-btn__emoji">♥</span> いいね <em id="clayCount">0</em>
</button>
<button class="clay-btn" type="button" id="clayShare">シェア</button>
</div>
</article>
</div>
/* クレイモーフィズム:外側の落ち影+内側の二重ハイライト影 */
:root {
--clay-bg: #f7d4e4;
--card: #fef3f8;
--accent: #ff5e8a;
--accent-2: #8b5cf6;
--ink: #5b4660;
/* ぷっくり感を生む内側シャドウのセット */
--clay-shadow:
8px 8px 16px rgba(176, 110, 145, 0.35),
-6px -6px 14px rgba(255, 255, 255, 0.9),
inset 6px 6px 12px rgba(255, 255, 255, 0.7),
inset -6px -6px 12px rgba(176, 110, 145, 0.18);
}
* { box-sizing: border-box; }
body {
margin: 0;
min-height: 360px;
display: grid;
place-items: center;
font-family: "Segoe UI", system-ui, -apple-system, sans-serif;
color: var(--ink);
background: radial-gradient(circle at 30% 20%, #ffe0ef, var(--clay-bg) 70%);
}
.clay-stage { padding: 16px; }
/* 粘土カード */
.clay-card {
width: min(310px, 84vw);
padding: 28px 26px 26px;
text-align: center;
border-radius: 34px;
background: var(--card);
box-shadow: var(--clay-shadow);
}
/* ぷにっとアイコン */
.clay-icon {
width: 70px; height: 70px;
margin: 0 auto 16px;
display: grid; place-items: center;
border-radius: 24px;
color: #fff;
background: linear-gradient(135deg, var(--accent), var(--accent-2));
box-shadow:
5px 5px 12px rgba(176, 110, 145, 0.4),
inset 3px 3px 7px rgba(255, 255, 255, 0.5),
inset -3px -3px 7px rgba(0, 0, 0, 0.12);
cursor: pointer;
transition: transform 0.25s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.clay-icon svg { width: 34px; height: 34px; fill: currentColor; }
.clay-icon:hover { transform: rotate(-8deg) scale(1.06); }
.clay-icon.is-pop { animation: pop 0.5s cubic-bezier(0.34, 1.56, 0.64, 1); }
@keyframes pop {
0% { transform: scale(1); }
50% { transform: scale(1.22) rotate(12deg); }
100% { transform: scale(1); }
}
.clay-title { margin: 0 0 8px; font-size: 22px; font-weight: 800; color: #6d4a63; }
.clay-text { margin: 0 0 22px; font-size: 13px; line-height: 1.7; color: #8a7384; }
.clay-actions { display: flex; gap: 12px; justify-content: center; }
/* 粘土ボタン */
.clay-btn {
font: inherit; font-weight: 700; font-size: 13.5px;
color: var(--ink);
border: none; cursor: pointer;
padding: 11px 18px;
border-radius: 18px;
background: var(--card);
box-shadow:
5px 5px 11px rgba(176, 110, 145, 0.32),
-4px -4px 10px rgba(255, 255, 255, 0.85),
inset 2px 2px 5px rgba(255, 255, 255, 0.6),
inset -2px -2px 5px rgba(176, 110, 145, 0.12);
transition: transform 0.14s ease, box-shadow 0.14s ease;
}
.clay-btn:active { transform: translateY(2px) scale(0.98); }
.clay-btn--primary {
color: #fff;
background: linear-gradient(135deg, var(--accent), #ff8fb0);
box-shadow:
5px 5px 12px rgba(255, 94, 138, 0.4),
inset 2px 2px 6px rgba(255, 255, 255, 0.5),
inset -2px -2px 6px rgba(0, 0, 0, 0.1);
}
.clay-btn__emoji { font-size: 14px; }
.clay-btn em { font-style: normal; font-weight: 800; }
@media (prefers-reduced-motion: reduce) {
.clay-icon { transition: none; }
.clay-icon.is-pop { animation: none; }
}
// いいねカウントとぷにっとポップ演出
const likeBtn = document.getElementById("clayLike");
const countEl = document.getElementById("clayCount");
const icon = document.getElementById("clayIcon");
const shareBtn = document.getElementById("clayShare");
let likes = 0;
// いいね:数を増やし、アイコンを弾ませる
likeBtn?.addEventListener("click", () => {
likes += 1;
if (countEl) countEl.textContent = String(likes);
popIcon();
});
// アイコン自体のクリックでも弾む
icon?.addEventListener("click", popIcon);
// アニメ用クラスを付け外し(連打にも対応)
function popIcon() {
if (!icon) return;
icon.classList.remove("is-pop");
// リフローを挟んでアニメを再起動
void icon.offsetWidth;
icon.classList.add("is-pop");
}
// シェア:簡易フィードバック
shareBtn?.addEventListener("click", () => {
const original = shareBtn.textContent;
shareBtn.textContent = "コピー済";
setTimeout(() => { shareBtn.textContent = original; }, 1200);
});
🤖 AIエージェント用プロンプト
あなたは熟練のフロントエンドエンジニアです。私のWebサイトに「クレイモーフィズム」の効果を追加してください。
# 追加してほしい効果
クレイモーフィズム(グラス / ニューモーフィズム)
内外の二重シャドウでぷっくり膨らんだ粘土風カード。やわらかく親しみやすいUIやSNS系コンポーネントに向きます。
# 追加する場所
👉【ここに対象箇所を記入:例「トップのヒーローセクション」「お問い合わせボタン」「記事カードの一覧」など】
# 参考実装(この見た目・挙動を再現してください)
【HTML】
<!-- クレイモーフィズム:ぷっくりした粘土風カード -->
<div class="clay-stage">
<article class="clay-card">
<!-- ぷにっとしたアイコン -->
<div class="clay-icon" id="clayIcon">
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 2l2.6 6.3L21 9l-5 4.3L17.5 20 12 16.5 6.5 20 8 13.3 3 9l6.4-.7z"/></svg>
</div>
<h2 class="clay-title">Claymorphism</h2>
<p class="clay-text">内側と外側の影でぷっくり膨らんだ粘土のような質感。やわらかなUIにぴったり。</p>
<div class="clay-actions">
<button class="clay-btn clay-btn--primary" id="clayLike" type="button">
<span class="clay-btn__emoji">♥</span> いいね <em id="clayCount">0</em>
</button>
<button class="clay-btn" type="button" id="clayShare">シェア</button>
</div>
</article>
</div>
【CSS】
/* クレイモーフィズム:外側の落ち影+内側の二重ハイライト影 */
:root {
--clay-bg: #f7d4e4;
--card: #fef3f8;
--accent: #ff5e8a;
--accent-2: #8b5cf6;
--ink: #5b4660;
/* ぷっくり感を生む内側シャドウのセット */
--clay-shadow:
8px 8px 16px rgba(176, 110, 145, 0.35),
-6px -6px 14px rgba(255, 255, 255, 0.9),
inset 6px 6px 12px rgba(255, 255, 255, 0.7),
inset -6px -6px 12px rgba(176, 110, 145, 0.18);
}
* { box-sizing: border-box; }
body {
margin: 0;
min-height: 360px;
display: grid;
place-items: center;
font-family: "Segoe UI", system-ui, -apple-system, sans-serif;
color: var(--ink);
background: radial-gradient(circle at 30% 20%, #ffe0ef, var(--clay-bg) 70%);
}
.clay-stage { padding: 16px; }
/* 粘土カード */
.clay-card {
width: min(310px, 84vw);
padding: 28px 26px 26px;
text-align: center;
border-radius: 34px;
background: var(--card);
box-shadow: var(--clay-shadow);
}
/* ぷにっとアイコン */
.clay-icon {
width: 70px; height: 70px;
margin: 0 auto 16px;
display: grid; place-items: center;
border-radius: 24px;
color: #fff;
background: linear-gradient(135deg, var(--accent), var(--accent-2));
box-shadow:
5px 5px 12px rgba(176, 110, 145, 0.4),
inset 3px 3px 7px rgba(255, 255, 255, 0.5),
inset -3px -3px 7px rgba(0, 0, 0, 0.12);
cursor: pointer;
transition: transform 0.25s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.clay-icon svg { width: 34px; height: 34px; fill: currentColor; }
.clay-icon:hover { transform: rotate(-8deg) scale(1.06); }
.clay-icon.is-pop { animation: pop 0.5s cubic-bezier(0.34, 1.56, 0.64, 1); }
@keyframes pop {
0% { transform: scale(1); }
50% { transform: scale(1.22) rotate(12deg); }
100% { transform: scale(1); }
}
.clay-title { margin: 0 0 8px; font-size: 22px; font-weight: 800; color: #6d4a63; }
.clay-text { margin: 0 0 22px; font-size: 13px; line-height: 1.7; color: #8a7384; }
.clay-actions { display: flex; gap: 12px; justify-content: center; }
/* 粘土ボタン */
.clay-btn {
font: inherit; font-weight: 700; font-size: 13.5px;
color: var(--ink);
border: none; cursor: pointer;
padding: 11px 18px;
border-radius: 18px;
background: var(--card);
box-shadow:
5px 5px 11px rgba(176, 110, 145, 0.32),
-4px -4px 10px rgba(255, 255, 255, 0.85),
inset 2px 2px 5px rgba(255, 255, 255, 0.6),
inset -2px -2px 5px rgba(176, 110, 145, 0.12);
transition: transform 0.14s ease, box-shadow 0.14s ease;
}
.clay-btn:active { transform: translateY(2px) scale(0.98); }
.clay-btn--primary {
color: #fff;
background: linear-gradient(135deg, var(--accent), #ff8fb0);
box-shadow:
5px 5px 12px rgba(255, 94, 138, 0.4),
inset 2px 2px 6px rgba(255, 255, 255, 0.5),
inset -2px -2px 6px rgba(0, 0, 0, 0.1);
}
.clay-btn__emoji { font-size: 14px; }
.clay-btn em { font-style: normal; font-weight: 800; }
@media (prefers-reduced-motion: reduce) {
.clay-icon { transition: none; }
.clay-icon.is-pop { animation: none; }
}
【JavaScript】
// いいねカウントとぷにっとポップ演出
const likeBtn = document.getElementById("clayLike");
const countEl = document.getElementById("clayCount");
const icon = document.getElementById("clayIcon");
const shareBtn = document.getElementById("clayShare");
let likes = 0;
// いいね:数を増やし、アイコンを弾ませる
likeBtn?.addEventListener("click", () => {
likes += 1;
if (countEl) countEl.textContent = String(likes);
popIcon();
});
// アイコン自体のクリックでも弾む
icon?.addEventListener("click", popIcon);
// アニメ用クラスを付け外し(連打にも対応)
function popIcon() {
if (!icon) return;
icon.classList.remove("is-pop");
// リフローを挟んでアニメを再起動
void icon.offsetWidth;
icon.classList.add("is-pop");
}
// シェア:簡易フィードバック
shareBtn?.addEventListener("click", () => {
const original = shareBtn.textContent;
shareBtn.textContent = "コピー済";
setTimeout(() => { shareBtn.textContent = original; }, 1200);
});
# 外部ライブラリ
なし(追加ライブラリ不要)
# 守ってほしいこと
- 既存のHTML構造・レイアウト・デザインを壊さないこと。必要に応じてクラス名・色・サイズを私のサイトに合わせて調整してよい。
- クラス名やidが既存と衝突しないよう、必要なら接頭辞で名前空間を分けること。
- レスポンシブ対応と prefers-reduced-motion への配慮を入れること。
- 私のサイトのフレームワーク(React / Vue / 素のHTML など)に合わせて実装すること。不明な場合は素のHTML/CSS/JSで提示し、組み込み手順も説明すること。
- 変更後の確認手順も簡潔に教えてください。