GODRICH

スキューモーフィズムデザインの質感パーツ9選

スキューモーフィズムデザインは、革・金属・木目・ガラスといった実物の質感を画面に持ち込むスタイルです。革・金属・木目をCSSの値だけで作り、テクスチャ写真を1枚も使わずに、2024年以降の製品サイトに少しずつ戻ってきた「選択的な質感」を貼って使える部品9つにまとめました。

2010年代前半、このスタイルは画面全体を革とリネンで包み込み、その重さへの疲れがフラットデザインを生みました。今戻ってきた質感は違います。明るくフラットな画面に、本物の材料をわずか3か所だけ置いて、手が覚えている手触りをアクセントに使うやり方です。まず下のワンページをスクロールして、質感がどこに座っているか探してみてください。

ページを新しいタブで開く

あのページを構成する部品9つを1つずつ取り出して、下のグリッドに並べました。順番は人気順ではなく、材料が重みを持つ順です。革を縫い、金属を回し、紙を重ね、ノブを触り、ガラスを嵌め、木を開け、ステッカーを貼り、キーを押す。最後の9つ目は、これらの材料を1ページに過不足なく配置する方法です。

自動再生 · タイルを押すとその項目へ · すべて1つのzip

01レザーのステッチ料金カード

レザーカードが20px上から着地した瞬間、明るいステッチ目盛が二重枠の中に1フレームのカットで刻まれます。ステッチは画像ではなく、4辺それぞれにrepeating-linear-gradientの目盛を巻いたものなので、背景色を変えても作り直す必要がありません。

이중 테두리repeating-linear-gradientsteps(1, end)
.leather__stitch {
  position: absolute;
  top: 8px; left: 8px; right: 8px; bottom: 8px;
  border-radius: $r-control;
  opacity: 0;
  background:
    repeating-linear-gradient(90deg, $stitch 0 8px, transparent 8px 16px) top    / 100% 2px no-repeat,
    repeating-linear-gradient(90deg, $stitch 0 8px, transparent 8px 16px) bottom / 100% 2px no-repeat,
    repeating-linear-gradient(0deg,  $stitch 0 8px, transparent 8px 16px) left   / 2px 100% no-repeat,
    repeating-linear-gradient(0deg,  $stitch 0 8px, transparent 8px 16px) right  / 2px 100% no-repeat;
  animation: stitchCut $duration steps(1, end) infinite;
}
@keyframes stitchCut {
  0%, 36%  { opacity: 0; }
  38%, 86% { opacity: 1; }
  88%, 100% { opacity: 0; }
}

02メタルダイヤルCTA

ダイヤルが左右32度ずつ回ると、conic-gradientの陰影が面を流れて、削り出した金属のように見えます。要素は本物のボタン要素で、円盤そのものがコンバージョンを取る操作になっています。

conic-gradient노치 테두리왕복 회전
.metaldial__dial {
  animation: dialSwing $duration $ease-spring infinite;
}
.metaldial__face {
  background:
    conic-gradient(from 210deg,
      $metal-hi 0deg, $metal-lo 70deg, $metal-mid 120deg,
      $metal-hi 180deg, $metal-edge 250deg, $metal-mid 300deg, $metal-hi 360deg);
  box-shadow: inset 0 2px 3px rgba(255, 255, 255, .65), inset 0 -3px 5px rgba(0, 0, 0, .4);
}
@keyframes dialSwing {
  0%, 6%    { transform: rotate(-32deg); }
  48%, 56%  { transform: rotate(32deg); }
  94%, 100% { transform: rotate(-32deg); }
}

03紙目の機能カード

目の入った紙3枚が重なり、一番上の紙が48pxだけ上へ滑って、下の紙の目を現します。目は方向の異なる1pxのrepeating-linear-gradient3層なので、ノイズ画像もbase64も不要です。

1px 결 겹침translateY 시트radius 16
.paperstack__sheet {
  background:
    repeating-linear-gradient(0deg,  $grain-a 0 1px, transparent 1px 3px),
    repeating-linear-gradient(90deg, $grain-b 0 1px, transparent 1px 4px),
    repeating-linear-gradient(48deg, $grain-c 0 1px, transparent 1px 7px),
    $paper-face;
}
@keyframes sheetSlide {
  0%, 10%   { transform: translateY(0); }
  46%, 58%  { transform: translateY(-48px); }
  88%, 100% { transform: translateY(0); }
}

04ボリュームノブ

ノブが目盛りの最小から最大まで左右120度ずつ回り、明るい指針線が目盛りの上を通っていきます。回転を円の内側だけで完結させているので、角度が進んでもノブが大きく見えることはありません。

rotate 왕복지침 선radius 50%
.volknob__knob {
  background:
    radial-gradient(120% 120% at 34% 26%, rgba(255, 255, 255, .32), transparent 42%),
    conic-gradient(from 250deg, $knob-face, $knob-body 90deg, $knob-face 170deg,
      $knob-body 260deg, $knob-face 340deg);
  box-shadow: 0 6px 10px rgba(23, 20, 26, .35), inset 0 1px 2px rgba(255, 255, 255, .22);
  animation: knobSweep $duration $ease-out infinite;
}
@keyframes knobSweep {
  0%, 8%    { transform: rotate(-120deg); }
  46%, 56%  { transform: rotate(120deg); }
  92%, 100% { transform: rotate(-120deg); }
}

05ガラスインレイバッジ

ブラシメタルの板に彫った窪みにガラスバッジが嵌っており、斜めのハイライト帯が左から右へ撫でていきます。帯が中心を通る瞬間にガラスの中のコアが一度だけ明るくなるところまで含めて、光がガラスを透過する感覚を作ります。

하이라이트 훑기translateX 광선inset 깊이
.glassbadge__sheen {
  position: absolute;
  top: -20%; left: 0;
  width: 44%;
  height: 140%;
  transform: translateX(-140%) rotate(24deg);
  background: linear-gradient(100deg, transparent, rgba(255, 255, 255, .4) 45%,
    rgba(255, 255, 255, .55) 50%, rgba(255, 255, 255, .4) 55%, transparent);
  animation: sheenSweep $duration $ease-out infinite;
}
@keyframes flareUp {
  0%, 36%   { opacity: 0; }
  44%, 50%  { opacity: 1; }
  58%, 100% { opacity: 0; }
}

06木目の引き違いパネル

木目のパネル2枚が左右に開いて内側の明るいスロットを現し、しばらく開いたままになってからまた閉じます。目はパネル自身に塗ってあるので、パネルが動けば目も一緒に流れます。木の写真と同じ効果を、重さなしで得られます。

두 짝 분할나무 결 gradient대칭 이동
.wooddoors__leaf {
  background:
    radial-gradient(ellipse 14px 22px at 62% 30%, rgba(74, 44, 12, .55) 0 38%,
      rgba($wood-c, .5) 42% 52%, transparent 60%),
    repeating-linear-gradient(90deg,
      $wood-a 0 12px, $wood-b 12px 15px, $wood-c 15px 27px, $wood-d 27px 30px,
      $wood-a 30px 38px, $wood-lo 38px 41px);
}
@keyframes doorsOpenL {
  0%, 10%   { transform: translateX(0); }
  42%, 60%  { transform: translateX(-92%); }
  88%, 100% { transform: translateX(0); }
}

07ステッカーエンボスロゴ

エンボスロゴのステッカーが24px上から傾いたまま降りて、マイナス3度の位置に収まります。彫刻はtext-shadow4層です。下に明るい光1px、上に暗い影1px、左右の補正2px — この4つが揃って初めて、印刷ではなく彫った文字に見えます。

text-shadow 4겹스탬프 착지radius 16
.emboss__brand {
  color: $emboss-ink;
  text-shadow:
    0 1px 0 $emboss-light,
    0 -1px 0 $emboss-dark,
    1px 0 0 rgba(255, 255, 255, .55),
    -1px 0 0 rgba(96, 74, 48, .35);
}
@keyframes stickerApply {
  0%        { transform: translateY(-24px) rotate(-8deg) scale(1.12); }
  40%       { transform: translateY(0) rotate(-3deg) scale(1); }
  50%       { transform: translateY(-2px) rotate(-3.6deg) scale(1.01); }
  60%, 88%  { transform: translateY(0) rotate(-3deg) scale(1); }
  100%      { transform: translateY(-24px) rotate(-8deg) scale(1.12); }
}

08物理的に沈むボタン

キーキャップが8px沈む間、下の側壁要素がscaleYで4分の1に縮みます。側壁をbox-shadowで描かず独立した要素にしたのは、押し込みの動きを影ではなく変換で処理するためです。

옆벽 scaleY8px 스트로크radius 12
.physkey__wall {
  height: 8px;
  transform-origin: 50% 0;
  animation: wallPress $duration $ease-spring infinite;
}
@keyframes capPress {
  0%, 12%   { transform: translateY(0); }
  32%, 46%  { transform: translateY(8px); }
  62%       { transform: translateY(-3px); }
  76%, 100% { transform: translateY(0); }
}
@keyframes wallPress {
  0%, 12%   { transform: scaleY(1); }
  32%, 46%  { transform: scaleY(.25); }
  62%       { transform: scaleY(1.1); }
  76%, 100% { transform: scaleY(1); }
}

09質感3か所だけのLP

ミニLP全体が上下に行ったり来たりしながら各セクションを通ります。質感は木目ナビ・メタルダイヤル・レザー料金カードの3か所だけで、残りは明るいフラットです。トラックをビューポート高さのちょうど2倍にしてtranslateY(-50%)が1画面分だけ動くようにするのが、このプレビューの骨組みです。

질감 3곳핑퐁 스크롤translateY 프리뷰
.minipage__track {
  display: flex;
  flex-direction: column;
  height: 200%;
  animation: pageScroll $duration $ease-out infinite;
}
@keyframes pageScroll {
  0%, 10%   { transform: translateY(0); }
  44%, 54%  { transform: translateY(-50%); }
  88%, 100% { transform: translateY(0); }
}

tailwind.config カスタム

このスタイルで値を1か所にまとめるべき理由は色ではなく押し込みの厚みです。物理キーは静止時に側壁8px、底付きで2px — この2つの値がずれると、ボタンが浮いて見えたり奥に嵌まりすぎたりします。

theme: {
  extend: {
    colors: {
      paper: "#fbf6ec", sheet: "#ffffff", ink: "#2a2320", stone: "#5c5048",
      brand: "#2f6df6", branddeep: "#1c48b8", mint: "#2f9e74",
      leather: "#7a4a2b", leatherdeep: "#5e3517", wood: "#a96f38",
    },
    borderRadius: { card: "16px", control: "12px", chip: "4px", pill: "999px" },
    boxShadow: {
      keyrest: "inset 0 2px 0 rgba(255,255,255,.4), inset 0 -2px 0 rgba(0,0,0,.25), 0 8px 0 #1a3fa0",
      keydown: "inset 0 2px 0 rgba(255,255,255,.4), inset 0 -2px 0 rgba(0,0,0,.25), 0 2px 0 #1a3fa0",
    },
  },
},
役割 トークン いつ
キー側壁 shadow-keyrest ボタンが静止しているとき(8px)
押された壁 shadow-keydown active: のときだけ(2px)
質感面 tex-leather など 1ページ最大3か所

バイブコーディング プロンプト

設定を置いたあと、Claude CodeやCursorに渡す指示は次のひとかたまりで足ります。色のリストより質感をどこに置くかが先に来る順番が大事です。切り詰める前の原文全文は、zipの中のprompt.mdに収めてあります。

質感は正確に3か所だけに置く。ナビ(木目)・CTA(メタルダイヤル)・おすすめ料金プラン(革)。
質感のない面積は質感のある面積の2倍以上にする。木目は縦方向のrepeating-linear-gradient、
金属ダイヤルは4区切りのconic-gradient、革は2方向のrepeating重ねに上部ハイライト。
ステッチ目盛は4辺それぞれに8pxの糸/8pxの間隔のrepeating-linear-gradientを巻く。
ボタンは静止時の側壁8px、押下時2px — 壁が減った分だけtranslateYで沈む。

この指示どおりにpage/index.htmlを作り、1280pxのビューポートで全体を撮ったのが下の図です。

結果

どこで壊れるか — 落とし穴

一番長く粘ったのは木の上の文字でした。ナビに白いブランド名を直接置いたところ、木目の帯が4色あるため帯ごとにコントラストが変わりました。相対輝度で直接計算すると、同じ白い文字が暗い帯(#96622e)では5.14:1、明るい帯(#c08a4e)では3.01:1まで落ちます。どの1色でも4帯すべてを4.5:1以上にできないので、文字は濃いインレイチップの上に移し、木目は装飾として残しました。質感の上の本文は、測ってから座らせるのが原則です。

2つ目は紙の移動距離でした。一番上の紙を高さの72パーセントだけ上げると、480pxでは問題ないのに320pxで紙の上端がステージからはみ出して切れました。移動距離を48pxのピクセル値に変え、狭い画面ではさらに20pxまで下げて、両方の幅で紙全体が見えるようにしました。9つの完成ファイルは、圧縮パスワード 7dcfwy5m で開くzipにそのまま入っています。

アクセシビリティ

質感はコントラストを壊します。WCAG 2.1の最低コントラスト基準の相対輝度の式で、このキットの文字の組み合わせを全部直接計算して表に残しました。

文字の組み合わせ 比率 判定
革上の本文 #f6e7cf / 革 #7a4a2b 6.07:1 合格
革上の料金 #ffffff / 革 #7a4a2b 7.39:1 合格
紙の本文 #574a38 / 紙 #fff7e6 8.07:1 合格
紙の補助 #7a6c56 / 紙 #fff7e6 4.80:1 合格(際どい)
ヒーローボタン #ffffff / ブランド色 #2f6df6 4.53:1 合格(際どい)
明るい革の目の上の本文 #f6e7cf / #96613c 4.24:1 不合格 — 明るい目の上に本文は置かない

最後の行が、革カードの文字を暗い目の側にだけ座らせた理由です。ミントコアの上の白いアイコン案(1.86:1)も、濃い青緑のアイコン色に差し替えました。9つすべての動きにMDNのprefers-reduced-motionのメディアクエリを入れ、動作を減らす設定の訪問者には質感が座った静止状態だけを見せます。質感そのものはMDNのconic-gradientMDNのtext-shadowの値なので、未対応のブラウザでも最悪でも単色の面に落ちるだけで、レイアウトは崩れません。

ほかのスタイルの流行はデザイントレンドのカテゴリーで、このサイトが何を配っているのかは紹介ページにまとめてあります。

FAQ

質感は何か所まで置いていいですか?

1ページに3か所までです。このキットでも木目ナビ・メタルダイヤル・レザー料金カードの3か所だけに質感を置き、残りは明るいフラットにしました。4か所を超えると目が休まる場所が消えて、2010年代の重い画面に戻ってしまいます。

2010年代のように画面全体を革で包んでもいいですか?

カード1枚なら可能ですが、LP全体にはおすすめしません。背景が暗くなる分だけどこでもコントラストを測り直す必要があり、一番明るい木目帯の上では、4.5:1の本文はそもそも置けません。質感はポイントであるときに価値になり、背景になるとコストになります。

Reactプロジェクトにそのまま貼れますか?

zipには9つの部品のReact版(.tsx + .module.scss)が同梱されています。時間・イージング・代表色はpropsで受け取るので、貼ったあとは値を変えるだけで使えます。バニラ版とReact版は同じ測定値で一緒に検証してあります。

解凍パスワードを入力してください

パスワードはこの記事の本文の中にあります。読み進めると出てきます。