【Next.js】機能紹介セクションの作り方を3列カードの実装例で解説
公開日: 2026年9月12日 · 読了目安 11 分
Next.js の LP に置く機能紹介(Features)セクションの作り方。読まれる見出しの書き方、Tailwind CSS の3列カード、Framer Motion で少しずつ遅れて出る入場、ホバー、左右交互レイアウトまでコード付きで解説します。
機能紹介セクションは「できること」を3枚か6枚で並べる
Next.js で LP を作り、ヒーローの下に機能紹介を置いた。アイコンと「高速」「安全」「連携」を3列に並べたら、どこかで見た SaaS のページになった。
この記事は、そんな悩みに答えます。
機能紹介(Features)セクションは、カードの見出しを機能名ではなく「訪問者ができるようになること」にすると読まれます。
枚数は3枚か6枚で足ります。動きは、カードが下から少しずつ遅れて揃う程度で十分です。
この記事で分かること:
機能紹介の見出しと本文の書き方(書き換えの例つき)
Tailwind CSS で作る3列カードの機能紹介セクション
Motion(旧 Framer Motion)でカードを順番に出す入場アニメーション
枠とアイコンだけを変える控えめなホバー
スクリーンショットを左右交互に並べるレイアウト
機能紹介セクションが読まれない3つの理由
機能紹介は、LP の中でじっくり読まれる場所です。
ヒーローで興味を持った人が、何ができるのかを確かめに来ます。
ここで流し読みされてしまう原因は、主に次の3つです。
見出しが機能名だけで、本文がその言い換えになっている(「高速」の本文が「高速に動作します」)
アイコンが全部同じ形と太さで、無くても意味が変わらない
ヒーローと同じ強さのアニメーションが付いていて、文字を読む前に目が動きに取られる
どれも見た目の問題に見えますが、根本は「訪問者にとって何が変わるか」が書かれていないことです。デザインを触る前に、カードの文章から直します。
機能紹介の見出しを書き換える例
機能名を、訪問者の作業がどう変わるかに置き換えます。本文では「誰の・何が・どれくらい」を1〜2文で補います。
「高速」→「ページの表示で訪問者を待たせない」
「セキュリティ」→「顧客データを社外に出さずに使える」
「連携」→「問い合わせが Slack にそのまま届く」
「分析」→「どの広告から申し込みが来たか分かる」
機能紹介のカードは3枚か6枚にする
3列のグリッドでは、3枚か6枚だと行が欠けません。4枚や5枚だと最後の行に空きができ、未完成に見えます。
9枚以上になると「全部載せた」印象になり、どれも読まれなくなります。
伝えたいことが多いときは、上位の6つに絞ります。残りは料金表や FAQ に回します。
Tailwind CSS で3列カードの機能紹介セクションを作る
まずは動きのない形を作ります。カードの中身はアイコン・見出し・2行ほどの本文です。
データを配列にしておくと、文言の差し替えが1か所で済みます。
このコンポーネントは状態を持たないので、サーバーコンポーネントのまま使えます。アイコンには shadcn/ui でもよく使われる lucide-react を使っています(npm i lucide-react)。
import { Clock, ShieldCheck, Zap } from "lucide-react";
const features = [
{
icon: Zap,
title: "ページの表示で訪問者を待たせない",
body: "画像は自動で軽くなり、スマホの回線でも最初の画面がすぐに出ます。",
},
{
icon: ShieldCheck,
title: "顧客データを社外に出さずに使える",
body: "データは自社の環境に保存されます。権限は担当者ごとに分けられます。",
},
{
icon: Clock,
title: "公開までの作業が1日で終わる",
body: "文章を入れるだけで、確認用の URL がすぐに発行されます。",
},
];
export function Features() {
return (
<section id="features" className="mx-auto max-w-6xl px-6 py-24">
<p className="text-sm font-medium text-indigo-600">機能</p>
<h2 className="mt-2 text-3xl font-semibold tracking-tight md:text-4xl">
作る時間を減らして、届ける時間を増やす
</h2>
<p className="mt-4 max-w-2xl text-zinc-600">
LP の公開までに必要な作業を、3つの機能でまとめて短くします。
</p>
<ul className="mt-12 grid gap-6 md:grid-cols-3">
{features.map(({ icon: Icon, title, body }) => (
<li key={title} className="rounded-2xl border border-zinc-200 p-6">
<Icon aria-hidden className="h-6 w-6 text-indigo-600" />
<h3 className="mt-4 font-semibold">{title}</h3>
<p className="mt-2 text-sm leading-relaxed text-zinc-600">{body}</p>
</li>
))}
</ul>
</section>
);
}セクションの見出しとリードの役割
カードの上には、小さなラベル・h2・1行のリードを置きます。h2 は機能の総まとめではなく、カード全体で何が変わるかを書きます。
カードの見出しは h3 にすると、見出しの順番が飛ばずに済みます。
余白を揃えると、動きが無くても整って見える
次の3つの余白を揃えるだけで、印象はかなり変わります。
カードの padding: 24px
カード同士の gap: 24px
セクションの上下の余白: 96px
動きを足すのは、この形が整ってからにします。
機能紹介のカードを順番に出す入場アニメーション
スクロールして機能紹介が見えたときに、カードが下から 16px ほど浮き上がり、0.08 秒ずつ遅れて揃う。機能紹介の動きはこれで十分です。
Motion の variants(動きの状態に名前を付ける仕組み)を使います。親の delayChildren に stagger(子を順番に遅らせる指定)を書くと、カードごとの遅延をまとめて決められます。
動きを担当する部分だけを、ブラウザで動く部品に分けます。ファイルの先頭に "use client"(この部品はブラウザで動かす、という印)を書きます。
機能紹介の本体は、サーバーで組み立てる部品のままにします。カードのリスト部分だけを、この部品に置き換えます。
"use client";
import { motion, stagger, type Variants } from "motion/react";
import type { ReactNode } from "react";
const list: Variants = {
hidden: {},
show: { transition: { delayChildren: stagger(0.08) } },
};
const item: Variants = {
hidden: { opacity: 0, y: 16 },
show: { opacity: 1, y: 0, transition: { duration: 0.4, ease: "easeOut" } },
};
export function RevealList({ children, className }: { children: ReactNode; className?: string }) {
return (
<motion.ul
className={className}
variants={list}
initial="hidden"
whileInView="show"
viewport={{ once: true, amount: 0.3 }}
>
{children}
</motion.ul>
);
}
export function RevealItem({ children, className }: { children: ReactNode; className?: string }) {
return (
<motion.li className={className} variants={item}>
{children}
</motion.li>
);
}機能紹介のリストを入場用の部品に置き換える
リストの外枠(ul)は、RevealList に置き換えます。
各カード(li)は、RevealItem に置き換えます。付けていたクラスは、そのまま渡せます。
<RevealList className="mt-12 grid gap-6 md:grid-cols-3">
{features.map(({ icon: Icon, title, body }) => (
<RevealItem key={title} className="rounded-2xl border border-zinc-200 p-6">
<Icon aria-hidden className="h-6 w-6 text-indigo-600" />
<h3 className="mt-4 font-semibold">{title}</h3>
<p className="mt-2 text-sm leading-relaxed text-zinc-600">{body}</p>
</RevealItem>
))}
</RevealList>一度だけ再生して、戻るたびにカードを動かさない
viewport の once を true にすると、一度表示されたカードは上に戻っても再生されません。読み返すたびにカードが消えて出直すと、読む邪魔になります。
amount: 0.3 は、セクションの3割が見えたら再生する、という意味です。
機能紹介カードのホバーは枠とアイコンの色で示す
カードにホバーで大きな影を付けると、押せるボタンのように見えます。
機能紹介のカードは多くの場合リンクではないので、変化は小さく抑えます。枠の色を少し濃くし、アイコンを 2px だけ上げる程度にします。
<RevealItem className="group rounded-2xl border border-zinc-200 p-6 transition-colors hover:border-indigo-300">
<Icon
aria-hidden
className="h-6 w-6 text-indigo-600 transition-transform duration-300 group-hover:-translate-y-0.5 motion-reduce:transition-none"
/>
{/* 見出しと本文は同じ */}
</RevealItem>画面を見せる機能紹介は左右交互のレイアウトにする
機能が画面そのもの(ダッシュボード、編集画面など)のときは、カードよりスクリーンショットを大きく見せた方が伝わります。文章と画像を1行ずつ並べ、偶数行だけ左右を入れ替えます。
画像には next/image を使い、width と height を指定してレイアウトのずれを防ぎます。
入場の動きは、ヒーローより弱くします。ヒーローの作り方は https://design-layer.com/ja/articles/nextjs-animated-hero-section-guide で解説しています。
import Image from "next/image";
const rows = [
{
title: "申し込みの流れを1画面で追える",
body: "どの広告から来て、どのページで離れたかを時系列で確認できます。",
image: "/features/dashboard.png",
alt: "申し込みの流れを表示したダッシュボード",
},
{
title: "文章の修正はブラウザで完結する",
body: "公開中のページをそのまま編集し、確認してから反映できます。",
image: "/features/editor.png",
alt: "ページの文章を編集している画面",
},
];
export function FeatureRows() {
return (
<section className="mx-auto max-w-6xl space-y-24 px-6 py-24">
{rows.map((row, i) => (
<div
key={row.title}
className={`flex flex-col items-center gap-10 md:flex-row ${i % 2 === 1 ? "md:flex-row-reverse" : ""}`}
>
<div className="md:w-1/2">
<h3 className="text-2xl font-semibold">{row.title}</h3>
<p className="mt-4 leading-relaxed text-zinc-600">{row.body}</p>
</div>
<Image
src={row.image}
alt={row.alt}
width={1200}
height={800}
className="rounded-2xl border border-zinc-200 md:w-1/2"
/>
</div>
))}
</section>
);
}機能紹介を3列カードとベントグリッドで使い分ける
最近の LP では、大小のマスを組み合わせたベントグリッドもよく見かけます。どちらを選ぶかは、見せたいものが文章か、写真や数字かで決めます。
説明文が中心なら、3列カードの方が読みやすい
写真・数字・小さなデモを大きく見せたいなら、ベントグリッドが向いている
画面そのものを見せたいなら、左右交互のレイアウトが伝わりやすい
ベントグリッドの作り方は https://design-layer.com/ja/articles/nextjs-bento-grid-guide にまとめています。
完成した機能紹介セクションをコピーして使う方法

ホバーでカードが持ち上がり、アイコンが少し動き、入場の遅延も整っている。この塊を一から組むと、カードの比率や余白の調整に時間がかかります。
DesignLayer は、人が組んだ React + Tailwind のモーション付きセクションを、ブラウザでライブプレビューしてからコピーできるカタログです。
閲覧はアカウントもカードも不要です。https://design-layer.com/ja/components
無料サンプル10個を無料アカウントで回数制限なくコピーでき、動画プロンプトは月1回です。Free では MCP に接続できません。カタログ全体は30日ビルドパス($19の1回払い、自動更新なし)、Lifetime Access(先着100名の$79の1回払い)、Plus(月額 $9、いつでも解約可)です。機能紹介と料金表が無料サンプル以外なら、30日ビルドパス($19)、Lifetime($79)、Plus(月額 $9)です。
料金表の作り方は https://design-layer.com/ja/articles/nextjs-pricing-table-guide です。
機能紹介セクションについてよくある質問
3列のグリッドなら3枚か6枚です。行に空きができず、最後まで読まれやすくなります。
それ以上あるときは、料金表や FAQ に分けて載せます。
まとめ:Next.js で機能紹介セクションを作る手順
カードの見出しは機能名ではなく、訪問者ができるようになることを書く
枚数は3枚か6枚にし、多いときは料金表や FAQ に回す
動きはカードが少しずつ遅れて揃う程度にし、一度だけ再生する
ホバーは影ではなく、枠とアイコンの色だけを変える
画面を見せたいときは左右交互、写真や数字を大きく見せたいときはベントグリッド
まずは今ある機能紹介の見出しを、この記事の例にならって書き換えてみてください。レイアウトの選択肢を広げるなら https://design-layer.com/ja/articles/nextjs-bento-grid-guide 、スクロールで出す動きは https://design-layer.com/ja/articles/nextjs-scroll-reveal-guide が参考になります。


