昼夜トグルスイッチ

太陽が月に変わり、空が夜になって星が現れるアニメ付きスイッチ。ほぼ純CSSで動き、ダークモード切替などの設定UIに向きます。

#css#form#toggle#animation

ライブデモ

使用例(お題: カフェ MOON BREW)

この技法を「カフェ MOON BREW」というテーマのダミーサイトで実際に使った例です。

HTML
<!-- MOON BREW: メニュー設定。Hot/Icedトグルスイッチを主役に -->
<div class="mb">
  <header class="mb__head">
    <span class="mb__logo">☕ MOON BREW</span>
    <span class="mb__sub">本日のおすすめ</span>
  </header>

  <div class="mb__card">
    <div class="mb__cup" aria-hidden="true">
      <span class="mb__steam"></span>
      <span class="mb__steam"></span>
    </div>
    <div class="mb__text">
      <h1 class="mb__name">ハニーカフェオレ</h1>
      <p class="mb__desc">国産はちみつのやさしい甘さ。<br>お好みの温度でどうぞ。</p>

      <label class="switch">
        <span class="switch__side switch__side--hot">HOT</span>
        <input class="switch__input" type="checkbox" role="switch" aria-label="HotとIcedの切替">
        <span class="switch__track">
          <span class="switch__thumb"></span>
        </span>
        <span class="switch__side switch__side--ice">ICED</span>
      </label>

      <p class="mb__state">ただいま <span class="mode">HOT</span> を選択中 / <span class="price">¥540</span></p>
    </div>
  </div>
</div>
CSS
/* MOON BREW カフェ テーマ: クリーム/濃ブラウン/琥珀 */
* { box-sizing: border-box; }
body {
  margin: 0;
  font-family: "Hiragino Mincho ProN", "Segoe UI", system-ui, serif;
  background: #f5ede1;
  color: #2b1d12;
}

.mb {
  height: 400px;
  display: flex;
  flex-direction: column;
  padding: 0 30px;
}
.mb__head {
  display: flex;
  align-items: baseline;
  gap: 14px;
  padding: 20px 0;
  border-bottom: 1px solid #e3d6c2;
}
.mb__logo {
  font-size: 18px;
  font-weight: 700;
  letter-spacing: .04em;
}
.mb__sub {
  font-size: 12px;
  color: #9b876f;
  font-family: "Segoe UI", system-ui, sans-serif;
}

.mb__card {
  flex: 1;
  display: grid;
  grid-template-columns: 150px 1fr;
  align-items: center;
  gap: 24px;
}

/* カップ(CSSで簡易表現) */
.mb__cup {
  position: relative;
  justify-self: center;
  width: 110px;
  height: 110px;
  border-radius: 50%;
  background:
    radial-gradient(circle at 42% 36%, #d9b388 0%, #c98a3b 45%, #7a5224 100%);
  box-shadow: 0 16px 34px rgba(122,82,36,.4), inset 0 -8px 16px rgba(0,0,0,.25);
}
.mb__steam {
  position: absolute;
  top: -22px;
  width: 7px;
  height: 26px;
  border-radius: 999px;
  background: rgba(255,255,255,.5);
  filter: blur(2px);
  animation: steam 2.6s ease-in-out infinite;
}
.mb__steam:nth-child(1) { left: 38px; }
.mb__steam:nth-child(2) { left: 62px; animation-delay: .8s; }
@keyframes steam {
  0% { opacity: 0; transform: translateY(6px) scaleY(.7); }
  50% { opacity: .8; }
  100% { opacity: 0; transform: translateY(-14px) scaleY(1.3); }
}

.mb__name {
  margin: 0;
  font-size: 26px;
  font-weight: 700;
}
.mb__desc {
  margin: 12px 0 0;
  font-size: 13px;
  line-height: 1.8;
  color: #5a4633;
}

/* 主役: Hot/Iced トグルスイッチ */
.switch {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  margin: 22px 0 0;
  cursor: pointer;
  user-select: none;
  font-family: "Segoe UI", system-ui, sans-serif;
}
.switch__side {
  font-size: 12px;
  font-weight: 800;
  letter-spacing: .08em;
  color: #c0ac93;
  transition: color .3s ease;
}
.switch__side--hot { color: #c4622a; }
.switch__input { position: absolute; opacity: 0; pointer-events: none; }
.switch__track {
  position: relative;
  width: 64px;
  height: 32px;
  border-radius: 999px;
  background: linear-gradient(90deg, #d98a4a, #c4622a);
  box-shadow: inset 0 2px 6px rgba(0,0,0,.25);
  transition: background .4s ease;
}
.switch__thumb {
  position: absolute;
  top: 3px;
  left: 3px;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: #fbf6ee;
  box-shadow: 0 3px 8px rgba(0,0,0,.3);
  transition: transform .4s cubic-bezier(.34,1.56,.64,1);
}
/* チェック時=Iced: トラック青系へ、サムが右へ */
.switch__input:checked + .switch__track {
  background: linear-gradient(90deg, #6fb4d6, #3f8fc2);
}
.switch__input:checked + .switch__track .switch__thumb {
  transform: translateX(32px);
}
.switch__input:checked ~ .switch__side--ice { color: #2f86bd; }
.switch:has(.switch__input:checked) .switch__side--hot { color: #c0ac93; }

.mb__state {
  margin: 18px 0 0;
  font-size: 13px;
  color: #5a4633;
  font-family: "Segoe UI", system-ui, sans-serif;
}
.mode { font-weight: 800; color: #2b1d12; }
.price { font-weight: 800; color: #c98a3b; }

@media (prefers-reduced-motion: reduce) {
  .mb__steam { animation: none; opacity: .5; }
  .switch__thumb, .switch__track { transition: none; }
}
JavaScript
// MOON BREW: Hot/Icedトグルで表示ラベルと価格を同期(視覚の主役はCSS)
(() => {
  const input = document.querySelector('.switch__input');
  const mode = document.querySelector('.mode');
  const price = document.querySelector('.price');
  if (!input) return; // null安全

  // Iced は +50円という設定
  const sync = () => {
    const iced = input.checked;
    if (mode) mode.textContent = iced ? 'ICED' : 'HOT';
    if (price) price.textContent = iced ? '¥590' : '¥540';
  };

  input.addEventListener('change', sync);
  sync(); // 初期表示を整える
})();

コード

HTML
<!-- トグルスイッチ: 昼/夜を切り替えるアニメ付きスイッチ -->
<div class="stage">
  <label class="switch">
    <input class="switch__input" type="checkbox" role="switch" aria-label="ダークモード切替">
    <span class="switch__track">
      <span class="switch__stars" aria-hidden="true"></span>
      <span class="switch__thumb">
        <span class="switch__craters" aria-hidden="true"></span>
      </span>
    </span>
  </label>
  <p class="hint">クリックで <span class="mode">Day</span> / Night</p>
</div>
CSS
* { box-sizing: border-box; }
body {
  margin: 0;
  min-height: 100vh;
  display: grid;
  place-items: center;
  font-family: "Segoe UI", system-ui, sans-serif;
  background: #1b2430;
  color: #e6edf5;
}

.stage {
  display: grid;
  place-items: center;
  gap: 22px;
}

/* 実体のcheckboxは隠し、ラベルで操作 */
.switch { cursor: pointer; }
.switch__input {
  position: absolute;
  opacity: 0;
  width: 0;
  height: 0;
}

/* トラック(背景): 昼空 */
.switch__track {
  position: relative;
  display: block;
  width: 132px;
  height: 60px;
  border-radius: 999px;
  background: linear-gradient(180deg, #87cefa 0%, #4ea4e0 100%);
  box-shadow: inset 0 2px 8px rgba(0, 0, 0, .25);
  transition: background .5s ease;
  overflow: hidden;
}

/* 夜空の星(チェック時に出現) */
.switch__stars {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity .5s ease;
  background-image:
    radial-gradient(1.5px 1.5px at 20px 18px, #fff, transparent),
    radial-gradient(1.5px 1.5px at 50px 40px, #fff, transparent),
    radial-gradient(1px 1px at 35px 28px, #fff, transparent),
    radial-gradient(1.5px 1.5px at 70px 16px, #fff, transparent),
    radial-gradient(1px 1px at 90px 34px, #fff, transparent);
}

/* つまみ(太陽→月) */
.switch__thumb {
  position: absolute;
  top: 6px;
  left: 6px;
  width: 48px;
  height: 48px;
  border-radius: 50%;
  background: radial-gradient(circle at 35% 35%, #fff7d6, #ffd83b);
  box-shadow: 0 4px 10px rgba(0, 0, 0, .35), 0 0 22px rgba(255, 216, 59, .7);
  transition: transform .5s cubic-bezier(.68,-0.4,.27,1.4), background .5s ease, box-shadow .5s ease;
}

/* 月のクレーター(チェック時に表示) */
.switch__craters {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  opacity: 0;
  transition: opacity .5s ease;
  background-image:
    radial-gradient(circle, #c4cbd6 0 5px, transparent 6px),
    radial-gradient(circle, #c4cbd6 0 3px, transparent 4px),
    radial-gradient(circle, #c4cbd6 0 4px, transparent 5px);
  background-position: 14px 12px, 30px 28px, 22px 34px;
  background-repeat: no-repeat;
}

/* チェック時(夜)の状態変化 */
.switch__input:checked + .switch__track {
  background: linear-gradient(180deg, #1c2541 0%, #3a3f6b 100%);
}
.switch__input:checked + .switch__track .switch__stars { opacity: 1; }
.switch__input:checked + .switch__track .switch__thumb {
  transform: translateX(72px);
  background: radial-gradient(circle at 35% 35%, #f4f6fb, #d4dae6);
  box-shadow: 0 4px 10px rgba(0, 0, 0, .45), 0 0 18px rgba(212, 218, 230, .5);
}
.switch__input:checked + .switch__track .switch__craters { opacity: 1; }

/* キーボードフォーカス可視化 */
.switch__input:focus-visible + .switch__track {
  outline: 3px solid #8ac6ff;
  outline-offset: 3px;
}

.hint {
  margin: 0;
  font-size: 13px;
  color: rgba(230, 237, 245, .6);
}
.mode { font-weight: 700; color: #ffd83b; }

@media (prefers-reduced-motion: reduce) {
  .switch__track, .switch__thumb, .switch__stars, .switch__craters { transition: none; }
}
JavaScript
// トグルスイッチ: 見た目はCSS。JSはラベル表示の更新のみ
(() => {
  const input = document.querySelector('.switch__input');
  const mode = document.querySelector('.mode');
  if (!input || !mode) return; // null安全

  const sync = () => {
    mode.textContent = input.checked ? 'Night' : 'Day';
  };
  input.addEventListener('change', sync);
  sync(); // 初期表示を合わせる
})();

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

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

# 追加してほしい効果
昼夜トグルスイッチ(マイクロインタラクション)
太陽が月に変わり、空が夜になって星が現れるアニメ付きスイッチ。ほぼ純CSSで動き、ダークモード切替などの設定UIに向きます。

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

# 参考実装(この見た目・挙動を再現してください)
【HTML】
<!-- トグルスイッチ: 昼/夜を切り替えるアニメ付きスイッチ -->
<div class="stage">
  <label class="switch">
    <input class="switch__input" type="checkbox" role="switch" aria-label="ダークモード切替">
    <span class="switch__track">
      <span class="switch__stars" aria-hidden="true"></span>
      <span class="switch__thumb">
        <span class="switch__craters" aria-hidden="true"></span>
      </span>
    </span>
  </label>
  <p class="hint">クリックで <span class="mode">Day</span> / Night</p>
</div>

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

.stage {
  display: grid;
  place-items: center;
  gap: 22px;
}

/* 実体のcheckboxは隠し、ラベルで操作 */
.switch { cursor: pointer; }
.switch__input {
  position: absolute;
  opacity: 0;
  width: 0;
  height: 0;
}

/* トラック(背景): 昼空 */
.switch__track {
  position: relative;
  display: block;
  width: 132px;
  height: 60px;
  border-radius: 999px;
  background: linear-gradient(180deg, #87cefa 0%, #4ea4e0 100%);
  box-shadow: inset 0 2px 8px rgba(0, 0, 0, .25);
  transition: background .5s ease;
  overflow: hidden;
}

/* 夜空の星(チェック時に出現) */
.switch__stars {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity .5s ease;
  background-image:
    radial-gradient(1.5px 1.5px at 20px 18px, #fff, transparent),
    radial-gradient(1.5px 1.5px at 50px 40px, #fff, transparent),
    radial-gradient(1px 1px at 35px 28px, #fff, transparent),
    radial-gradient(1.5px 1.5px at 70px 16px, #fff, transparent),
    radial-gradient(1px 1px at 90px 34px, #fff, transparent);
}

/* つまみ(太陽→月) */
.switch__thumb {
  position: absolute;
  top: 6px;
  left: 6px;
  width: 48px;
  height: 48px;
  border-radius: 50%;
  background: radial-gradient(circle at 35% 35%, #fff7d6, #ffd83b);
  box-shadow: 0 4px 10px rgba(0, 0, 0, .35), 0 0 22px rgba(255, 216, 59, .7);
  transition: transform .5s cubic-bezier(.68,-0.4,.27,1.4), background .5s ease, box-shadow .5s ease;
}

/* 月のクレーター(チェック時に表示) */
.switch__craters {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  opacity: 0;
  transition: opacity .5s ease;
  background-image:
    radial-gradient(circle, #c4cbd6 0 5px, transparent 6px),
    radial-gradient(circle, #c4cbd6 0 3px, transparent 4px),
    radial-gradient(circle, #c4cbd6 0 4px, transparent 5px);
  background-position: 14px 12px, 30px 28px, 22px 34px;
  background-repeat: no-repeat;
}

/* チェック時(夜)の状態変化 */
.switch__input:checked + .switch__track {
  background: linear-gradient(180deg, #1c2541 0%, #3a3f6b 100%);
}
.switch__input:checked + .switch__track .switch__stars { opacity: 1; }
.switch__input:checked + .switch__track .switch__thumb {
  transform: translateX(72px);
  background: radial-gradient(circle at 35% 35%, #f4f6fb, #d4dae6);
  box-shadow: 0 4px 10px rgba(0, 0, 0, .45), 0 0 18px rgba(212, 218, 230, .5);
}
.switch__input:checked + .switch__track .switch__craters { opacity: 1; }

/* キーボードフォーカス可視化 */
.switch__input:focus-visible + .switch__track {
  outline: 3px solid #8ac6ff;
  outline-offset: 3px;
}

.hint {
  margin: 0;
  font-size: 13px;
  color: rgba(230, 237, 245, .6);
}
.mode { font-weight: 700; color: #ffd83b; }

@media (prefers-reduced-motion: reduce) {
  .switch__track, .switch__thumb, .switch__stars, .switch__craters { transition: none; }
}

【JavaScript】
// トグルスイッチ: 見た目はCSS。JSはラベル表示の更新のみ
(() => {
  const input = document.querySelector('.switch__input');
  const mode = document.querySelector('.mode');
  if (!input || !mode) return; // null安全

  const sync = () => {
    mode.textContent = input.checked ? 'Night' : 'Day';
  };
  input.addEventListener('change', sync);
  sync(); // 初期表示を合わせる
})();

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

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