無限マーキー
トラックを複製しtranslateX(-50%)で継ぎ目のない横スクロールループを実現。お知らせ帯やロゴ流しに使えます。
ライブデモ
使用例(お題: カフェ MOON BREW)
この技法を「カフェ MOON BREW」というテーマのダミーサイトで実際に使った例です。
HTML
<!-- MOON BREW:カフェのお知らせ帯を無限マーキーで流す -->
<section class="mb-stage">
<header class="mb-nav">
<div class="mb-brand"><span class="mb-cup">☕</span> MOON BREW</div>
<nav class="mb-menu"><span>MENU</span><span>STORE</span><span>NEWS</span></nav>
</header>
<!-- お知らせ帯:トラックを複製して継ぎ目なくループ -->
<div class="mb-marquee" id="mbMarquee" aria-label="お知らせ">
<div class="mb-track" id="mbTrack">
<span class="mb-item"><b>NEW</b> 季節限定「焙煎ハニーラテ」新登場</span>
<span class="mb-dot">●</span>
<span class="mb-item">本日 18時まで 豆20%OFF</span>
<span class="mb-dot">●</span>
<span class="mb-item">月見テラス席 予約受付中</span>
<span class="mb-dot">●</span>
<span class="mb-item">朝7時オープン モーニング全品+クッキー</span>
<span class="mb-dot">●</span>
</div>
</div>
<div class="mb-hero">
<img class="mb-photo" src="https://picsum.photos/360/200?random=41" alt="本日のコーヒー">
<div class="mb-card">
<p class="mb-tag">本日のおすすめ</p>
<h2 class="mb-h">焙煎ハニーラテ</h2>
<p class="mb-desc">深煎り豆の余韻に、信州産はちみつの甘み。<br>月明かりのような、まろやかな一杯。</p>
<div class="mb-price">¥620 <button class="mb-order" type="button">注文する</button></div>
</div>
</div>
</section>
CSS
/* MOON BREW:お知らせ帯の無限マーキー */
:root {
--cream: #f5ede1;
--brown: #2b1d12;
--amber: #c98a3b;
}
* { box-sizing: border-box; }
body {
margin: 0;
height: 400px;
font-family: "Hiragino Mincho ProN", "Yu Mincho", "Segoe UI", serif;
background: var(--cream);
color: var(--brown);
}
.mb-stage { height: 400px; display: flex; flex-direction: column; }
.mb-nav {
display: flex; align-items: center; justify-content: space-between;
padding: 12px 20px;
background: var(--cream);
}
.mb-brand { font-size: 16px; font-weight: 800; letter-spacing: 0.08em; }
.mb-cup { font-size: 15px; }
.mb-menu { display: flex; gap: 16px; font-size: 11px; letter-spacing: 0.12em; color: #6b5640; }
/* マーキー帯 */
.mb-marquee {
overflow: hidden;
white-space: nowrap;
background: var(--brown);
color: var(--cream);
padding: 9px 0;
-webkit-mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
}
/* トラックを translateX(-50%) で流す(複製で継ぎ目なし) */
.mb-track {
display: inline-flex;
align-items: center;
gap: 22px;
padding-left: 22px;
animation: mb-scroll 18s linear infinite;
will-change: transform;
}
.mb-marquee:hover .mb-track { animation-play-state: paused; }
@keyframes mb-scroll {
to { transform: translateX(-50%); }
}
.mb-item { font-size: 12px; letter-spacing: 0.05em; }
.mb-item b { color: var(--amber); margin-right: 4px; font-weight: 800; }
.mb-dot { font-size: 6px; color: var(--amber); }
/* ヒーロー */
.mb-hero { flex: 1; display: flex; gap: 16px; padding: 18px 20px; align-items: center; }
.mb-photo {
width: 180px; height: 200px;
object-fit: cover;
border-radius: 14px;
box-shadow: 0 16px 34px -14px rgba(43, 29, 18, 0.5);
}
.mb-card { flex: 1; }
.mb-tag {
display: inline-block;
font-size: 10px; letter-spacing: 0.14em;
padding: 3px 10px; border-radius: 999px;
background: rgba(201, 138, 59, 0.16); color: #9a6420;
margin: 0 0 10px;
}
.mb-h { margin: 0 0 10px; font-size: 24px; font-weight: 800; }
.mb-desc { margin: 0 0 16px; font-size: 13px; line-height: 1.8; color: #5e4a36; }
.mb-price { display: flex; align-items: center; gap: 14px; font-size: 20px; font-weight: 800; color: var(--amber); }
.mb-order {
font-family: inherit; font-size: 12px; font-weight: 700;
padding: 9px 18px; border: none; border-radius: 999px; cursor: pointer;
color: var(--cream); background: var(--brown);
transition: transform 0.1s ease, background 0.2s ease;
}
.mb-order:hover { background: #44301f; }
.mb-order:active { transform: scale(0.97); }
@media (prefers-reduced-motion: reduce) {
.mb-track { animation: none; }
}
JavaScript
// MOON BREW:トラック内の要素群を複製し、translateX(-50%) で継ぎ目なくループ
(() => {
const track = document.getElementById("mbTrack");
if (!track) return; // null安全
// 現在の子要素をまるごと複製して後ろに連結
// → トラック幅が2倍になり、-50%移動で元の並びと完全に重なる
const items = Array.from(track.children);
items.forEach((node) => {
const clone = node.cloneNode(true);
clone.setAttribute("aria-hidden", "true");
track.appendChild(clone);
});
})();
コード
HTML
<!-- 無限マーキー:途切れないループ流れ。ホバーで一時停止できる -->
<div class="marq-stage">
<div class="marq-headline">
<span class="marq-badge">LIVE</span>
Trending Now
</div>
<!-- 上段:左へ流れる -->
<div class="marquee" data-marquee>
<div class="marquee-track">
<span class="chip">★ デザイン</span><span class="chip">⚡ アニメーション</span>
<span class="chip">◆ CSS</span><span class="chip">✦ UI/UX</span>
<span class="chip">● トランジション</span><span class="chip">▲ モーション</span>
</div>
</div>
<!-- 下段:右へ流れる(速度ちがい) -->
<div class="marquee marquee--reverse marquee--slow" data-marquee>
<div class="marquee-track">
<span class="chip alt">JavaScript</span><span class="chip alt">SVG</span>
<span class="chip alt">Canvas</span><span class="chip alt">WebGL</span>
<span class="chip alt">Easing</span><span class="chip alt">Keyframes</span>
</div>
</div>
</div>
CSS
/* 暗い背景に発光チップが流れる */
* { box-sizing: border-box; }
body {
margin: 0;
min-height: 360px;
display: grid;
align-content: center;
gap: 18px;
font-family: "Segoe UI", "Hiragino Sans", "Yu Gothic UI", system-ui, sans-serif;
background: linear-gradient(160deg, #0e1020 0%, #181a33 100%);
color: #eef0ff;
overflow: hidden;
}
.marq-stage { display: grid; gap: 16px; }
.marq-headline {
text-align: center;
font-size: 18px;
font-weight: 700;
letter-spacing: .04em;
display: flex; align-items: center; justify-content: center; gap: 10px;
}
.marq-badge {
font-size: 11px; font-weight: 800; letter-spacing: .12em;
padding: 3px 8px; border-radius: 6px;
background: #ff4d6d; color: #fff;
box-shadow: 0 0 14px rgba(255, 77, 109, .6);
}
/* マーキー枠:はみ出しを隠し、左右をフェード */
.marquee {
overflow: hidden;
-webkit-mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
}
/* トラックを2倍幅にして同内容を複製→-50%で継ぎ目なしループ */
.marquee-track {
display: flex;
width: max-content;
gap: 14px;
padding: 4px 7px;
animation: marqScroll 18s linear infinite;
}
.marquee--slow .marquee-track { animation-duration: 26s; }
.marquee--reverse .marquee-track { animation-direction: reverse; }
@keyframes marqScroll {
from { transform: translateX(0); }
to { transform: translateX(-50%); }
}
/* ホバーで全マーキー停止 */
.marquee:hover .marquee-track { animation-play-state: paused; }
.chip {
flex: none;
padding: 10px 18px;
border-radius: 999px;
font-size: 14px; font-weight: 600;
white-space: nowrap;
background: rgba(124, 139, 255, 0.16);
border: 1px solid rgba(124, 139, 255, 0.32);
color: #dfe3ff;
}
.chip.alt {
background: rgba(109, 240, 194, 0.12);
border-color: rgba(109, 240, 194, 0.34);
color: #c9ffe9;
}
@media (prefers-reduced-motion: reduce) {
.marquee-track { animation: none; }
}
JavaScript
// 無限マーキー:トラック内容を複製し、-50%移動で継ぎ目のないループにする
(() => {
const marquees = document.querySelectorAll('[data-marquee]');
if (!marquees.length) return; // null安全
marquees.forEach((marq) => {
const track = marq.querySelector('.marquee-track');
if (!track) return;
// 元の子要素を丸ごと複製して連結(合計幅が2倍→-50%で元位置に戻る)
const clone = track.cloneNode(true);
clone.setAttribute('aria-hidden', 'true');
track.append(...Array.from(clone.children));
});
})();
🤖 AIエージェント用プロンプト
このままコピーしてAIに貼り付け「追加する場所」だけ書き換えればOK
あなたは熟練のフロントエンドエンジニアです。私のWebサイトに「無限マーキー」の効果を追加してください。
# 追加してほしい効果
無限マーキー(アニメーション & トランジション)
トラックを複製しtranslateX(-50%)で継ぎ目のない横スクロールループを実現。お知らせ帯やロゴ流しに使えます。
# 追加する場所
👉【ここに対象箇所を記入:例「トップのヒーローセクション」「お問い合わせボタン」「記事カードの一覧」など】
# 参考実装(この見た目・挙動を再現してください)
【HTML】
<!-- 無限マーキー:途切れないループ流れ。ホバーで一時停止できる -->
<div class="marq-stage">
<div class="marq-headline">
<span class="marq-badge">LIVE</span>
Trending Now
</div>
<!-- 上段:左へ流れる -->
<div class="marquee" data-marquee>
<div class="marquee-track">
<span class="chip">★ デザイン</span><span class="chip">⚡ アニメーション</span>
<span class="chip">◆ CSS</span><span class="chip">✦ UI/UX</span>
<span class="chip">● トランジション</span><span class="chip">▲ モーション</span>
</div>
</div>
<!-- 下段:右へ流れる(速度ちがい) -->
<div class="marquee marquee--reverse marquee--slow" data-marquee>
<div class="marquee-track">
<span class="chip alt">JavaScript</span><span class="chip alt">SVG</span>
<span class="chip alt">Canvas</span><span class="chip alt">WebGL</span>
<span class="chip alt">Easing</span><span class="chip alt">Keyframes</span>
</div>
</div>
</div>
【CSS】
/* 暗い背景に発光チップが流れる */
* { box-sizing: border-box; }
body {
margin: 0;
min-height: 360px;
display: grid;
align-content: center;
gap: 18px;
font-family: "Segoe UI", "Hiragino Sans", "Yu Gothic UI", system-ui, sans-serif;
background: linear-gradient(160deg, #0e1020 0%, #181a33 100%);
color: #eef0ff;
overflow: hidden;
}
.marq-stage { display: grid; gap: 16px; }
.marq-headline {
text-align: center;
font-size: 18px;
font-weight: 700;
letter-spacing: .04em;
display: flex; align-items: center; justify-content: center; gap: 10px;
}
.marq-badge {
font-size: 11px; font-weight: 800; letter-spacing: .12em;
padding: 3px 8px; border-radius: 6px;
background: #ff4d6d; color: #fff;
box-shadow: 0 0 14px rgba(255, 77, 109, .6);
}
/* マーキー枠:はみ出しを隠し、左右をフェード */
.marquee {
overflow: hidden;
-webkit-mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
}
/* トラックを2倍幅にして同内容を複製→-50%で継ぎ目なしループ */
.marquee-track {
display: flex;
width: max-content;
gap: 14px;
padding: 4px 7px;
animation: marqScroll 18s linear infinite;
}
.marquee--slow .marquee-track { animation-duration: 26s; }
.marquee--reverse .marquee-track { animation-direction: reverse; }
@keyframes marqScroll {
from { transform: translateX(0); }
to { transform: translateX(-50%); }
}
/* ホバーで全マーキー停止 */
.marquee:hover .marquee-track { animation-play-state: paused; }
.chip {
flex: none;
padding: 10px 18px;
border-radius: 999px;
font-size: 14px; font-weight: 600;
white-space: nowrap;
background: rgba(124, 139, 255, 0.16);
border: 1px solid rgba(124, 139, 255, 0.32);
color: #dfe3ff;
}
.chip.alt {
background: rgba(109, 240, 194, 0.12);
border-color: rgba(109, 240, 194, 0.34);
color: #c9ffe9;
}
@media (prefers-reduced-motion: reduce) {
.marquee-track { animation: none; }
}
【JavaScript】
// 無限マーキー:トラック内容を複製し、-50%移動で継ぎ目のないループにする
(() => {
const marquees = document.querySelectorAll('[data-marquee]');
if (!marquees.length) return; // null安全
marquees.forEach((marq) => {
const track = marq.querySelector('.marquee-track');
if (!track) return;
// 元の子要素を丸ごと複製して連結(合計幅が2倍→-50%で元位置に戻る)
const clone = track.cloneNode(true);
clone.setAttribute('aria-hidden', 'true');
track.append(...Array.from(clone.children));
});
})();
# 外部ライブラリ
なし(追加ライブラリ不要)
# 守ってほしいこと
- 既存のHTML構造・レイアウト・デザインを壊さないこと。必要に応じてクラス名・色・サイズを私のサイトに合わせて調整してよい。
- クラス名やidが既存と衝突しないよう、必要なら接頭辞で名前空間を分けること。
- レスポンシブ対応と prefers-reduced-motion への配慮を入れること。
- 私のサイトのフレームワーク(React / Vue / 素のHTML など)に合わせて実装すること。不明な場合は素のHTML/CSS/JSで提示し、組み込み手順も説明すること。
- 変更後の確認手順も簡潔に教えてください。