【Next.js】ホバーカードの作り方を Tailwind の実例付きで紹介
公開日: 2026年9月12日 · 読了目安 10 分
Next.js で機能紹介や作品一覧のカードにホバーアニメーションを付ける方法を、Tailwind CSS だけの拡大・影、マウス位置で光るスポットライト、Framer Motion の whileHover の3通りのコードで解説。タッチ端末とキーボード操作への対応、よくある失敗も。
Next.js のホバーカードが地味・派手すぎるときの直し方
機能紹介や作品一覧のカードを Next.js で並べると、静かすぎて押せる場所に見えないことがあります。
かといって拡大・影・画像ズームを全部付けると、今度は画面が落ち着きません。
ホバーカードは、反応する場所を1か所に絞ると整います。枠の色、画像の拡大、カードの浮き上がりのうち1つを選びます。
時間は 150〜300ms、イージングは減速寄り(ease-out)にします。拡大するなら 1.02〜1.04 倍が目安です。
この記事では、次の内容をコード付きで説明します。
Tailwind CSS だけで作る、画像が拡大するホバーカード
マウス位置に合わせて光るスポットライトカード
Motion(旧 Framer Motion)の whileHover で浮き上がらせる方法
タッチ端末とキーボード操作で崩れないための注意点
ホバーカードの反応を1か所に絞る3つの理由
ホバー演出の役割は「ここを押せる」と伝えることです。反応が複数あると、視線がどこに向かえばよいか分からなくなります。
カードが 6〜9 枚並ぶ機能セクションでは、1枚ごとの動きが小さいほど全体が整って見えます。
もう1つの理由は、レイアウトの崩れです。ホバーで width や margin、border の太さを変えると、隣のカードまで押し出されて動きます。
位置や大きさ(transform)と透明度(opacity)だけを変えれば、周りの配置に影響しません。ブラウザの描画負荷も軽くなります。
最後に、タッチ端末の事情があります。スマホのブラウザはタップしたときにホバー状態を当て、別の場所に触れるまで残すことがあります(sticky hover)。
ホバーでしか見えない説明文やボタンは、スマホでは存在しないのと同じです。
情報は最初から見えている場所に置き、ホバーは飾りにとどめます。
Tailwind CSS だけで作るホバーカードの実装
まずは追加のパッケージなしで作れる形です。サーバーで組み立てる部品(Server Component)のままでよく、ブラウザで動かす印の "use client" も要りません。
カード全体を Link にし、中の画像だけを overflow-hidden の枠の中で拡大します。
import Image from "next/image";
import Link from "next/link";
type WorkCardProps = {
href: string;
title: string;
summary: string;
image: string;
};
export function WorkCard({ href, title, summary, image }: WorkCardProps) {
return (
<Link
href={href}
className="group block overflow-hidden rounded-2xl border border-zinc-200 bg-white transition-colors duration-200 ease-out hover:border-zinc-400 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-900 focus-visible:ring-offset-2"
>
<div className="relative aspect-[4/3] overflow-hidden bg-zinc-100">
<Image
src={image}
alt=""
fill
sizes="(min-width: 1024px) 33vw, (min-width: 768px) 50vw, 100vw"
className="object-cover transition-transform duration-300 ease-out group-hover:scale-[1.04] group-focus-visible:scale-[1.04] motion-reduce:transition-none"
/>
</div>
<div className="p-5">
<h3 className="font-semibold text-zinc-950">{title}</h3>
<p className="mt-2 text-sm leading-relaxed text-zinc-600">{summary}</p>
</div>
</Link>
);
}画像だけを拡大するとホバーカードが落ち着く
カード全体を hover:scale で膨らませると、角丸や影ごと大きくなります。隣のカードに重なって見えることもあります。
画像だけを枠の中で拡大すれば、カードの外形は変わりません。group と group-hover を使うと、カードのどこにマウスを乗せても画像が反応します。
画像がタイトルの言い換えにすぎないなら alt は空にし、画像に固有の情報があるなら内容を書きます。
空にする場合も alt 属性そのものは残してください。
浮き上がりと影で反応するホバーカード
画像のないテキストだけのカードなら、少し上に動かして影を足す形が合います。動かす量は 4px 程度で十分です。
影は shadow-lg くらいまでにして、色付きの大きな光彩は避けます。
<div className="rounded-2xl border border-zinc-200 bg-white p-6 transition duration-200 ease-out hover:-translate-y-1 hover:shadow-lg motion-reduce:transition-none motion-reduce:hover:translate-y-0">
<h3 className="font-semibold">請求書を自動で読み取る</h3>
<p className="mt-2 text-sm text-zinc-600">PDF をアップロードするだけで、金額と期日を抜き出します。</p>
</div>キーボード操作でも同じ強調を出す
Tab キーで移動する人にとって、ホバーの演出は見えません。
キーボードで選んだときの状態(focus-visible)にも同じ強調を付けます。すると、マウスでもキーボードでも「選べる場所」が分かります。
上のコードでは、リングの表示と画像の拡大を、キーボードで選んだときにも付けています。
Tailwind CSS v4 では、hover: のスタイルがホバーできる端末だけに適用されるようになりました。
v3 のプロジェクトでは、スマホでタップ後にホバー状態が残ることがあります。
tailwind.config の future に hoverOnlyWhenSupported: true を足すと、v4 と同じ挙動にできます。
マウス位置で光るスポットライトのホバーカード
暗い背景の機能セクションでよく見る、マウスの位置にやわらかい光が付いてくる演出です。マウスの座標を読むので、ブラウザで動く部品(Client Component)にします。
ポイントは、座標を useState(状態を覚える仕組み)に入れないことです。状態を更新すると、マウスが動くたびに画面の描き直しが走ります。
CSS 変数(--x と --y)を要素に直接書き込めば、React の再描画なしで光だけが動きます。
"use client";
import { useRef, type PointerEvent, type ReactNode } from "react";
export function SpotlightCard({ children }: { children: ReactNode }) {
const ref = useRef<HTMLDivElement>(null);
function handlePointerMove(event: PointerEvent<HTMLDivElement>) {
// タッチやペンでは光らせない
if (event.pointerType !== "mouse" || !ref.current) return;
const rect = ref.current.getBoundingClientRect();
ref.current.style.setProperty("--x", `${event.clientX - rect.left}px`);
ref.current.style.setProperty("--y", `${event.clientY - rect.top}px`);
}
return (
<div
ref={ref}
onPointerMove={handlePointerMove}
className="group relative overflow-hidden rounded-2xl border border-white/10 bg-zinc-900 p-6 text-white"
>
<div
aria-hidden="true"
className="pointer-events-none absolute inset-0 opacity-0 transition-opacity duration-300 group-hover:opacity-100"
style={{
background:
"radial-gradient(240px circle at var(--x, 50%) var(--y, 50%), rgba(255, 255, 255, 0.12), transparent 70%)",
}}
/>
<div className="relative">{children}</div>
</div>
);
}スポットライトは1セクションだけにする
目を引く演出なので、LP の全カードに付けると疲れます。機能紹介の1セクションか、料金表の推しプランだけに使うのが目安です。
スマホではマウスがないため、pointerType で mouse 以外を除外しています。
光がなくても情報が伝わるよう、カードの枠と文字のコントラストは光なしの状態で整えておきます。
Framer Motion でふわっと浮くホバーカード
すでに Motion を入れているプロジェクトなら、whileHover と whileTap でばねのような動きを付けられます。CSS の transition より、止まり際がやわらかくなります。
導入の手順は https://design-layer.com/ja/articles/nextjs-framer-motion-guide にまとめています。
"use client";
import { motion } from "motion/react";
import type { ReactNode } from "react";
export function LiftCard({ children }: { children: ReactNode }) {
return (
<motion.div
whileHover={{ y: -4 }}
whileTap={{ scale: 0.98 }}
transition={{ type: "spring", stiffness: 300, damping: 24 }}
className="rounded-2xl border border-zinc-200 bg-white p-6"
>
{children}
</motion.div>
);
}CSS で足りるホバーカードは CSS で作る
ホバーの浮き上がりだけのために、Motion を追加する必要はありません。
カードがスクロールで入場する、並び替えで位置が動くといった別の動きもあるときに使うと、パッケージを入れる意味が出ます。
ホバーカードでよくある失敗と直し方
公開前に、次の点を確認してください。
transition-all を付けて、色や影まで毎回すべて計算させている(変える値だけを指定する)
カード全体が Link なのに、中にも別のリンクやボタンがある(a の中に a は入れられず、クリック先も分かりにくい)
親に overflow-hidden を付けたまま、浮き上がったカードの影が切れている
ホバーでしか表示されない説明文や価格がある
拡大率が大きすぎて、画像の端がぼやけている
カードの中に「詳しく見る」とは別の操作を置きたいときは、カード全体をリンクにするのをやめます。代わりに、タイトルだけをリンクにします。
押せる範囲を広げたい場合は、タイトルのリンクに after:absolute after:inset-0 を付け、カードを relative にする方法があります。
ホバーカード入りのセクションをコピーして使う方法

ここまでのコードで、1枚のカードは作れます。ただ、実際の機能セクションでは、次の点がまとめて揃っている必要があります。
カードの並び方
画像の切り抜き
見出しの大きさ
ホバーの強さ
この調整に時間がかかります。
DesignLayer は、人が組んだ React + Tailwind CSS のモーション付きセクションを、ブラウザでライブプレビューしてからコピーできるカタログです。
ホバーの強さや動きの速さを、実際に触って確かめてから選べます。
閲覧は無料で、カード登録も要りません。https://design-layer.com/ja/components
Copy for Cursor を押すと、統合の指示・ライブプレビューの URL・本体の TSX・npm 依存がまとめてコピーされます。Cursor や Claude にそのまま渡せます。
無料アカウントでは、無料サンプル10個を無料アカウントで回数制限なくコピーでき、動画プロンプトは月1回です。Free では MCP に接続できません。カタログ全体は30日ビルドパス($19の1回払い、自動更新なし)、Lifetime Access(先着100名の$79の1回払い)、Plus(月額 $9、いつでも解約可)です。
カードを並べる形そのものに迷っている場合は、次の記事も参考にしてください。
Next.js のホバーカードについてよくある質問
Tailwind CSS の hover: や group-hover: だけで作るなら、必要ありません。サーバーで組み立てる部品のままで使えます。
マウスの座標を読むスポットライトや、Motion を使う場合は、ブラウザで動かす印が必要です。その場合も、カード1枚の部品だけをブラウザで動く部品にし、ページ全体はサーバー側に残します。
まとめ:Next.js でホバーカードを作る手順
ホバーで反応させるのは、枠・画像・浮き上がりのうち1か所にする
変えるのは位置・大きさ・透明度・色だけにし、隣のカードを動かさない
キーボードで選んだときにも同じ強調を付け、ホバーでしか見えない情報を置かない
スポットライトはブラウザで動く部品にし、座標は状態ではなく CSS 変数で渡す
Motion は、ほかの動きもあるときに使う
まずは Tailwind CSS の WorkCard を1つ置き、拡大率と時間を実際に触って調整してみてください。
セクション全体の見た目まで揃えたいときは、DesignLayer のカタログでホバーを確かめてから選べます。https://design-layer.com/ja/components


