lab-css

反応する庭

チェックボックスとラジオボタンの状態に:has()で庭全体が応答する。夜にすれば月が昇り、札を選べば花が咲く。JavaScriptは一切使っていない。

全画面で見る
:has():checked操作: クリック

上部のスイッチを切り替えると庭が変化します

庭を操作する

お使いのブラウザは:has()に未対応のため、この庭はスイッチに反応しません。

対応ブラウザ

CSS機能Chrome / EdgeFirefoxSafari備考
:has()105+121+15.4+Baseline
:checked対応対応対応チェックボックスハック

コード

表示中のコードは作品の実行に使われているものと同一ソースです。そのままコピーして試せます。

/* 反応する庭: フォーム要素の状態に:has()で庭全体が応答する。JSは不使用 */

.work-has-garden {
  position: relative;
  width: 100%;
  height: 100%;
  overflow: hidden;
  background: #0c0d12;
}

/* ---- 操作パネル ---- */

.hg-controls {
  position: absolute;
  top: 12px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 20;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 14px;
  border: 1px solid rgba(255, 255, 255, 0.15);
  border-radius: 999px;
  background: rgba(8, 9, 14, 0.72);
  backdrop-filter: blur(6px);
}

.hg-legend {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
}

.hg-chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  color: #d8d8de;
  font-size: 12px;
  cursor: pointer;
  white-space: nowrap;
}

.hg-chip input {
  accent-color: #f2a5b8;
}

.hg-sep {
  width: 1px;
  height: 16px;
  background: rgba(255, 255, 255, 0.2);
}

/* ---- 昼の庭 ---- */

.hg-scene {
  position: absolute;
  inset: 0;
}

.hg-sky {
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, #7fc4e8 0%, #bfe3ef 60%, #eaf2d9 100%);
  transition: filter 1.2s ease, opacity 1.2s ease;
}

.hg-sun {
  position: absolute;
  top: 16%;
  left: 16%;
  width: 11%;
  aspect-ratio: 1;
  border-radius: 50%;
  background: radial-gradient(circle, #fff6d8 30%, #ffd166 70%);
  box-shadow: 0 0 44px rgba(255, 209, 102, 0.8);
  transition: transform 1.2s ease, opacity 1.2s ease;
}

.hg-moon {
  position: absolute;
  top: 14%;
  right: 18%;
  width: 9%;
  aspect-ratio: 1;
  border-radius: 50%;
  background: radial-gradient(circle at 35% 35%, #fdf7e3, #e5d9a8);
  box-shadow: 0 0 34px rgba(253, 247, 227, 0.5);
  opacity: 0;
  transform: translateY(60px);
  transition: transform 1.2s ease, opacity 1.2s ease;
}

.hg-stars {
  position: absolute;
  inset: 0 0 40% 0;
  background-image:
    radial-gradient(1.5px 1.5px at 12% 30%, #fff, transparent),
    radial-gradient(1px 1px at 28% 12%, #fff, transparent),
    radial-gradient(1.5px 1.5px at 44% 38%, #fff, transparent),
    radial-gradient(1px 1px at 58% 18%, #fff, transparent),
    radial-gradient(1.5px 1.5px at 71% 42%, #fff, transparent),
    radial-gradient(1px 1px at 86% 26%, #fff, transparent),
    radial-gradient(1px 1px at 35% 55%, #fff, transparent),
    radial-gradient(1.5px 1.5px at 92% 52%, #fff, transparent);
  opacity: 0;
  transition: opacity 1.4s ease;
}

.hg-hill {
  position: absolute;
  left: -10%;
  right: -10%;
  bottom: -32%;
  height: 62%;
  border-radius: 50% 50% 0 0;
  transition: filter 1.2s ease;
}

.hg-hill-back {
  bottom: -26%;
  background: #8fbf6a;
  filter: brightness(0.92);
}

.hg-hill-front {
  background: #79ad55;
}

/* ---- 花 ---- */

.hg-flower {
  position: absolute;
  bottom: 18%;
  width: 8px;
  height: 22%;
  transition: filter 1.2s ease;
}

.hg-f1 { left: 18%; height: 24%; }
.hg-f2 { left: 34%; height: 19%; bottom: 14%; }
.hg-f3 { left: 52%; height: 26%; bottom: 16%; }
.hg-f4 { left: 68%; height: 20%; bottom: 12%; }
.hg-f5 { left: 84%; height: 23%; bottom: 15%; }

.hg-stem {
  position: absolute;
  left: 50%;
  bottom: 0;
  width: 4px;
  height: 100%;
  transform: translateX(-50%);
  border-radius: 4px;
  background: linear-gradient(180deg, #4d8a3d, #2f6b2a);
}

/* 花頭: repeating-conic-gradientの花弁と中心の芯 */
.hg-head {
  position: absolute;
  top: 0;
  left: 50%;
  width: 54px;
  height: 54px;
  border-radius: 50%;
  background:
    radial-gradient(circle, #ffd166 0 22%, transparent 23%),
    repeating-conic-gradient(from 0deg,
      #f2a5b8 0deg 24deg, #fbd3dd 24deg 45deg);
  transform: translate(-50%, -40%) scale(0.22);
  transform-origin: center;
  filter: saturate(0.5) brightness(0.85);
  transition: transform 0.9s cubic-bezier(0.34, 1.56, 0.64, 1), filter 0.9s ease;
}

/* ---- 状態1: 三分咲き(radioに:has()で応答) ---- */

.work-has-garden:has(.hg-bloom:checked) .hg-f1 .hg-head,
.work-has-garden:has(.hg-bloom:checked) .hg-f3 .hg-head,
.work-has-garden:has(.hg-bloom:checked) .hg-f5 .hg-head {
  transform: translate(-50%, -40%) scale(0.85);
  filter: saturate(1) brightness(1);
}

/* ---- 状態2: 満開 ---- */

.work-has-garden:has(.hg-full:checked) .hg-head {
  transform: translate(-50%, -40%) scale(1);
  filter: saturate(1.15) brightness(1.05)
    drop-shadow(0 0 10px rgba(242, 165, 184, 0.6));
}

/* ---- 状態3: 夜(checkboxに:has()で応答) ---- */

.work-has-garden:has(.hg-night:checked) .hg-sky {
  filter: hue-rotate(150deg) saturate(0.55) brightness(0.32);
}

.work-has-garden:has(.hg-night:checked) .hg-sun {
  transform: translateY(140px);
  opacity: 0;
}

.work-has-garden:has(.hg-night:checked) .hg-moon {
  transform: translateY(0);
  opacity: 1;
}

.work-has-garden:has(.hg-night:checked) .hg-stars {
  opacity: 0.9;
}

.work-has-garden:has(.hg-night:checked) .hg-hill,
.work-has-garden:has(.hg-night:checked) .hg-flower {
  filter: brightness(0.45) saturate(0.7);
}

/* 夜の満開は花明かりに */
.work-has-garden:has(.hg-night:checked):has(.hg-full:checked) .hg-head {
  filter: brightness(0.9) saturate(1.1)
    drop-shadow(0 0 14px rgba(255, 214, 224, 0.8));
}

/* ---- :has()非対応ブラウザへの告知 ---- */

@supports not selector(:has(input)) {
  .work-has-garden .work-warn {
    display: block;
  }

  .work-has-garden .hg-controls {
    opacity: 0.45;
  }
}