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 の任意値クラスから呼び出せます。
@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 を既定で拒否します。
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秒以上流れ続けるマーキーには、一時停止ボタンも置いてください。
<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 で左右のグラデーションをかけると、ロゴが端で自然に消えていきます。
<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段が同じリズムで動く単調さも避けられます。
<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 程度にとどめ、暗い背景では白抜きのロゴを用意します。
完成したロゴマーキーをコピーして使う方法

端のフェードや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 で解説しています。




