GODRICH

キネティックタイポグラフィをコードで分解してみた

キネティックタイポグラフィとは、見出しの文字サイズが画面幅に合わせて変わり、単語が順番に浮かび上がり、数字がオドメーターのように上がっていくデザイン手法のことです。最近のランディングページはどれもファーストビューがこれなので、実際にコードを分解して9つのパーツに切り分けてみました。

まずは9つの部品をそのままつないだ一枚のランディングページを、上から下までスクロールしてみてください。見出しが単語ごとに浮き上がる様子、カードの数字が実際の値まで駆け上がる様子、いちばん下のワードマークを光が一度だけ斜めに横切る様子が見どころです。

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

下の格子にある9つは、上の画面から切り出した同じ部品です。並び順は、訪問者が実際のランディングページをたどる流れ(最初に目が止まる場所、機能をざっと見る場所、価格を確かめる場所、信頼できるか判断する場所、行動を後押しされる場所、最後にたどり着くフッター)のとおりにしてあります。

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

01ヒーロー

見出しの3つの単語が、隠れた枠の中から順番に下から上へ現れます。文字サイズ自体もclamp()で画面幅に合わせて自動的に大きくも小さくもなるため、狭い画面でもはみ出しません。

clamp() 가변폭단어 단위 staggeroverflow: hidden 마스크
<section class="flex flex-col items-center gap-6 py-24 text-center">
  <p class="text-xs font-bold uppercase tracking-[0.2em] text-accent">
    KINETIC TYPE
  </p>
  <h1 class="font-display text-6xl font-extrabold leading-[1.02]
             sm:text-7xl md:text-8xl">
    生각의 속도로<br>만든다
  </h1>
  <button class="rounded-pill bg-ink px-8 py-4 text-base font-bold text-cream">
    今すぐ始める
  </button>
</section>

02ナビゲーション

ナビ左側のワードマークが、放っておいても勝手に縮んだり戻ったりを繰り返します。実際のスクロールと連動しているわけではなく、スクロールで縮む一般的なstickyヘッダーの見た目をループのデモで先に見せているだけで、変わるのは大きさだけ、字間は動きません。

transform-origin: left centerletter-spacing 보간sticky 헤더
<header class="sticky top-0 z-20 px-6 pt-6">
  <nav class="mx-auto flex max-w-5xl items-center justify-between
              rounded-pill bg-ink px-6 py-3 shadow-bento">
    <span class="font-display text-xl font-extrabold text-cream">MOTIF</span>
    <div class="hidden items-center gap-8 sm:flex">
      <span class="text-sm font-semibold text-cream/70">概要</span>
      <span class="text-sm font-semibold text-cream/70">機能</span>
      <span class="text-sm font-semibold text-cream/70">料金</span>
    </div>
    <button class="rounded-pill bg-accent px-5 py-2 text-sm font-bold text-cream">
      始める
    </button>
  </nav>
</header>

03カードグリッド

カードの中の数字が0から実際の値(248)まで、桁をそろえたまま駆け上がります。counter()で描いた数字はスクリーンリーダーが読み上げられないため、上がりきった最終値(「プロジェクト248件」)を見た目だけ隠したテキストとして別に用意してあります。

@property 숫자 보간counter-resettabular-nums
<section class="py-14">
  <h2 class="mb-8 font-display text-3xl font-extrabold">数字で見る実績</h2>
  <div class="grid grid-cols-1 gap-4 sm:grid-cols-3">
    <div class="rounded-tile bg-ink p-8 text-center shadow-bento">
      <p class="font-display text-6xl font-extrabold tabular-nums text-cream">
        248
      </p>
      <p class="mt-2 text-sm font-semibold text-cream/70">プロジェクト</p>
    </div>
    <div class="rounded-tile bg-ink p-8 text-center shadow-bento">
      <p class="font-display text-6xl font-extrabold tabular-nums text-cream">
        99.9%
      </p>
      <p class="mt-2 text-sm font-semibold text-cream/70">稼働率</p>
    </div>
  </div>
</section>

04機能一覧

3行のリストが上から順に右へわずかに寄っては戻り、下の下線も同じ拍子で伸びては消えます。左側の大きな番号はコードエディターの行番号のような装飾で、実際の機能名は常に文字として隣にあるため番号だけでは意味が途切れません。

grid 번호 정렬호버 translateX@keyframes underline-grow
<ul class="divide-y divide-line rounded-tile bg-white shadow-bento">
  <li class="grid grid-cols-[auto_1fr] items-baseline gap-6 p-6">
    <span class="font-display text-3xl font-extrabold text-accent
                 tabular-nums">01</span>
    <span class="text-lg font-bold">リアルタイム共同編集</span>
  </li>
  <li class="grid grid-cols-[auto_1fr] items-baseline gap-6 p-6">
    <span class="font-display text-3xl font-extrabold text-accent
                 tabular-nums">02</span>
    <span class="text-lg font-bold">自動デプロイ</span>
  </li>
</ul>

05料金

月額(19,000円)と年額(190,000円)の間を、価格の数字が自動で行ったり来たりします。ボタンを押して切り替わるトグルではなく最初から最後まで勝手に動くデモで、実際のサービスに組み込むときはこの場所に本物の月額・年額切り替えボタンを足せば済みます。

숫자 롤 애니메이션@keyframes price-rolltabular-nums
<div class="flex flex-col items-end gap-4 sm:flex-row">
  <div class="flex-1 rounded-tile bg-white/60 p-8
              shadow-[0_6px_12px_rgba(23,20,26,.08)]">
    <p class="font-bold">無料</p>
    <p class="mt-2 font-display text-4xl font-extrabold tabular-nums">¥0</p>
  </div>
  <div class="relative flex-[1.1] rounded-tile bg-ink p-8 pt-10
              shadow-bento-hover">
    <span class="absolute -top-3 left-8 rounded-pill bg-accent px-3 py-1
                 text-xs font-bold text-cream">おすすめ</span>
    <p class="font-bold text-cream/70">プロプラン</p>
    <p class="mt-2 font-display text-5xl font-extrabold tabular-nums
              text-cream">
      ¥19,000<span class="text-lg font-semibold text-cream/60"> / 月</span>
    </p>
  </div>
</div>

06お客様の声

超大型の引用文が左から右へ、カーテンを開くように一気に現れます。01のヒーローが使う上下方向のマスクとは違い、こちらはclip-pathで左右方向にワイプする手法です。

clip-path: inset()단어 단위 stagger@keyframes wipe-reveal
<section class="py-14">
  <h2 class="mb-8 font-display text-3xl font-extrabold">お客様の声</h2>
  <figure class="rounded-tile bg-white p-10 text-center shadow-bento">
    <p class="font-display text-3xl font-extrabold leading-snug sm:text-4xl">
      「スピードがチームの文化を変えた」
    </p>
    <figcaption class="mt-4 text-sm text-ink/60">パク・ジフン・グロースリード</figcaption>
  </figure>
</section>

07CTA帯

横幅いっぱいの帯の中を、CTA文言が継ぎ目なく流れ続けます。文言をまるごと2組つなげてトラック1本にし、ちょうど半分(-50%)だけ動かすのがコツで、間隔はgapではなく項目ごとのmargin-rightで取らないと、一周するたびに数ピクセル飛んでしまいます。

translateX(-50%) 루프margin 간격(gap 금지)hover 일시정지
<div class="relative overflow-hidden rounded-tile bg-accent py-8">
  <div class="flex w-max animate-marquee">
    <span class="mr-12 flex-shrink-0 whitespace-nowrap font-display
                 text-5xl font-extrabold text-cream">今すぐ始める —</span>
    <span class="mr-12 flex-shrink-0 whitespace-nowrap font-display
                 text-5xl font-extrabold text-cream">今すぐ始める —</span>
    <span class="mr-12 flex-shrink-0 whitespace-nowrap font-display
                 text-5xl font-extrabold text-cream" aria-hidden="true">今すぐ始める —</span>
  </div>
</div>

08フッター

フッター最下部の巨大なワードマークの上を、光の帯が斜めに一度だけ通り過ぎます。background-clip: textで文字の形の中だけにグラデーションを閉じ込め、光が通り過ぎたあとはループの大半を静止したまま過ごします。

background-clip: textgradient sweepclamp() 초대형 폰트
<footer class="py-14">
  <div class="grid grid-cols-2 gap-4 sm:grid-cols-3">
    <div class="rounded-tile bg-ink/[.04] p-5">
      <p class="mb-2 text-xs font-bold uppercase tracking-wide text-ink/50">
        製品
      </p>
      <p class="text-sm font-semibold">機能</p>
    </div>
    <div class="rounded-tile bg-ink/[.04] p-5">
      <p class="mb-2 text-xs font-bold uppercase tracking-wide text-ink/50">
        会社
      </p>
      <p class="text-sm font-semibold">利用規約</p>
    </div>
  </div>
  <p class="mt-10 text-center font-display text-7xl font-extrabold
            text-ink/[.06] sm:text-8xl">MOTIF</p>
</footer>

09ボタン・入力

リンク型ボタンの下線が、ホバーすると中央から左右へ伸びてからまた縮みます。マウスでホバーしなくてもキーボードでフォーカスを移すと別枠の:focus-visibleが必ず現れるため、下線アニメーションひとつだけに頼らずに今どこにいるかがわかります。

transform: scaleXtransform-origin: centerfocus-visible 링
<div class="flex flex-col items-center gap-6 rounded-tile bg-ink p-10
            sm:flex-row sm:justify-center">
  <button class="relative border-0 bg-transparent font-display text-2xl
                 font-extrabold text-cream after:absolute after:-bottom-1
                 after:left-0 after:right-0 after:h-[2px] after:bg-accent">
    詳しく見る
  </button>
  <label class="relative w-full max-w-xs rounded-[12px] bg-cream/5">
    <input class="w-full rounded-[12px] border border-cream/30 bg-transparent
                  px-4 py-3 text-sm text-cream outline-none" type="email"
           placeholder="メールアドレス" readonly>
  </label>
</div>

tailwind.config カスタム

ここまでの9つの部品と一枚のランディングページは、すべてこの設定ひとつだけを参照しています。色・書体・角丸・影の値をここで書き換えると、画面全体の色調が一度にそろって変わります。

theme: {
  extend: {
    colors: {
      cream: "#fff7e6",
      ink: "#17141a",
      accent: "#2f6df6",
      line: "rgba(23,20,26,.08)",
    },
    fontFamily: {
      display: ["'Space Grotesk'", "system-ui", "sans-serif"],
      body: ["'Inter'", "system-ui", "sans-serif"],
    },
    borderRadius: { tile: "20px", pill: "999px" },
    boxShadow: {
      bento: "0 14px 24px rgba(23,20,26,.10)",
      "bento-hover": "0 20px 32px rgba(23,20,26,.16)",
    },
    spacing: { gutter: "14px" },
  },
},

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

上の設定をプロジェクトに貼り付けたら、Claude CodeやCursorには次のような数行を渡すだけで十分伝わります。省略していない指示文の全文はzipのprompt.mdにそのまま入っています。

背景はcream(#fff7e6)ひとつだけ。カードは真っ白ではなくink(#17141a)の上にcreamの文字を置く。
見出しと大きな数字にはfont-display(Space Grotesk)、本文にはfont-body(Inter)を使い、両者を混ぜない。
強調が必要な場所(ボタン・おすすめバッジ・CTA帯)にだけaccent(#2f6df6)を使い、二つ目の強調色は入れない。
角丸はrounded-tile・rounded-pillの二値だけを使う。

この指示をそのままpage/index.htmlに渡して得た結果を、1280px幅のビューポートでページ全体キャプチャとして残しました。

結果

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

このスタイルでいちばん多い落とし穴は、背景色や文字色を<style>タグの中でtheme()関数を使って直接指定することです。Tailwind Play CDNはbg-creamのようなコンパイル済みのユーティリティクラスの中のtheme()は正しく処理しますが、<style>タグの中に直書きしたbackground: theme('colors.cream')は静かに無視され、ブラウザ既定値(透明な背景・黒い文字)へ戻ってしまいます。このプロジェクトも最初は<body>の背景・文字色とh2の書体まで全部<style>タグのtheme()で指定していましたが、実際にレンダリングして確かめると、背景は透明(computed backgroundがrgba(0,0,0,0))、文字はink色ではなくただの黒、見出しの書体も反映されていない、という状態でした。<body class="bg-cream text-ink font-body">のようにコンパイルされるユーティリティクラスへ書き換え、h2一つひとつにfont-displayクラスを直接付けてはじめて正しく直りました。二つ目の落とし穴は02のワードマークです。見た目はスクロールに連動しているようですが、実際はスクロール監視なしのループ再生なので、字間まで一緒に縮むと期待してコードをそのまま流用すると、大きさしか変わらず戸惑うかもしれません。9つの部品と一枚のランディングページのソースを丸ごと収めたzipには鍵がかかっていて、そのパスワードはy9my63zgで、本文の下にあるボタンから受け取れます。

三つ目の落とし穴は03・05の数字アニメーションです。@property --numsyntax: '<integer>'を宣言しないと、ブラウザは0.5や1.7のような小数の途中値まで補間してしまい、数字がちらつきながら進みます。整数型を宣言してはじめて、桁がきれいにひとつずつ上がります。

アクセシビリティ

9つのデモはすべてMDNのprefers-reduced-motionのページが定めるメディアクエリで包んであり、動作を減らす設定を有効にした方には単語が浮き上がったり数字が駆け上がったりする代わりに、静止した最終状態だけが見えます。03・05の数字はcounter()で描いているためスクリーンリーダーが読み上げられず、実際の値を見た目だけ隠したテキストとして常に添えてあります。07のマーキーで複製した半分はaria-hiddenにして同じ文言を二度読み上げないようにし、09は下線アニメーションとは別に:focus-visibleの枠を常に有効にしてあるため、動きを止めた環境でもフォーカスの位置がわかります。

このスタイル以外のトレンドが気になる方はデザイントレンドのカテゴリーにまとめてあり、このサイトを運営しているのが誰かはサイト紹介ページでご確認いただけます。

FAQ

MOTIFやKINETICのような名前を実際のサービスでそのまま使ってもいいですか?

はい、問題ありません。この記事の部品は特定の実在ブランドをコピーしたものではなく、ピンタレストでよく見かけるキネティックタイポグラフィの雰囲気を参考に考えた架空の名前(MOTIF)とラベル(KINETIC)ですので、ご自身のサービス名に置き換えていただいて構いません。

Space GroteskやInter以外の書体に変えてもいいですか?

可能です。tailwind.config.jsfontFamily.displayfontFamily.bodyの二つの値を変えるだけで、9つの部品すべてに新しい書体が一度に反映されます。ただし、太く目立つ見出し・大きな数字(display)と落ち着いた本文(body)という役割分担そのものは残しておくことをおすすめします。

Tailwindを使わず素のCSSだけでも使えますか?

使えます。zipに入っているtokens.csstailwind.config.jsと同じ値を--color-cream--radius-tileのようなCSS変数として書き出しているので、Tailwindのクラスの代わりにvar(--radius-tile)と直接参照すれば、色や角丸をそのまま合わせられます。

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

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