GODRICH

コラージュ デザインのLPパーツ9選、コピペOK

コラージュ デザインは、余白を取るのではなく色面・大きな活字・シールを重ねて貼り、画面を埋めていくスタイルです。このキットは写真ファイルを1枚も使わず、CSSの値だけで雑誌から切り抜いたような画面を作ります。

Pinterestで保存するのは簡単なのに、いざ自分で作ろうとすると手が止まります。要素が多いからではなく、重ね方のルールがないからです。まずは下のワンページをスクロールして、この画面で人の手で決めた値がいくつあるか数えてみてください。3つです。

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

そのページを組み立てている9つの部品を1つずつ取り出し、下のグリッドに並べました。順番は人気順ではなく、コラージュを実際に作るときの手順です。写真フレームを敷き、目次を載せ、切り抜きを並べ、スタンプを押し、帯を巻き、下線を引き、カードを重ね、端をくり抜き、最後に署名を入れます。

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

01重なるフレームのヒーロー

グラデーションで埋めた写真フレーム3枚がそれぞれ違う位相で揺れ、その上に貼った見出しカードだけが浮き上がります。前後の層が同じ向きに動くと、重なりが1枚の平面に潰れて見えます。

z-index 겹침반대 위상radius 4
.hcol__frame {
  border: 6px solid #fff;            // 白い余白が写真の枠の役割をする
  animation-name: frameSway;
  animation-duration: 2s;
  animation-iteration-count: infinite;
}
.hcol__frame--sky  { --rot: 8deg;  animation-delay: -.7s; }
.hcol__frame--lime { --rot: -5deg; animation-delay: -1.4s; }

@keyframes frameSway {
  0%, 100% { transform: translateY(0) rotate(var(--rot)); }
  50%      { transform: translateY(8px) rotate(calc(var(--rot) + 5deg)); }
}

02雑誌の目次風ナビ

メニューごとに2桁のページ番号を付けるだけで、バーが雑誌の目次になります。レモン色のチップは各マスで少し止まってから次へ跳びますが、この止まる区間がないとどのタブが選ばれているのか読み取れません。

고정 폭 탭쪽번호 세리프radius 4
.ncol { --tab: 68px; --step: 72px; }   // 実測: タブ68px + 間隔4px
.ncol__tab  { flex: 0 0 var(--tab); }  // 均等配分にすると移動量とレンダー幅がずれる

@keyframes chipHop {
  0%, 10%      { transform: translateX(0) rotate(-3deg); }
  13.3%        { transform: translateX(calc(var(--step) * .5)) translateY(-11px) rotate(5deg); }
  16.6%, 26.6% { transform: translateX(var(--step)) rotate(-3deg); }
  50%, 60%     { transform: translateX(calc(var(--step) * 3)) rotate(-3deg); }
  100%         { transform: translateX(0) rotate(-3deg); }
}

03切り抜きフレームのカードグリッド

3枚がそれぞれ、貼られた角度から0度まで戻っては、また傾きます。0.24秒ずつずらすことで、1つの塊ではなく別々に貼った切り抜きとして読めるようになります。

시차 0.24s각도 복원radius 4
.ccol__card--coral { --rot: -7deg; }
.ccol__card--sky   { --rot: 5deg;  animation-delay: -.24s; }
.ccol__card--grape { --rot: -4deg; animation-delay: -.48s; }

@keyframes cardStraighten {
  0%, 100% { transform: rotate(var(--rot)); box-shadow: 0 5px 0 rgba(36, 29, 46, .16); }
  45%      { transform: rotate(0deg) translateY(-8px); box-shadow: 0 13px 0 rgba(36, 29, 46, .12); }
}

04回転スタンプバッジ

破線の枠が1本あるだけで、円がゴム印になります。0.55倍まで潰れて1.16倍まで跳ね返りますが、傾きを保つにはtransformの値の中で毎回rotateを書き直す必要があります。

scale 0.55→1.16점선 테두리radius 50%
.scol__badge--lemon { --rot: -12deg; background: #ffd93d; }
.scol__badge--lime  { --rot: 8deg;   animation-delay: -.5s; }

@keyframes stampPress {
  0%, 55%, 100% { transform: rotate(var(--rot)) scale(1); }
  8%            { transform: rotate(var(--rot)) scale(.55); }
  20%           { transform: rotate(var(--rot)) scale(1.16); }
  32%           { transform: rotate(var(--rot)) scale(1); }
}

05マーキーの文字帯

同じ語のまとまりを2組つなげ、1組分の幅だけ動かすと、一周し終えた瞬間が最初のフレームとピクセル単位で一致します。上下の帯を逆向きに流すと、2行が互いに押し合っているように見えます。

두 벌 복제margin-right 간격translateX(-50%)
.mcol__track {
  display: flex;
  width: max-content;
  animation-name: stripFlow;
  animation-duration: 2s;
  animation-timing-function: linear;
  animation-iteration-count: infinite;
}
.mcol__track--back { animation-name: stripFlowBack; }
.mcol__bit { margin-right: 24px; }     // gapで与えると-50%がずれる

@keyframes stripFlow { from { transform: translateX(0); } to { transform: translateX(-50%); } }

06手書き下線のレビュー

stroke-dashoffsetを正の値から0へ、さらに負の値へと動かすと、1本のSVGパスが左から引かれ、左から消えていきます。逆戻りする区間がないので、ループの切れ目が目に付きません。

stroke-dashoffsetSVG pathradius 4
.tcol__line {
  fill: none;
  stroke: #d93a1e;
  stroke-width: 4;
  stroke-linecap: round;
  stroke-dasharray: 230;               // 実測したパス長より余裕を持たせる
  animation-name: inkDraw;
  animation-duration: 2s;
  animation-iteration-count: infinite;
}
@keyframes inkDraw {
  0%   { stroke-dashoffset: 230; }
  45%  { stroke-dashoffset: 0; }
  70%  { stroke-dashoffset: 0; }
  100% { stroke-dashoffset: -230; }
}

07重なる料金レイヤー

負のmarginでカード2枚を重ね、z-indexで重なり順を決めます。手前のカードが浮くときに影の厚みが5pxから17pxへ伸びないと、重なりが層として読めません。

음수 margin 겹침그림자 확장radius 4
.pcol__plan--base { z-index: 1; transform: rotate(-3deg); }
.pcol__plan--pick {
  z-index: 2;
  margin-left: -20px;                  // 手前のカードが奥のカードの角を覆う
  margin-bottom: 16px;
}
@keyframes planLift {
  0%, 100% { transform: rotate(2deg) translateY(0);     box-shadow: 0 5px 0 rgba(36, 29, 46, .16); }
  50%      { transform: rotate(2deg) translateY(-12px); box-shadow: 0 17px 0 rgba(36, 29, 46, .12); }
}

08スタンプCTA帯

帯の下端をマスク2枚で半円にくり抜きます。円のどちら側を残すかで結果が変わります。ボタンはスタンプのように傾きながら沈み、沈んでいく間に影の厚みも14pxから2pxへ薄くなります。

radial-gradient 마스크그림자=두께radius 4
.bcol {
  mask:
    radial-gradient(circle 8px at 50% 0, #000 98%, #0000 100%) 0 100% / 16px 8px repeat-x,
    linear-gradient(#000 0 0) 0 0 / 100% calc(100% - 8px) no-repeat;
}
@keyframes stampPush {
  0%, 100% { transform: translateY(-6px) rotate(-2deg); box-shadow: 0 14px 0 rgba(36, 29, 46, .35); }
  50%      { transform: translateY(0) rotate(1.5deg);   box-shadow: 0 2px 0 rgba(36, 29, 46, .35); }
}

09コラージュのフッター

大きなセリフ体の語をあえて見切れるように敷くと、文字ではなく面として読まれます。手前の紙片4つは0.5秒ずつずれて漂い、上がるときに傾きの符号が反転してめくれる紙のように見えます。

배경 워드마크시차 0.5sradius 4
.fcol__word {
  position: absolute;
  left: -12px; bottom: -16px;
  color: rgba(36, 29, 46, .1);         // 10%なら見出しではなく面として読まれる
  font-size: 62px;
  white-space: nowrap;
}
@keyframes chipBob {
  0%, 100% { transform: translateY(0) rotate(var(--rot)); }
  50%      { transform: translateY(-9px) rotate(calc(var(--rot) * -1)); }
}

tailwind.config カスタム

このスタイルで一箇所にまとめるべき値は色ではなく角度です。要素ごとに気分で角度を決めると、重なりが意図ではなく事故に見えます。そこで角度をユーティリティ名に変え、4つだけ残します。

theme: {
  extend: {
    colors: {
      cream: "#fbf3e4", sheet: "#ffffff", ink: "#241d2e", slate: "#57506a",
      coral: "#d93a1e", sky: "#2d6fb5", grape: "#6b3fa0",
      lemon: "#ffd93d", lime: "#b6e34f", blush: "#ffb3c7",
    },
    borderRadius: { chip: "4px", control: "12px", card: "16px", pill: "999px" },
    boxShadow: {
      paste: "0 5px 0 rgba(36,29,46,.16)",   // 面に付いている状態 = 厚み
      stamp: "0 4px 0 rgba(36,29,46,.2)",
      lift:  "0 16px 0 rgba(36,29,46,.12)",  // 持ち上げたときだけ
    },
    rotate: { a: "-3deg", b: "2deg", c: "-1.5deg", d: "5deg" },
  },
},
役割 トークン いつ
貼った角度 rotate-arotate-d フレーム・カード・バッジ・帯のすべて
付いている厚み shadow-paste 面に置かれている状態
持ち上げ shadow-lift 浮いている瞬間だけ

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

設定を入れておけば、AIエディタに渡す指示は次のひとかたまりで足ります。色のリストより角度のリストを先に置く、この順番が大事です。省略していない原文はzipの中のprompt.mdに入っています。

角度は4つだけ使う: -3deg, 2deg, -1.5deg, 5deg。このリスト以外の角度を作らない。
面に付いている要素の影はぼかし0の 0 5px 0 rgba(36,29,46,.16)、持ち上げるときだけ
0 16px 0 に厚くする。背景は cream(#fbf3e4) の1トーン、面は sheet(#ffffff) の1トーン。
白い文字は coral・sky・grape の上にだけ置き、lemon・lime・blush の上には ink の文字だけを置く。
写真は使わない。写真の位置は2色の linear-gradient と 6px の白い枠で代わりにする。

この指示で生成したpage/index.htmlを1280pxのビューポートに表示し、ページ全体を1枚で撮ったものが下の画像です。

結果

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

いちばん時間がかかったのはCTA帯の端でした。下端を波形にくり抜こうとradial-gradientのマスクを敷いたのですが、最初に書いたcircle 8px at 50% 0, #0000 98%, #000 100%は円の外側を残す書き方で、画面には下向きの鋭い三角がずらりとぶら下がりました。ポスターを開いて初めて気づきました。波ではなく歯でした。色の順番を入れ替えて#000 98%, #0000 100%にし、円の内側を残すようにすると、ようやく半円が下にぶら下がりました。マスクは「何を消すか」ではなく「何を残すか」で読むべきものです。実際のマスクは2枚重ねで、下端の8px分を半円のタイルが、それより上をlinear-gradient(#000 0 0)のべた塗りが受け持ちます。べた塗りの1枚を書き忘れると、帯は下端の8pxだけを残して消えます。半円の半径は変数1つにまとめてあるので、タイルの幅16pxも帯の下の余白も同じ値から決まります。

2つ目はマーキーの帯でした。上下の帯をそれぞれ-3度と2.5度傾け、負のmargin-topで重ねたところ、レンダリングした画面では下の帯が上の帯の文字の下端をそのまま覆っていました。回転した要素が占める高さは回転前の高さより大きいので、回転前の値で計算した重なり量は、そのままでは成立しません。下の帯を88%幅に縮めて右に寄せ、帯の端どうしだけが重なるようにすると2行とも読めるようになりました。直したあとの角度は上の帯が-2.5度、下の帯が2度で、右に寄せるのはmargin-left: autoの1行です。ついでにトラック幅もPlaywrightのoffsetWidthで測り直しています。回転した要素ではgetBoundingClientRectが回転後の矩形を返すため、この計算には使えません。語の間隔もgapではなく1つずつのmargin-rightで与えています。gapは2N個の要素に対して2N-1個しか入らないので、2組の幅がちょうど半分という前提が崩れるからです。上の帯は796pxに対して1組が398px、下の帯は524pxに対して262pxと、どちらもちょうど半分なのでtranslateX(-50%)の一周で継ぎ目は0pxです。2つの落とし穴を直したファイルは、圧縮パスワード s3yjtjja で開くzipにそのまま入っています。

アクセシビリティ

色が増えるほど、コントラストを目分量で判断できなくなります。WCAG 2.1 の最低コントラスト基準の相対輝度の式で10色すべてを計算し、表にまとめました。本文の基準は4.5:1です。

クリーム地の上 白い面の上 インクの文字を載せると
インク #241d2e 14.76:1 16.28:1
スレート #57506a 6.90:1 7.61:1
コーラル #d93a1e 4.16:1 4.59:1 3.55:1
スカイ #2d6fb5 4.70:1 5.18:1 3.14:1
グレープ #6b3fa0 6.70:1 7.38:1 2.20:1
レモン #ffd93d 1.25:1 1.38:1 11.82:1
ライム #b6e34f 1.35:1 1.49:1 10.92:1
ブラッシュ #ffb3c7 1.52:1 1.68:1 9.71:1

ここから2つのルールが導けます。コーラルの文字は白い面の上では4.59:1で基準を満たしますが、クリーム地の上では4.16:1なので本文には使えません。そのため9個の部品のコーラルの文字はすべて白いカードの中にあります。逆にレモン・ライム・ブラッシュはどの地の上でも文字にできない代わり、インクの文字を載せれば9:1を超えるので、バッジや帯のとしてだけ使っています。

動きの面では、MDN の prefers-reduced-motion のページのメディアクエリを9個すべてに入れました。動きを減らす設定を有効にすると揺れと流れは止まりますが、貼った角度はそのまま残ります。MDN の transform のページrotateで作った傾きはこのスタイルそのものなので、角度まで0に戻すと落ち着いた画面ではなく別のデザインになってしまうからです。

同じ明るいトーンのもう一つの作り方はペーパーカット デザインのLPパーツにまとめてあります。このサイトが何を配っているのかは紹介ページをご覧ください。

FAQ

1画面に6色も使うと、ごちゃごちゃしませんか

ごちゃごちゃして見えるのは、色数のせいではなく役割が重なったときです。このキットではコーラル・スカイ・グレープが文字を載せる面、レモン・ライム・ブラッシュが文字を載せない装飾面です。役割が分かれていれば、6色あっても目は2つのグループとして読みます。

なぜ角度を4つに絞るのですか

傾きは値ではなくリストだからです。要素ごとに-2度、-7度、3度とばらばらに与えると、見る人はそれを「わざと傾けた」ではなく「揃っていない」と読みます。4つを回して使うと、同じ手が貼ったように見えます。

写真なしのフレームは寂しく見えませんか

枠の中を空けたままなら寂しく見えますが、2色のグラデーションで埋めて6pxの白い枠で囲むと、額の中に何かが入っているものとして読まれます。後から実際の写真を入れるときもbackgroundを差し替えるだけなので、素材の到着を待たずにレイアウトを確認できます。

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

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