Ken Burns スライドショー

静止画をゆっくりズーム&パンしながらクロスフェードさせる映画的スライドショー。ヒーローバナーや背景演出に最適です。

#css#animation#slideshow#js

ライブデモ

使用例(お題: アイドルグループ Sakura)

この技法を「アイドルグループ Sakura」というテーマのダミーサイトで実際に使った例です。

HTML
<!-- Sakura:ライブツアー告知ヒーロー(Ken Burns スライドショー) -->
<section class="sk-kb">
  <!-- 各スチルがズーム&パンしながらクロスフェード -->
  <div class="sk-kb__slide is-active" style="--img:url('https://picsum.photos/1000/700?random=41')"></div>
  <div class="sk-kb__slide" style="--img:url('https://picsum.photos/1000/700?random=42')"></div>
  <div class="sk-kb__slide" style="--img:url('https://picsum.photos/1000/700?random=43')"></div>

  <!-- 桜の花びら -->
  <span class="sk-kb__petal sk-kb__petal--1">❀</span>
  <span class="sk-kb__petal sk-kb__petal--2">❀</span>

  <!-- ヒーローコピー -->
  <div class="sk-kb__overlay">
    <p class="sk-kb__kicker">SAKURA SPRING TOUR 2026</p>
    <h1 class="sk-kb__title">満開、君に届け。</h1>
    <p class="sk-kb__lead">全国5都市をめぐる春のホールツアー、開幕。</p>
    <a class="sk-kb__btn" href="#">ツアー日程を見る</a>
  </div>

  <div class="sk-kb__dots" role="tablist" aria-label="スライド"></div>
</section>
CSS
/* Sakura:ライブツアー告知ヒーロー(Ken Burns) */
:root {
  --pink: #ffd1e0;
  --deep: #5a2e44;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  height: 400px;
  font-family: "Hiragino Kaku Gothic ProN", system-ui, sans-serif;
  overflow: hidden;
}

.sk-kb {
  position: relative;
  width: 100%;
  height: 400px;
  overflow: hidden;
  background: var(--deep);
}

/* スライド:背景画像をズーム&パン */
.sk-kb__slide {
  position: absolute;
  inset: 0;
  background: var(--img) center/cover no-repeat;
  opacity: 0;
  transform: scale(1.05);
}
.sk-kb__slide.is-active {
  opacity: 1;
  animation: skKenBurns 6s ease-out forwards;
}
@keyframes skKenBurns {
  0% { opacity: 0; transform: scale(1.18) translate(2%, -1%); }
  12% { opacity: 1; }
  100% { opacity: 1; transform: scale(1.02) translate(-2%, 1%); }
}

/* 桜ピンクのフィルター+暗幕 */
.sk-kb::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  background:
    linear-gradient(180deg, rgba(90,46,68,0.15) 0%, rgba(90,46,68,0.7) 100%),
    radial-gradient(120% 90% at 20% 100%, rgba(255,150,185,0.45), transparent 60%);
  pointer-events: none;
}

/* 花びら */
.sk-kb__petal {
  position: absolute;
  z-index: 2;
  color: rgba(255,209,224,0.85);
  text-shadow: 0 2px 6px rgba(0,0,0,0.3);
  pointer-events: none;
  animation: skFall 7s linear infinite;
}
.sk-kb__petal--1 { top: -20px; left: 18%; font-size: 22px; }
.sk-kb__petal--2 { top: -20px; left: 72%; font-size: 16px; animation-duration: 9s; animation-delay: -3s; }
@keyframes skFall {
  0% { transform: translateY(-20px) rotate(0); opacity: 0; }
  15% { opacity: 1; }
  100% { transform: translateY(420px) rotate(360deg); opacity: 0; }
}

/* ヒーローコピー */
.sk-kb__overlay {
  position: absolute;
  left: 36px;
  bottom: 40px;
  z-index: 3;
  color: #fff;
  max-width: 360px;
}
.sk-kb__kicker {
  margin: 0 0 8px;
  font-size: 10px;
  letter-spacing: 0.25em;
  color: var(--pink);
}
.sk-kb__title {
  margin: 0 0 8px;
  font-size: 34px;
  font-weight: 800;
  line-height: 1.3;
  font-family: "Hiragino Mincho ProN", "Yu Mincho", serif;
  text-shadow: 0 3px 12px rgba(0,0,0,0.4);
}
.sk-kb__lead { margin: 0 0 16px; font-size: 13px; line-height: 1.8; color: rgba(255,255,255,0.92); }
.sk-kb__btn {
  display: inline-block;
  padding: 11px 24px;
  border-radius: 999px;
  background: var(--pink);
  color: var(--deep);
  font-size: 13px;
  font-weight: 700;
  text-decoration: none;
  box-shadow: 0 8px 20px rgba(255,150,185,0.5);
  transition: transform 0.2s ease;
}
.sk-kb__btn:hover { transform: translateY(-2px); }

/* インジケーター */
.sk-kb__dots {
  position: absolute;
  right: 24px;
  bottom: 24px;
  z-index: 3;
  display: flex;
  gap: 8px;
}
.sk-kb__dot {
  width: 9px;
  height: 9px;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: rgba(255,255,255,0.4);
  cursor: pointer;
  transition: background 0.2s ease, transform 0.2s ease;
}
.sk-kb__dot[aria-selected="true"] { background: var(--pink); transform: scale(1.3); }

@media (prefers-reduced-motion: reduce) {
  .sk-kb__slide.is-active { animation: none; }
  .sk-kb__petal { animation: none; opacity: 0; }
  .sk-kb__btn, .sk-kb__dot { transition: none; }
}
JavaScript
// スライドを一定間隔で切り替え、Ken Burns アニメを再トリガーする
const slides = Array.from(document.querySelectorAll(".sk-kb__slide"));
const dotsWrap = document.querySelector(".sk-kb__dots");
let index = 0;
let timer = null;

if (slides.length && dotsWrap) {
  // ドット生成
  const dots = slides.map((_, i) => {
    const b = document.createElement("button");
    b.className = "sk-kb__dot";
    b.setAttribute("role", "tab");
    b.setAttribute("aria-label", `スライド ${i + 1}`);
    b.addEventListener("click", () => go(i));
    dotsWrap.appendChild(b);
    return b;
  });

  // 指定スライドを表示
  const go = (next) => {
    slides[index].classList.remove("is-active");
    index = (next + slides.length) % slides.length;
    const el = slides[index];
    el.classList.remove("is-active");
    void el.offsetWidth; // reflow でアニメ再生を保証
    el.classList.add("is-active");
    dots.forEach((d, i) => d.setAttribute("aria-selected", String(i === index)));
    restart();
  };

  // 自動送り
  const restart = () => {
    if (timer) clearInterval(timer);
    timer = setInterval(() => go(index + 1), 5000);
  };

  dots[0].setAttribute("aria-selected", "true");
  restart();
}

コード

HTML
<!-- Ken Burns: ゆっくりズーム&パンするスライドショー -->
<div class="kb">
  <!-- 各スライドが順番にズームしながらクロスフェード -->
  <div class="kb__slide is-active" style="--img:url('https://picsum.photos/id/1018/1000/700')"></div>
  <div class="kb__slide" style="--img:url('https://picsum.photos/id/1039/1000/700')"></div>
  <div class="kb__slide" style="--img:url('https://picsum.photos/id/1043/1000/700')"></div>

  <div class="kb__overlay">
    <p class="kb__kicker">CINEMATIC</p>
    <h2 class="kb__title">Ken Burns Effect</h2>
  </div>

  <!-- インジケーター -->
  <div class="kb__dots" role="tablist" aria-label="スライド"></div>
</div>
CSS
* { box-sizing: border-box; }
body {
  margin: 0;
  min-height: 100vh;
  display: grid;
  place-items: center;
  background: #000;
  font-family: "Segoe UI", system-ui, sans-serif;
}

/* ビューポート枠 */
.kb {
  position: relative;
  width: 100%;
  height: 360px;
  overflow: hidden;
  background: #111;
}

/* スライド: 背景画像を拡大表示し、active のときだけ動かす */
.kb__slide {
  position: absolute;
  inset: 0;
  background-image: var(--img);
  background-size: cover;
  background-position: center;
  opacity: 0;
  transform: scale(1.05);
  transition: opacity 1.4s ease;
}
.kb__slide.is-active {
  opacity: 1;
  /* ゆっくりズーム&パン */
  animation: kenburns 8s ease-in-out forwards;
}

@keyframes kenburns {
  0%   { transform: scale(1.05) translate(0, 0); }
  100% { transform: scale(1.28) translate(-3%, -2%); }
}

/* 暗いビネット + テキスト */
.kb::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(to top, rgba(0, 0, 0, .7), transparent 55%);
  pointer-events: none;
}
.kb__overlay {
  position: absolute;
  left: 32px;
  bottom: 28px;
  z-index: 2;
  color: #fff;
  text-shadow: 0 2px 12px rgba(0, 0, 0, .6);
}
.kb__kicker {
  margin: 0 0 4px;
  font-size: 12px;
  letter-spacing: .4em;
  color: #ffd479;
  font-weight: 700;
}
.kb__title {
  margin: 0;
  font-size: clamp(24px, 5vw, 40px);
  font-weight: 800;
  letter-spacing: .02em;
}

/* ドット */
.kb__dots {
  position: absolute;
  right: 22px;
  bottom: 22px;
  z-index: 3;
  display: flex;
  gap: 8px;
}
.kb__dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  border: none;
  background: rgba(255, 255, 255, .4);
  cursor: pointer;
  padding: 0;
  transition: background .3s ease, transform .3s ease;
}
.kb__dot[aria-selected="true"] { background: #fff; transform: scale(1.3); }

@media (prefers-reduced-motion: reduce) {
  .kb__slide.is-active { animation: none; transform: scale(1.1); }
  .kb__slide { transition: opacity .4s ease; }
}
JavaScript
// スライドを一定間隔で切り替え、Ken Burns アニメを再トリガーする
const slides = Array.from(document.querySelectorAll(".kb__slide"));
const dotsWrap = document.querySelector(".kb__dots");
let index = 0;
let timer = null;

if (slides.length && dotsWrap) {
  // ドットを生成
  const dots = slides.map((_, i) => {
    const b = document.createElement("button");
    b.className = "kb__dot";
    b.setAttribute("role", "tab");
    b.setAttribute("aria-label", `スライド ${i + 1}`);
    b.addEventListener("click", () => go(i));
    dotsWrap.appendChild(b);
    return b;
  });

  // 指定スライドを表示
  const go = (next) => {
    slides[index].classList.remove("is-active");
    index = (next + slides.length) % slides.length;
    // animation を確実に再生させるため reflow を挟む
    const el = slides[index];
    el.classList.remove("is-active");
    void el.offsetWidth;
    el.classList.add("is-active");
    dots.forEach((d, i) => d.setAttribute("aria-selected", String(i === index)));
    restart();
  };

  // 自動送りタイマー
  const restart = () => {
    if (timer) clearInterval(timer);
    timer = setInterval(() => go(index + 1), 5000);
  };

  // 初期表示
  dots[0].setAttribute("aria-selected", "true");
  restart();
}

🤖 AIエージェント用プロンプト

このままコピーしてAIに貼り付け「追加する場所」だけ書き換えればOK
あなたは熟練のフロントエンドエンジニアです。私のWebサイトに「Ken Burns スライドショー」の効果を追加してください。

# 追加してほしい効果
Ken Burns スライドショー(画像エフェクト)
静止画をゆっくりズーム&パンしながらクロスフェードさせる映画的スライドショー。ヒーローバナーや背景演出に最適です。

# 追加する場所
👉【ここに対象箇所を記入:例「トップのヒーローセクション」「お問い合わせボタン」「記事カードの一覧」など】

# 参考実装(この見た目・挙動を再現してください)
【HTML】
<!-- Ken Burns: ゆっくりズーム&パンするスライドショー -->
<div class="kb">
  <!-- 各スライドが順番にズームしながらクロスフェード -->
  <div class="kb__slide is-active" style="--img:url('https://picsum.photos/id/1018/1000/700')"></div>
  <div class="kb__slide" style="--img:url('https://picsum.photos/id/1039/1000/700')"></div>
  <div class="kb__slide" style="--img:url('https://picsum.photos/id/1043/1000/700')"></div>

  <div class="kb__overlay">
    <p class="kb__kicker">CINEMATIC</p>
    <h2 class="kb__title">Ken Burns Effect</h2>
  </div>

  <!-- インジケーター -->
  <div class="kb__dots" role="tablist" aria-label="スライド"></div>
</div>

【CSS】
* { box-sizing: border-box; }
body {
  margin: 0;
  min-height: 100vh;
  display: grid;
  place-items: center;
  background: #000;
  font-family: "Segoe UI", system-ui, sans-serif;
}

/* ビューポート枠 */
.kb {
  position: relative;
  width: 100%;
  height: 360px;
  overflow: hidden;
  background: #111;
}

/* スライド: 背景画像を拡大表示し、active のときだけ動かす */
.kb__slide {
  position: absolute;
  inset: 0;
  background-image: var(--img);
  background-size: cover;
  background-position: center;
  opacity: 0;
  transform: scale(1.05);
  transition: opacity 1.4s ease;
}
.kb__slide.is-active {
  opacity: 1;
  /* ゆっくりズーム&パン */
  animation: kenburns 8s ease-in-out forwards;
}

@keyframes kenburns {
  0%   { transform: scale(1.05) translate(0, 0); }
  100% { transform: scale(1.28) translate(-3%, -2%); }
}

/* 暗いビネット + テキスト */
.kb::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(to top, rgba(0, 0, 0, .7), transparent 55%);
  pointer-events: none;
}
.kb__overlay {
  position: absolute;
  left: 32px;
  bottom: 28px;
  z-index: 2;
  color: #fff;
  text-shadow: 0 2px 12px rgba(0, 0, 0, .6);
}
.kb__kicker {
  margin: 0 0 4px;
  font-size: 12px;
  letter-spacing: .4em;
  color: #ffd479;
  font-weight: 700;
}
.kb__title {
  margin: 0;
  font-size: clamp(24px, 5vw, 40px);
  font-weight: 800;
  letter-spacing: .02em;
}

/* ドット */
.kb__dots {
  position: absolute;
  right: 22px;
  bottom: 22px;
  z-index: 3;
  display: flex;
  gap: 8px;
}
.kb__dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  border: none;
  background: rgba(255, 255, 255, .4);
  cursor: pointer;
  padding: 0;
  transition: background .3s ease, transform .3s ease;
}
.kb__dot[aria-selected="true"] { background: #fff; transform: scale(1.3); }

@media (prefers-reduced-motion: reduce) {
  .kb__slide.is-active { animation: none; transform: scale(1.1); }
  .kb__slide { transition: opacity .4s ease; }
}

【JavaScript】
// スライドを一定間隔で切り替え、Ken Burns アニメを再トリガーする
const slides = Array.from(document.querySelectorAll(".kb__slide"));
const dotsWrap = document.querySelector(".kb__dots");
let index = 0;
let timer = null;

if (slides.length && dotsWrap) {
  // ドットを生成
  const dots = slides.map((_, i) => {
    const b = document.createElement("button");
    b.className = "kb__dot";
    b.setAttribute("role", "tab");
    b.setAttribute("aria-label", `スライド ${i + 1}`);
    b.addEventListener("click", () => go(i));
    dotsWrap.appendChild(b);
    return b;
  });

  // 指定スライドを表示
  const go = (next) => {
    slides[index].classList.remove("is-active");
    index = (next + slides.length) % slides.length;
    // animation を確実に再生させるため reflow を挟む
    const el = slides[index];
    el.classList.remove("is-active");
    void el.offsetWidth;
    el.classList.add("is-active");
    dots.forEach((d, i) => d.setAttribute("aria-selected", String(i === index)));
    restart();
  };

  // 自動送りタイマー
  const restart = () => {
    if (timer) clearInterval(timer);
    timer = setInterval(() => go(index + 1), 5000);
  };

  // 初期表示
  dots[0].setAttribute("aria-selected", "true");
  restart();
}

# 外部ライブラリ
なし(追加ライブラリ不要)

# 守ってほしいこと
- 既存のHTML構造・レイアウト・デザインを壊さないこと。必要に応じてクラス名・色・サイズを私のサイトに合わせて調整してよい。
- クラス名やidが既存と衝突しないよう、必要なら接頭辞で名前空間を分けること。
- レスポンシブ対応と prefers-reduced-motion への配慮を入れること。
- 私のサイトのフレームワーク(React / Vue / 素のHTML など)に合わせて実装すること。不明な場合は素のHTML/CSS/JSで提示し、組み込み手順も説明すること。
- 変更後の確認手順も簡潔に教えてください。