昼夜トグルスイッチ
太陽が月に変わり、空が夜になって星が現れるアニメ付きスイッチ。ほぼ純CSSで動き、ダークモード切替などの設定UIに向きます。
ライブデモ
使用例(お題: カフェ 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で提示し、組み込み手順も説明すること。
- 変更後の確認手順も簡潔に教えてください。