左右交互タイムライン

中央の縦線を挟んでカードが左右交互に並ぶ沿革タイムライン。それぞれが逆方向からふわっと現れ、狭い画面では片側寄せの1列表示に切り替わります。

#css#timeline

ライブデモ

コード

HTML
<!-- 左右交互タイムライン: 中央の縦線を挟んでカードが左右へ交互に並ぶ -->
<section class="tla">
  <div class="tla__card">
    <p class="tla__eyebrow">COMPANY HISTORY</p>
    <h2 class="tla__title">会社沿革</h2>

    <div class="tla__scroll" tabindex="0" role="region" aria-label="会社の沿革(スクロールで続きを表示)">
      <ol class="tla__list">
        <li class="tla__item">
          <div class="tla__content">
            <time class="tla__date">2019年</time>
            <h3 class="tla__heading">設立</h3>
            <p class="tla__desc">東京の小さなオフィスで、3名のメンバーとともに創業しました。</p>
          </div>
          <span class="tla__dot" aria-hidden="true"></span>
        </li>
        <li class="tla__item">
          <div class="tla__content">
            <time class="tla__date">2020年</time>
            <h3 class="tla__heading">初出資</h3>
            <p class="tla__desc">エンジェル投資家より資金を調達し、開発体制を強化しました。</p>
          </div>
          <span class="tla__dot" aria-hidden="true"></span>
        </li>
        <li class="tla__item">
          <div class="tla__content">
            <time class="tla__date">2021年</time>
            <h3 class="tla__heading">初の海外拠点</h3>
            <p class="tla__desc">シンガポールに拠点を新設し、アジア市場への足がかりを築きました。</p>
          </div>
          <span class="tla__dot" aria-hidden="true"></span>
        </li>
        <li class="tla__item">
          <div class="tla__content">
            <time class="tla__date">2022年</time>
            <h3 class="tla__heading">累計利用者50万人</h3>
            <p class="tla__desc">サービス開始から3年で、利用者数が50万人を突破しました。</p>
          </div>
          <span class="tla__dot" aria-hidden="true"></span>
        </li>
        <li class="tla__item">
          <div class="tla__content">
            <time class="tla__date">2023年</time>
            <h3 class="tla__heading">株式上場</h3>
            <p class="tla__desc">東京証券取引所グロース市場に株式を上場しました。</p>
          </div>
          <span class="tla__dot" aria-hidden="true"></span>
        </li>
        <li class="tla__item">
          <div class="tla__content">
            <time class="tla__date">2024年</time>
            <h3 class="tla__heading">新社屋へ移転</h3>
            <p class="tla__desc">渋谷に新オフィスを構え、従業員数は200名を超えました。</p>
          </div>
          <span class="tla__dot" aria-hidden="true"></span>
        </li>
      </ol>
    </div>
  </div>
</section>
CSS
/* 左右交互タイムライン: 中央線を挟んでカードが左右交互に並ぶ沿革 */
* { box-sizing: border-box; }
body {
  margin: 0;
  min-height: 100vh;
  display: grid;
  place-items: center;
  padding: 30px 16px;
  font-family: "Segoe UI", "Hiragino Kaku Gothic ProN", "Yu Gothic UI", system-ui, sans-serif;
  background: radial-gradient(130% 110% at 50% -10%, #241b3d 0%, #12101e 55%, #0c0a14 100%);
  color: #f1eefb;
}

/* ルート: 全幅 */
.tla { width: 100%; display: grid; place-items: center; }

.tla__card {
  width: min(680px, 100%);
  background: rgba(255, 255, 255, .035);
  border: 1px solid rgba(255, 255, 255, .09);
  border-radius: 20px;
  padding: 28px 26px 8px;
  box-shadow: 0 30px 60px -30px rgba(0, 0, 0, .65);
}

.tla__eyebrow {
  margin: 0 0 6px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .24em;
  color: #d9a4ff;
  text-align: center;
}
.tla__title {
  margin: 0 0 22px;
  font-size: clamp(19px, 3vw, 23px);
  font-weight: 800;
  text-align: center;
  letter-spacing: -.01em;
}

.tla__scroll {
  max-height: 380px;
  overflow-y: auto;
  scrollbar-width: thin;
  scrollbar-color: rgba(217, 164, 255, .4) transparent;
}
.tla__scroll::-webkit-scrollbar { width: 6px; }
.tla__scroll::-webkit-scrollbar-thumb { background: rgba(217, 164, 255, .35); border-radius: 999px; }

.tla__list {
  position: relative;
  list-style: none;
  margin: 0;
  padding: 4px 4px 22px;
}
/* 中央の縦線 */
.tla__list::before {
  content: "";
  position: absolute;
  left: 50%; top: 4px; bottom: 10px;
  width: 2px;
  transform: translateX(-50%);
  background: linear-gradient(180deg, #d9a4ff, #7c8bff 55%, rgba(124, 139, 255, .12));
  border-radius: 2px;
}

.tla__item {
  position: relative;
  display: grid;
  grid-template-columns: 1fr 36px 1fr;
  column-gap: 16px;
  align-items: start;
  padding-bottom: 26px;
  opacity: 0;
}
.tla__item:last-child { padding-bottom: 4px; }

.tla__dot {
  grid-column: 2;
  justify-self: center;
  margin-top: 5px;
  width: 12px; height: 12px;
  border-radius: 50%;
  background: linear-gradient(135deg, #d9a4ff, #7c8bff);
  box-shadow: 0 0 0 4px rgba(217, 164, 255, .16);
}

.tla__content { min-width: 0; }
.tla__date {
  display: block;
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: .06em;
  color: #b9a8e6;
  margin-bottom: 4px;
}
.tla__heading { margin: 0 0 6px; font-size: 15px; font-weight: 800; color: #f6f2ff; }
.tla__desc { margin: 0; font-size: 13px; line-height: 1.7; color: #c3bde0; }

/* 奇数=左側、偶数=右側 */
.tla__item:nth-child(odd) .tla__content {
  grid-column: 1;
  text-align: right;
}
.tla__item:nth-child(even) .tla__content {
  grid-column: 3;
  text-align: left;
}

/* 交互に左右から出現 */
.tla__item:nth-child(odd) { animation: tlaInLeft .6s cubic-bezier(.22, 1, .36, 1) forwards; }
.tla__item:nth-child(even) { animation: tlaInRight .6s cubic-bezier(.22, 1, .36, 1) forwards; }
.tla__item:nth-child(1) { animation-delay: .05s; }
.tla__item:nth-child(2) { animation-delay: .16s; }
.tla__item:nth-child(3) { animation-delay: .27s; }
.tla__item:nth-child(4) { animation-delay: .38s; }
.tla__item:nth-child(5) { animation-delay: .49s; }
.tla__item:nth-child(6) { animation-delay: .60s; }

@keyframes tlaInLeft {
  from { opacity: 0; transform: translateX(-22px); }
  to   { opacity: 1; transform: translateX(0); }
}
@keyframes tlaInRight {
  from { opacity: 0; transform: translateX(22px); }
  to   { opacity: 1; transform: translateX(0); }
}

/* 狭幅: 線を左端へ寄せ、全カードを片側寄せの1列表示に */
@media (max-width: 560px) {
  .tla__card { padding: 22px 16px 6px; border-radius: 16px; }
  .tla__list { padding-left: 6px; }
  .tla__list::before { left: 14px; transform: none; }
  .tla__item {
    grid-template-columns: 28px 1fr;
    column-gap: 12px;
  }
  .tla__dot { grid-column: 1; justify-self: start; margin-left: 8px; }
  .tla__item:nth-child(odd) .tla__content,
  .tla__item:nth-child(even) .tla__content {
    grid-column: 2;
    text-align: left;
  }
  .tla__item:nth-child(even) { animation-name: tlaInLeft; }
}

@media (prefers-reduced-motion: reduce) {
  .tla__item { animation: none !important; opacity: 1; transform: none; }
}
JavaScript
// 左右交互タイムライン: 演出はCSSの読み込み時アニメーションのみで完結(JS不要)

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

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

# 追加してほしい効果
左右交互タイムライン(タイムライン & 404)
中央の縦線を挟んでカードが左右交互に並ぶ沿革タイムライン。それぞれが逆方向からふわっと現れ、狭い画面では片側寄せの1列表示に切り替わります。

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

# 参考実装(この見た目・挙動を再現してください)
【HTML】
<!-- 左右交互タイムライン: 中央の縦線を挟んでカードが左右へ交互に並ぶ -->
<section class="tla">
  <div class="tla__card">
    <p class="tla__eyebrow">COMPANY HISTORY</p>
    <h2 class="tla__title">会社沿革</h2>

    <div class="tla__scroll" tabindex="0" role="region" aria-label="会社の沿革(スクロールで続きを表示)">
      <ol class="tla__list">
        <li class="tla__item">
          <div class="tla__content">
            <time class="tla__date">2019年</time>
            <h3 class="tla__heading">設立</h3>
            <p class="tla__desc">東京の小さなオフィスで、3名のメンバーとともに創業しました。</p>
          </div>
          <span class="tla__dot" aria-hidden="true"></span>
        </li>
        <li class="tla__item">
          <div class="tla__content">
            <time class="tla__date">2020年</time>
            <h3 class="tla__heading">初出資</h3>
            <p class="tla__desc">エンジェル投資家より資金を調達し、開発体制を強化しました。</p>
          </div>
          <span class="tla__dot" aria-hidden="true"></span>
        </li>
        <li class="tla__item">
          <div class="tla__content">
            <time class="tla__date">2021年</time>
            <h3 class="tla__heading">初の海外拠点</h3>
            <p class="tla__desc">シンガポールに拠点を新設し、アジア市場への足がかりを築きました。</p>
          </div>
          <span class="tla__dot" aria-hidden="true"></span>
        </li>
        <li class="tla__item">
          <div class="tla__content">
            <time class="tla__date">2022年</time>
            <h3 class="tla__heading">累計利用者50万人</h3>
            <p class="tla__desc">サービス開始から3年で、利用者数が50万人を突破しました。</p>
          </div>
          <span class="tla__dot" aria-hidden="true"></span>
        </li>
        <li class="tla__item">
          <div class="tla__content">
            <time class="tla__date">2023年</time>
            <h3 class="tla__heading">株式上場</h3>
            <p class="tla__desc">東京証券取引所グロース市場に株式を上場しました。</p>
          </div>
          <span class="tla__dot" aria-hidden="true"></span>
        </li>
        <li class="tla__item">
          <div class="tla__content">
            <time class="tla__date">2024年</time>
            <h3 class="tla__heading">新社屋へ移転</h3>
            <p class="tla__desc">渋谷に新オフィスを構え、従業員数は200名を超えました。</p>
          </div>
          <span class="tla__dot" aria-hidden="true"></span>
        </li>
      </ol>
    </div>
  </div>
</section>

【CSS】
/* 左右交互タイムライン: 中央線を挟んでカードが左右交互に並ぶ沿革 */
* { box-sizing: border-box; }
body {
  margin: 0;
  min-height: 100vh;
  display: grid;
  place-items: center;
  padding: 30px 16px;
  font-family: "Segoe UI", "Hiragino Kaku Gothic ProN", "Yu Gothic UI", system-ui, sans-serif;
  background: radial-gradient(130% 110% at 50% -10%, #241b3d 0%, #12101e 55%, #0c0a14 100%);
  color: #f1eefb;
}

/* ルート: 全幅 */
.tla { width: 100%; display: grid; place-items: center; }

.tla__card {
  width: min(680px, 100%);
  background: rgba(255, 255, 255, .035);
  border: 1px solid rgba(255, 255, 255, .09);
  border-radius: 20px;
  padding: 28px 26px 8px;
  box-shadow: 0 30px 60px -30px rgba(0, 0, 0, .65);
}

.tla__eyebrow {
  margin: 0 0 6px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .24em;
  color: #d9a4ff;
  text-align: center;
}
.tla__title {
  margin: 0 0 22px;
  font-size: clamp(19px, 3vw, 23px);
  font-weight: 800;
  text-align: center;
  letter-spacing: -.01em;
}

.tla__scroll {
  max-height: 380px;
  overflow-y: auto;
  scrollbar-width: thin;
  scrollbar-color: rgba(217, 164, 255, .4) transparent;
}
.tla__scroll::-webkit-scrollbar { width: 6px; }
.tla__scroll::-webkit-scrollbar-thumb { background: rgba(217, 164, 255, .35); border-radius: 999px; }

.tla__list {
  position: relative;
  list-style: none;
  margin: 0;
  padding: 4px 4px 22px;
}
/* 中央の縦線 */
.tla__list::before {
  content: "";
  position: absolute;
  left: 50%; top: 4px; bottom: 10px;
  width: 2px;
  transform: translateX(-50%);
  background: linear-gradient(180deg, #d9a4ff, #7c8bff 55%, rgba(124, 139, 255, .12));
  border-radius: 2px;
}

.tla__item {
  position: relative;
  display: grid;
  grid-template-columns: 1fr 36px 1fr;
  column-gap: 16px;
  align-items: start;
  padding-bottom: 26px;
  opacity: 0;
}
.tla__item:last-child { padding-bottom: 4px; }

.tla__dot {
  grid-column: 2;
  justify-self: center;
  margin-top: 5px;
  width: 12px; height: 12px;
  border-radius: 50%;
  background: linear-gradient(135deg, #d9a4ff, #7c8bff);
  box-shadow: 0 0 0 4px rgba(217, 164, 255, .16);
}

.tla__content { min-width: 0; }
.tla__date {
  display: block;
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: .06em;
  color: #b9a8e6;
  margin-bottom: 4px;
}
.tla__heading { margin: 0 0 6px; font-size: 15px; font-weight: 800; color: #f6f2ff; }
.tla__desc { margin: 0; font-size: 13px; line-height: 1.7; color: #c3bde0; }

/* 奇数=左側、偶数=右側 */
.tla__item:nth-child(odd) .tla__content {
  grid-column: 1;
  text-align: right;
}
.tla__item:nth-child(even) .tla__content {
  grid-column: 3;
  text-align: left;
}

/* 交互に左右から出現 */
.tla__item:nth-child(odd) { animation: tlaInLeft .6s cubic-bezier(.22, 1, .36, 1) forwards; }
.tla__item:nth-child(even) { animation: tlaInRight .6s cubic-bezier(.22, 1, .36, 1) forwards; }
.tla__item:nth-child(1) { animation-delay: .05s; }
.tla__item:nth-child(2) { animation-delay: .16s; }
.tla__item:nth-child(3) { animation-delay: .27s; }
.tla__item:nth-child(4) { animation-delay: .38s; }
.tla__item:nth-child(5) { animation-delay: .49s; }
.tla__item:nth-child(6) { animation-delay: .60s; }

@keyframes tlaInLeft {
  from { opacity: 0; transform: translateX(-22px); }
  to   { opacity: 1; transform: translateX(0); }
}
@keyframes tlaInRight {
  from { opacity: 0; transform: translateX(22px); }
  to   { opacity: 1; transform: translateX(0); }
}

/* 狭幅: 線を左端へ寄せ、全カードを片側寄せの1列表示に */
@media (max-width: 560px) {
  .tla__card { padding: 22px 16px 6px; border-radius: 16px; }
  .tla__list { padding-left: 6px; }
  .tla__list::before { left: 14px; transform: none; }
  .tla__item {
    grid-template-columns: 28px 1fr;
    column-gap: 12px;
  }
  .tla__dot { grid-column: 1; justify-self: start; margin-left: 8px; }
  .tla__item:nth-child(odd) .tla__content,
  .tla__item:nth-child(even) .tla__content {
    grid-column: 2;
    text-align: left;
  }
  .tla__item:nth-child(even) { animation-name: tlaInLeft; }
}

@media (prefers-reduced-motion: reduce) {
  .tla__item { animation: none !important; opacity: 1; transform: none; }
}

【JavaScript】
// 左右交互タイムライン: 演出はCSSの読み込み時アニメーションのみで完結(JS不要)

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

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