【Next.js】ヒーローセクションに入場と背景のアニメーションを付ける方法を解説

公開日: 2026年9月8日 · 読了目安 12 分

Next.js のヒーローセクションに、時間差で揃う入場アニメーション、ゆっくり動く背景、スクロールに連動するパララックスを付ける方法をコード付きで解説。CSS だけの方法と Motion(旧 Framer Motion)の方法、動きを減らす設定、公開前のチェックまで。

Next.js のヒーローセクションにアニメーションを付けるには

Next.js でサイトのトップを作り、見出しと説明文とボタンを並べた。

構成は悪くないのに、開いた瞬間に何も起きないので、写真付きのバナーと同じに見えてしまう。ヒーローセクションでよくある悩みです。

解決するには、派手な素材を足すより先に「何を動かすか」を決めます。候補は次の3つです。

  • 要素が時間差で揃う入場

  • ゆっくり動く背景

  • カーソルへの反応

このうち2つまでに絞ります。入場は CSS で、スクロールに連動する動きは Motion(旧 Framer Motion)で作るのがいちばん手堅い方法です。

この記事では、次の4つをコード付きで作ります。

  • CSS だけで作る、時間差の入場アニメーション

  • CSS だけで作る、ゆっくり動く背景の光

  • Motion で作る、まとめて制御する入場とスクロール連動のパララックス

  • 動きを減らす設定(prefers-reduced-motion)への対応

動きのないヒーローセクションがバナーに見える3つの理由

コードに入る前に、ヒーローが地味に見える原因を確認しておきます。原因がわかると、どこに動きを足せばよいかが決まります。

ヒーローのすべての要素が同時に表示される

見出しや本文、ボタンや画像が同じタイミングで出ると、目線の順番が生まれません。要素が少しずつ揃うと、読む順番が自然に伝わります。

スクロールした瞬間にヒーローが終わる

画面の高さを過ぎたとたんに次のセクションへ切り替わると、ファーストビューは1枚のポスターになります。背景が本文より遅れて動くだけでも、ページ全体の導入として働きます。

ヒーローに動きを付けすぎている

すべての要素が弾み、背景が激しくループし、マウスを追いかけてくる。

こうなると、印象より疲れが先に来ます。入場・背景・ホバーのうち2つまでにすると破綻しにくくなります。

この記事で作るヒーローセクションのアニメーション

目指す動きを先に決めておきます。数値は、そのままコードに使っています。

  • ラベルが先に現れ、続いて見出しが下から20px上がる。本文とボタンは0.08秒ずつ遅れて揃う

  • 背景のぼんやりした光が、18秒かけてゆっくり位置と大きさを変える

  • 少しスクロールすると、背景の写真が本文より遅れて動き、文字は薄くなっていく

  • CTA ボタンは、ホバーでほんの少しだけ縮む

3D やシェーダーは扱いません。多くの LP では、入場と背景の動きだけで十分に印象が変わります。

CSS だけでヒーローの入場アニメーションを作る

入場とホバーだけなら、ライブラリは要りません。サーバーコンポーネントのまま書けるので、ブラウザに送る JavaScript も増えません。

アニメーションを1つ作り、開始のタイミングだけをずらす

全要素に同じアニメーションを付けると、同時に出るのと変わりません。

遅延の段差は、次のくらいで十分です。

  • ラベル:0秒(すぐ)

  • 見出し:0.08秒

  • 本文:0.16秒

  • ボタン:0.24秒

動く距離は16〜24px にします。大きく動かすと安っぽく見えます。

最後の @media は、OS で「視差効果を減らす」などを有効にしている人向けの設定です。アニメーションを止め、最初から表示された状態にします。

app/globals.css
@keyframes hero-rise {
  from {
    opacity: 0;
    transform: translateY(20px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.hero-rise {
  animation: hero-rise 0.7s cubic-bezier(0.22, 1, 0.36, 1) both;
}

@media (prefers-reduced-motion: reduce) {
  .hero-rise {
    animation: none;
  }
}

ヒーローの入場アニメーションをページに組み込む

App Router では、ヒーローを page.tsx の最初のセクションに置きます。高さは min-h-[100svh] にすると、スマホのアドレスバーの出し入れでずれにくくなります。

ボタンのホバーは scale を少し変えるだけにし、影や色の点滅は入場とぶつかるので避けます。

入場アニメーションと同じ要素に transform のホバーを付けると、アニメーションの値に上書きされて効きません。

そこでボタンを div で包み、入場は外側に、ホバーの scale は内側のリンクに付けます。

app/page.tsx
export default function Page() {
  return (
    <section className="relative isolate min-h-[100svh] overflow-hidden px-6 pt-28">
      <p className="hero-rise text-sm tracking-wide">2026 Launch</p>
      <h1 className="hero-rise mt-4 text-4xl font-semibold" style={{ animationDelay: "80ms" }}>
        動きのあるファーストビューを、今日出す
      </h1>
      <p className="hero-rise mt-5 max-w-xl text-zinc-600" style={{ animationDelay: "160ms" }}>
        見出し、本文、ボタンの順に揃えるだけで印象は変わります。
      </p>
      <div className="hero-rise mt-8" style={{ animationDelay: "240ms" }}>
        <a
          href="#features"
          className="inline-flex rounded-full bg-zinc-950 px-5 py-3 text-white transition hover:scale-[0.98]"
        >
          詳しく見る
        </a>
      </div>
    </section>
  );
}

CSS だけでヒーローの背景をゆっくり動かす

背景に動きがあると、文字が止まっていてもページが生きて見えます。

ここでは、ぼんやりした光を18秒かけて動かします。速くすると目障りになるので、気づくか気づかないかくらいの速さにしてください。

光は radial-gradient(円形のグラデーション)で、最初からぼかした形にしておきます。

ぼかし(filter: blur)をアニメーションさせると重くなります。そのため、動かすのは位置と大きさ(transform)だけにします。

app/globals.css
@keyframes hero-drift {
  0%,
  100% {
    transform: translate3d(0, 0, 0) scale(1);
  }
  50% {
    transform: translate3d(4%, -3%, 0) scale(1.08);
  }
}

.hero-glow {
  background: radial-gradient(circle at 50% 40%, rgb(56 189 248 / 0.35), transparent 60%);
  animation: hero-drift 18s ease-in-out infinite;
}

@media (prefers-reduced-motion: reduce) {
  .hero-glow {
    animation: none;
  }
}

背景の光をヒーローセクションの中に置く

光は、先ほどの section の最初の子として置きます。

外枠に relative と isolate を付けておくと、-z-10 の光が本文の後ろに収まります。

aria-hidden を付け、読み上げの対象から外します。

app/page.tsx
<div
  aria-hidden
  className="hero-glow pointer-events-none absolute inset-x-0 -top-1/2 -z-10 h-[120%]"
/>

Framer Motion でヒーローの入場とパララックスを作る

スクロール量に合わせて位置や透明度を変えたいときは、Motion を使います。npm install motion で追加できます。

古いプロジェクトで framer-motion を使っている場合も、同じ書き方で動きます。

スクロール量を読み取る仕組み(useScroll)や motion を使うファイルには、先頭に "use client"(この部品はブラウザで動かす、という印)が必要です。

ページ全体をブラウザで動く部品にせず、ヒーローだけを別ファイルに切り出してください。

ヒーローの入場の時間差を Framer Motion でまとめて書く

CSS では要素ごとに delay を書きましたが、Motion では親の staggerChildren(子要素を順番に動かす指定)で一度に指定できます。

ヒーローは開いた時点で画面内にあるので、animate で表示と同時に再生します。

下のセクションに使う場合は、whileInView(画面に入ったら動かす指定)にします。

あわせて viewport={{ once: true }} を付けると、スクロールで戻るたびに繰り返されません。

components/Hero.tsx
"use client";

import { motion, type Variants } from "motion/react";

const container: Variants = {
  hidden: {},
  show: { transition: { staggerChildren: 0.08, delayChildren: 0.1 } },
};

const item: Variants = {
  hidden: { opacity: 0, y: 20 },
  show: { opacity: 1, y: 0, transition: { duration: 0.7, ease: [0.22, 1, 0.36, 1] } },
};

export function Hero() {
  return (
    <motion.section
      variants={container}
      initial="hidden"
      animate="show"
      className="min-h-[100svh] px-6 pt-28"
    >
      <motion.p variants={item} className="text-sm tracking-wide">2026 Launch</motion.p>
      <motion.h1 variants={item} className="mt-4 text-4xl font-semibold">
        動きのあるファーストビューを、今日出す
      </motion.h1>
      <motion.p variants={item} className="mt-5 max-w-xl text-zinc-600">
        見出し、本文、ボタンの順に揃えるだけで印象は変わります。
      </motion.p>
      <motion.a
        variants={item}
        href="#features"
        whileHover={{ scale: 0.98 }}
        className="mt-8 inline-flex rounded-full bg-zinc-950 px-5 py-3 text-white"
      >
        詳しく見る
      </motion.a>
    </motion.section>
  );
}

スクロールに合わせてヒーローの背景にパララックスを付ける

パララックスは、背景が手前の文字より遅く動いて奥行きが出る表現です。

まず、スクロール量を読み取る仕組み(useScroll)で、ヒーローのスクロール量を0〜1の数値で取ります。それを値を変換する仕組み(useTransform)で、背景の位置と文字の透明度に変えます。

useReducedMotion は、動きを減らす設定が有効なら true を返します。そのときは背景を動かさないようにしています。

背景は上下に10%ずつ余白を持たせ、動いても端が見えないようにします。

components/HeroParallax.tsx
"use client";

import { useRef } from "react";
import { motion, useReducedMotion, useScroll, useTransform } from "motion/react";

export function HeroParallax() {
  const ref = useRef<HTMLElement>(null);
  const reduce = useReducedMotion();
  const { scrollYProgress } = useScroll({
    target: ref,
    offset: ["start start", "end start"],
  });
  const bgY = useTransform(scrollYProgress, [0, 1], ["0%", reduce ? "0%" : "15%"]);
  const textOpacity = useTransform(scrollYProgress, [0, 0.7], [1, 0]);

  return (
    <section ref={ref} className="relative isolate min-h-[100svh] overflow-hidden px-6 pt-28">
      <motion.div
        aria-hidden
        style={{ y: bgY, backgroundImage: "url(/hero.jpg)" }}
        className="absolute inset-x-0 -top-[10%] -z-10 h-[120%] bg-cover bg-center"
      />
      <motion.div style={{ opacity: textOpacity }}>
        <h1 className="text-4xl font-semibold text-white">奥行きのあるファーストビュー</h1>
      </motion.div>
    </section>
  );
}

ヒーローのアニメーションで弱い動きと強い動きの違い

弱く見えるのは、動く時間(duration)を1.4秒以上にしたり、弾むような動きを使ったりする場合です。LP のヒーローは商品の紹介であり、読み込み画面ではありません。

強く見えるのは、減速寄りのイージングで、画像だけを0.12秒ほど遅らせる場合です。

テキストが先、ビジュアルが後という順番は、雑誌の見開きに近い読み心地になります。

パララックスも背景だけを数パーセント動かす程度にとどめ、文字まで追従させないようにします。

ヒーローのアニメーションを公開する前の確認リスト

動きを付けたら、公開の前に次の5点を確認してください。どれも見落とすと、せっかくの動きが逆効果になります。

  • 動きを減らす設定で、入場と背景のアニメーションが止まるか

  • スマホのファーストビューに、見出しと申し込みボタンが収まっているか

  • いちばん大きな画像を、アニメーションで透明にしていないか(表示速度の指標である LCP が遅れる)

  • ヒーロー以外のセクションに、同じ強さの動きを並べていないか

  • ページ全体のファイルに、ブラウザで動かす印を書いていないか

3つ目は特に見落としがちです。最初に目に入る写真は、最初から見えている状態にしてください。

フェードさせるのは文字とボタンだけで十分です。

完成したヒーローセクションをコピーして使う方法

DesignLayer の「グリーン・スクロールヒーロー」の詳細ページ。左でライブプレビューを確かめ、右の「Cursor 用にコピー」でソースをコピーできる
DesignLayer の「グリーン・スクロールヒーロー」の詳細ページ。左でライブプレビューを確かめ、右の「Cursor 用にコピー」でソースをコピーできる

スクロールで草木の後ろから見出しが現れる、写真が固定されたまま切り替わる。こうした凝った動きは、この記事の方法を組み合わせても半日以上かかることがあります。

その場合は、ブラウザで実際の動きを見てから、React + Tailwind CSS で作られたヒーローを自分の Next.js に載せる方法もあります。

DesignLayer のカタログでは、動きのあるセクションをライブプレビューで確かめ、ソースをコピーできます。

閲覧にカードは要らず、コピーは無料で日本時間の1日3回までです。https://design-layer.com/ja/components

載せたあとにする作業は、見出し・CTA・画像の差し替えだけです。動きの数値には触れず、文章と画像を先に変えると崩れません。

反対に、ヒーローそのものが製品の中心という場合もあります。1pxまで自分で制御したいなら、Motion で書く方が向いています。

ヒーローセクションのアニメーションでよくある質問

  • 入場とホバー、ゆっくり動く背景なら CSS だけで作れます。

    スクロール量に合わせた変化が必要なら、Motion などのライブラリを使います。どちらの場合も、ページ全体をブラウザで動く部品にする必要はありません。

まとめ:Next.js のヒーローセクションに動きを付ける手順

  • ヒーローは「入場・背景・ホバー」のうち2つまで動かす

  • 入場は CSS のアニメーション1つと、0.08秒ずつの遅れで作れる

  • 背景の光は位置と大きさだけを、18秒ほどかけてゆっくり動かす

  • スクロールに合わせた動きは Motion で作り、ブラウザで動かす印はヒーローのファイルだけに書く

  • 動きを減らす設定と、最初の写真を隠さないことを公開前に確認する

まずは CSS の入場だけを付けて公開し、物足りなければ背景とパララックスを足していくのが早道です。

見出しの文字を1文字ずつ見せる動きは、次の記事で解説しています。https://design-layer.com/ja/articles/nextjs-text-reveal-animation-guide

Motion の基本から学びたい場合はこちらです。https://design-layer.com/ja/articles/nextjs-framer-motion-guide

関連ガイド

【Next.js】ヒーローセクションに入場と背景のアニメーションを付ける方法を解説 | DesignLayer