Reactのロゴマーキーアニメーション(無限スクロール)

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

ロゴマーキーアニメーションは、同じロゴ列を2つ並べてCSSで左へ50%動かす無限スクロールです。継ぎ目は見えません。ReactとNext.jsでは、カルーセル用のライブラリは要りません。

ロゴの無限スクロールを途切れずに作る方法

1周したところで隙間が空く、またはロゴが跳ねるときは、2つの列の幅がそろっていません。同じロゴ列を2つ横に並べ、全体を左へ50%動かして繰り返します。2つ目の列が1つ目の位置に来た瞬間に戻るので、継ぎ目は見えません。

この記事のクラスは、Next.js 15.5、React 19、Tailwind CSS 3.4 で確認しています。マーキーはサーバーコンポーネントのままです。

CSS だけ

JavaScript のライブラリ

完成版をコピー

手に入るもの

この記事の無限スクロール

Swiper のような、1枚ずつ送るカルーセル

テンプレートショーケースマーキー。スクリーンショットの無限スクロール

ループ

複製した列を CSS で 50% 動かす

ライブラリのループ設定が必要

すでにループしている

依存

Next.js、React、Tailwind CSS

カルーセルのパッケージ

React、TypeScript、Tailwind CSS

向いているとき

ロゴを勝手に流したい

見る人が1枚ずつ送りたい

動きは作り済みがよい

この記事で実装するのは、CSS だけの列です。分かることは次のとおりです。

  • 継ぎ目が出ないロゴマーキーの基本コード

  • 隙間や跳ねが起きる原因と直し方

  • ホバーやキーボード操作で止める方法

  • 端のフェードや、2段で逆方向に流す応用

  • 動きを減らす設定とスクリーンリーダーへの対応

ロゴマーキーを CSS だけで作る理由

マーキーの動きは「一定の速さで横に流れ続ける」だけです。スクロール量やユーザー操作に合わせて計算する必要がないため、CSS の animation で十分に作れます。

JavaScript のライブラリを足すより、読み込みが軽くなります。

Next.js の App Router では、CSS アニメーションだけならサーバーコンポーネント(サーバーで組み立てる部品)のまま使えます。

"use client"(この部品はブラウザで動かす、という印)も不要です。ロゴ画像の最適化を next/image に任せつつ、ブラウザに送るコードを増やさずに済みます。

また、マーキーはページの主役ではありません。導入実績を「たくさんの会社が使っている」と静かに伝える場所です。

強い動きはヒーローに残し、マーキーは一定速度の横移動だけにすると、ページ全体のテンポが整います。

継ぎ目が出ないロゴマーキーの基本コード

まず、流れる動きを keyframes で定義します。0% の位置から、左へ 50% 移動するだけの動きです。

globals.css に書いておけば、Tailwind CSS の任意値クラスから呼び出せます。

app/globals.css
@keyframes marquee {
    from {
      transform: translateX(0);
    }
    to {
      transform: translateX(-50%);
    }
  }

同じロゴ列を2つ並べる

外枠に overflow-hidden を付け、その中に横並びのトラック(ロゴを載せて動かす帯)を置きます。トラックの中に同じロゴ列を2つ入れ、トラック全体を marquee で動かします。

w-max は、トラックの幅を中身の合計幅にするための指定です。

2つ目の列は見た目のためだけの複製なので、aria-hidden を付けてスクリーンリーダーに読ませません。同じ社名が2回読み上げられるのを防げます。

サンプルのロゴは PNG です。Next.js 15 の next/image は、unoptimized を付けない SVG を最適化しません。画像オプティマイザは SVG を既定で拒否します。

components/LogoMarquee.tsx
import Image from "next/image";
  
  const logos = [
    { name: "Acme", src: "/logos/acme.png" },
    { name: "Globex", src: "/logos/globex.png" },
    { name: "Initech", src: "/logos/initech.png" },
    { name: "Umbrella", src: "/logos/umbrella.png" },
    { name: "Hooli", src: "/logos/hooli.png" },
    { name: "Stark", src: "/logos/stark.png" },
  ];
  
  function LogoRow({ duplicate = false }: { duplicate?: boolean }) {
    return (
      <ul
        aria-hidden={duplicate || undefined}
        className={duplicate ? "flex shrink-0 items-center motion-reduce:hidden" : "flex shrink-0 items-center motion-reduce:w-full motion-reduce:flex-wrap motion-reduce:justify-center"}
      >
        {logos.map((logo) => (
          <li key={logo.name} className="px-8">
            <Image
              src={logo.src}
              alt={duplicate ? "" : logo.name}
              width={120}
              height={32}
              className="h-8 w-auto object-contain opacity-70"
            />
          </li>
        ))}
      </ul>
    );
  }
  
  export function LogoMarquee() {
    return (
      <section aria-label="導入企業" className="overflow-hidden py-12">
        <div className="flex w-max animate-[marquee_30s_linear_infinite] motion-reduce:w-full motion-reduce:animate-none">
          <LogoRow />
          <LogoRow duplicate />
        </div>
      </section>
    );
  }

ロゴの間隔は各ロゴの左右の余白で取る

ロゴの間隔を flex の gap で取ると、1つ目の列と2つ目の列の間にだけ余白が足りなくなります。その結果、50% 動かした位置が1列分とずれて、1周ごとに少し跳ねます。

上のコードのように、各ロゴに左右同じ padding(px-8)を付けてください。どの列も同じ幅になり、50% の移動がちょうど1列分になります。

ロゴマーキーをホバーやキーボード操作で止める

流れ続けるロゴは、読みたい人にとっては追いかけにくいものです。マウスを乗せたら止まるようにすると、気になる会社名をゆっくり確認できます。

CSS の animation-play-state を paused にするだけで止まります。

ロゴにリンクを付けている場合は、キーボードでフォーカスしたときも止めてください。focus-within を使うと、中のリンクにフォーカスがある間だけ止められます。

ホバーやフォーカスで止めるだけでは、WCAG 2.2.2 の「一時停止の仕組み」にはなりません。5秒以上流れ続けるマーキーには、一時停止ボタンも置いてください。

components/LogoMarquee.tsx(トラック部分)
<div className="flex w-max animate-[marquee_30s_linear_infinite] hover:[animation-play-state:paused] focus-within:[animation-play-state:paused] motion-reduce:w-full motion-reduce:animate-none">
    <LogoRow />
    <LogoRow duplicate />
  </div>

ロゴマーキーの応用:端のフェードと2段の逆方向

ロゴが枠の端でいきなり切れると、少し硬い印象になります。外枠に mask-image で左右のグラデーションをかけると、ロゴが端で自然に消えていきます。

components/LogoMarquee.tsx(外枠)
<section
    aria-label="導入企業"
    className="overflow-hidden py-12 [mask-image:linear-gradient(to_right,transparent,black_10%,black_90%,transparent)]"
  >
    {/* トラック */}
  </section>

2段目を逆方向に流す

ロゴが多い場合は2段に分け、2段目に animation-direction: reverse を付けると左右逆に流れます。速さを少し変えると、2段が同じリズムで動く単調さも避けられます。

tsx
<div className="flex w-max animate-[marquee_40s_linear_infinite] [animation-direction:reverse] motion-reduce:animate-none">
    <LogoRow />
    <LogoRow duplicate />
  </div>

ロゴマーキーで失敗しやすい4つのポイント

ロゴマーキーは小さなセクションですが、崩れると信頼を伝えるどころか、雑な印象を与えます。公開前に次の4点を確認してください。

ロゴが1周したところで隙間が空く

ロゴ列が1つしかないか、2つの列の幅がそろっていません。同じ配列を2回描画しているか、間隔を gap ではなく padding で取っているかを確認します。

ロゴが少なくて1列が画面幅より短い場合も隙間が出るので、配列を2〜3回つなげて1列を長くしてください。

ロゴの大きさがばらばら

ロゴ画像は会社ごとに余白や縦横比が違います。高さを h-8 などで固定し、幅は w-auto と object-contain で縦横比を保つと、潰れずにそろって見えます。

ロゴの流れる速さが速すぎる

社名を読む前に通り過ぎると、実績として伝わりません。1周 20〜40 秒が扱いやすい目安です。

ロゴの数が増えたら、同じ速さに見えるよう秒数も増やします。

コントラストが低いロゴが背景に沈む

ロゴをグレーで統一するときは、薄すぎる色に注意してください。明るい背景なら opacity は 0.6〜0.8 程度にとどめ、暗い背景では白抜きのロゴを用意します。

完成したロゴマーキーをコピーして使う方法

DesignLayer の「テンプレートショーケースマーキー」の詳細ページ。左でライブプレビューを確かめ、右の「Cursor 用にコピー」でソースをコピーできる
DesignLayer の「テンプレートショーケースマーキー」の詳細ページ。左でライブプレビューを確かめ、右の「Cursor 用にコピー」でソースをコピーできる

端のフェードや2段の逆方向に加え、ホバーでロゴが少し浮く演出まで含めると、CSS の調整だけで半日かかることがあります。見た目を先に決めたいときは、完成版をコピーします。

無限スクロールがすでに組んであるものは、テンプレートショーケースマーキー をコピーします。Safari 風の枠の中を、スクリーンショットが流れ続けます。見出しと各カードの画像を差し替え、Cursor や Claude に貼ります。顧客ロゴの列ではなく、画面のショーケースです。

ロゴ画像ではなく社名を出すなら、パートナー・シリンダー をコピーします。スクロールすると次の社名が手前に来て、ほかは薄いままです。ロゴマーキーアニメーションではありません。

閲覧とライブプレビューは無料で、カードの登録もいりません。無料アカウントでは、無料サンプル10個を回数制限なくコピーでき、動画プロンプトは月1回です。カタログ全体は30日ビルドパス、Lifetime、Plus です。https://design-layer.com/ja/components

ロゴマーキーについてよくある質問

ロゴマーキーの実装で、よく出る質問をまとめました。

  • 作れます。この記事のマーキーは CSS アニメーションだけで動くため、"use client" は不要です。

    ドラッグで動かすなど、JavaScript が必要な機能を足すときだけ、ブラウザで動く部品にします。

まとめ:Next.js でロゴマーキーを作る手順

  • 同じロゴ列を2つ並べ、全体を左へ 50% 動かして繰り返す

  • ロゴの間隔は各ロゴの左右の余白(padding)で取り、跳ねを防ぐ

  • ロゴは高さを固定し、1周 20〜40 秒の速さで流す

  • マウスを乗せたときとキーボードで選んだときに止め、一時停止ボタンも置く

  • 複製の列は、読み上げの対象から外す

  • 動きを減らす設定では、流れない一覧に切り替える

ロゴマーキーはヒーローの直後に置くと、続く説明を信頼して読んでもらいやすくなります。ヒーローの作り方は https://design-layer.com/ja/articles/nextjs-animated-hero-section-guide 、その下に置くお客様の声は https://design-layer.com/ja/articles/nextjs-testimonial-section-guide で解説しています。

関連ガイド