星評価入力

ホバーで星がプレビュー表示され、クリックで評価が確定する5段階の星評価入力。選択後は「満足」などの評価ラベルが表示されます。

#css#js#form#rating

ライブデモ

コード

HTML
<div class="stage">
  <div class="sr-card">
    <p class="sr-question">今回のサービスに満足しましたか?</p>

    <div class="sr-stars" role="radiogroup" aria-label="評価(5段階)" id="sr-stars">
      <label class="sr-star" data-value="5">
        <input type="radio" name="sr-rating" value="5" class="sr-input">
        <span class="sr-icon" aria-hidden="true">★</span>
        <span class="sr-only">5:大変満足</span>
      </label>
      <label class="sr-star" data-value="4">
        <input type="radio" name="sr-rating" value="4" class="sr-input">
        <span class="sr-icon" aria-hidden="true">★</span>
        <span class="sr-only">4:満足</span>
      </label>
      <label class="sr-star" data-value="3">
        <input type="radio" name="sr-rating" value="3" class="sr-input">
        <span class="sr-icon" aria-hidden="true">★</span>
        <span class="sr-only">3:普通</span>
      </label>
      <label class="sr-star" data-value="2">
        <input type="radio" name="sr-rating" value="2" class="sr-input">
        <span class="sr-icon" aria-hidden="true">★</span>
        <span class="sr-only">2:やや不満</span>
      </label>
      <label class="sr-star" data-value="1">
        <input type="radio" name="sr-rating" value="1" class="sr-input">
        <span class="sr-icon" aria-hidden="true">★</span>
        <span class="sr-only">1:不満</span>
      </label>
    </div>

    <p class="sr-feedback" id="sr-feedback" role="status">星を選択してください</p>
  </div>
</div>
CSS
* { box-sizing: border-box; }

body {
  margin: 0;
  min-height: 100vh;
  display: grid;
  place-items: center;
  padding: 24px;
  font-family: "Segoe UI", "Hiragino Kaku Gothic ProN", system-ui, sans-serif;
  /* 上品なローズ系グラデ背景 */
  background: linear-gradient(135deg, #fff1f2 0%, #ffe4e6 50%, #fce7f3 100%);
  color: #1f2937;
}

.stage { width: 100%; display: grid; place-items: center; }

.sr-card {
  width: min(340px, 92vw);
  padding: 32px 28px 26px;
  background: #fff;
  border-radius: 20px;
  box-shadow: 0 24px 56px -26px rgba(190, 24, 93, 0.3);
  text-align: center;
}

.sr-question {
  margin: 0 0 20px;
  font-size: 0.98rem;
  font-weight: 600;
  color: #4a1d2a;
}

/* DOMは5→1の逆順。row-reverseで見た目を1→5に戻し、
   後続セレクタで「選択/ホバーした星までを塗る」古典テクニックを使う */
.sr-stars {
  display: flex;
  flex-direction: row-reverse;
  justify-content: center;
  gap: 6px;
}

.sr-star {
  position: relative;
  cursor: pointer;
  line-height: 1;
}
.sr-input {
  position: absolute;
  opacity: 0;
  width: 1px;
  height: 1px;
}

.sr-icon {
  display: block;
  font-size: 2.1rem;
  color: #e2d4d8;
  transition: color 0.16s ease, transform 0.12s ease;
}

/* ホバー中:ホバー星+それより手前(DOM上で後ろ)の星も塗る */
.sr-star:hover .sr-icon,
.sr-star:hover ~ .sr-star .sr-icon {
  color: #f59e0b;
}
.sr-star:hover .sr-icon { transform: scale(1.12); }

/* 確定済み:チェックされた星+それより手前の星も塗る */
.sr-star:has(.sr-input:checked) .sr-icon,
.sr-star:has(.sr-input:checked) ~ .sr-star .sr-icon {
  color: #f59e0b;
}

.sr-input:focus-visible ~ .sr-icon {
  outline: none;
  box-shadow: 0 0 0 3px rgba(244, 63, 94, 0.35);
  border-radius: 6px;
}

.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.sr-feedback {
  margin: 18px 0 0;
  font-size: 0.86rem;
  font-weight: 600;
  color: #9d174d;
  transition: transform 0.18s ease;
}
.sr-feedback.is-confirmed { animation: sr-pop 0.28s ease; }
@keyframes sr-pop {
  0% { transform: scale(0.9); }
  60% { transform: scale(1.06); }
  100% { transform: scale(1); }
}

@media (prefers-reduced-motion: reduce) {
  .sr-icon, .sr-feedback { transition: none; }
  .sr-feedback.is-confirmed { animation: none; }
}
JavaScript
// 星評価入力:クリックで確定した値に応じて評価ラベルを表示する
(function () {
  var group = document.getElementById("sr-stars");
  var feedback = document.getElementById("sr-feedback");
  if (!group || !feedback) return;

  var labels = {
    1: "不満",
    2: "やや不満",
    3: "普通",
    4: "満足",
    5: "大変満足",
  };

  group.addEventListener("change", function (e) {
    var target = e.target;
    if (!target || !target.classList || !target.classList.contains("sr-input")) return;
    var value = parseInt(target.value, 10);
    var label = labels[value] || "";
    feedback.textContent = "評価:" + label + "(" + value + "/5)";
    feedback.classList.remove("is-confirmed");
    void feedback.offsetWidth;
    feedback.classList.add("is-confirmed");
  });
})();

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

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

# 追加してほしい効果
星評価入力(フォーム & 入力)
ホバーで星がプレビュー表示され、クリックで評価が確定する5段階の星評価入力。選択後は「満足」などの評価ラベルが表示されます。

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

# 参考実装(この見た目・挙動を再現してください)
【HTML】
<div class="stage">
  <div class="sr-card">
    <p class="sr-question">今回のサービスに満足しましたか?</p>

    <div class="sr-stars" role="radiogroup" aria-label="評価(5段階)" id="sr-stars">
      <label class="sr-star" data-value="5">
        <input type="radio" name="sr-rating" value="5" class="sr-input">
        <span class="sr-icon" aria-hidden="true">★</span>
        <span class="sr-only">5:大変満足</span>
      </label>
      <label class="sr-star" data-value="4">
        <input type="radio" name="sr-rating" value="4" class="sr-input">
        <span class="sr-icon" aria-hidden="true">★</span>
        <span class="sr-only">4:満足</span>
      </label>
      <label class="sr-star" data-value="3">
        <input type="radio" name="sr-rating" value="3" class="sr-input">
        <span class="sr-icon" aria-hidden="true">★</span>
        <span class="sr-only">3:普通</span>
      </label>
      <label class="sr-star" data-value="2">
        <input type="radio" name="sr-rating" value="2" class="sr-input">
        <span class="sr-icon" aria-hidden="true">★</span>
        <span class="sr-only">2:やや不満</span>
      </label>
      <label class="sr-star" data-value="1">
        <input type="radio" name="sr-rating" value="1" class="sr-input">
        <span class="sr-icon" aria-hidden="true">★</span>
        <span class="sr-only">1:不満</span>
      </label>
    </div>

    <p class="sr-feedback" id="sr-feedback" role="status">星を選択してください</p>
  </div>
</div>

【CSS】
* { box-sizing: border-box; }

body {
  margin: 0;
  min-height: 100vh;
  display: grid;
  place-items: center;
  padding: 24px;
  font-family: "Segoe UI", "Hiragino Kaku Gothic ProN", system-ui, sans-serif;
  /* 上品なローズ系グラデ背景 */
  background: linear-gradient(135deg, #fff1f2 0%, #ffe4e6 50%, #fce7f3 100%);
  color: #1f2937;
}

.stage { width: 100%; display: grid; place-items: center; }

.sr-card {
  width: min(340px, 92vw);
  padding: 32px 28px 26px;
  background: #fff;
  border-radius: 20px;
  box-shadow: 0 24px 56px -26px rgba(190, 24, 93, 0.3);
  text-align: center;
}

.sr-question {
  margin: 0 0 20px;
  font-size: 0.98rem;
  font-weight: 600;
  color: #4a1d2a;
}

/* DOMは5→1の逆順。row-reverseで見た目を1→5に戻し、
   後続セレクタで「選択/ホバーした星までを塗る」古典テクニックを使う */
.sr-stars {
  display: flex;
  flex-direction: row-reverse;
  justify-content: center;
  gap: 6px;
}

.sr-star {
  position: relative;
  cursor: pointer;
  line-height: 1;
}
.sr-input {
  position: absolute;
  opacity: 0;
  width: 1px;
  height: 1px;
}

.sr-icon {
  display: block;
  font-size: 2.1rem;
  color: #e2d4d8;
  transition: color 0.16s ease, transform 0.12s ease;
}

/* ホバー中:ホバー星+それより手前(DOM上で後ろ)の星も塗る */
.sr-star:hover .sr-icon,
.sr-star:hover ~ .sr-star .sr-icon {
  color: #f59e0b;
}
.sr-star:hover .sr-icon { transform: scale(1.12); }

/* 確定済み:チェックされた星+それより手前の星も塗る */
.sr-star:has(.sr-input:checked) .sr-icon,
.sr-star:has(.sr-input:checked) ~ .sr-star .sr-icon {
  color: #f59e0b;
}

.sr-input:focus-visible ~ .sr-icon {
  outline: none;
  box-shadow: 0 0 0 3px rgba(244, 63, 94, 0.35);
  border-radius: 6px;
}

.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.sr-feedback {
  margin: 18px 0 0;
  font-size: 0.86rem;
  font-weight: 600;
  color: #9d174d;
  transition: transform 0.18s ease;
}
.sr-feedback.is-confirmed { animation: sr-pop 0.28s ease; }
@keyframes sr-pop {
  0% { transform: scale(0.9); }
  60% { transform: scale(1.06); }
  100% { transform: scale(1); }
}

@media (prefers-reduced-motion: reduce) {
  .sr-icon, .sr-feedback { transition: none; }
  .sr-feedback.is-confirmed { animation: none; }
}

【JavaScript】
// 星評価入力:クリックで確定した値に応じて評価ラベルを表示する
(function () {
  var group = document.getElementById("sr-stars");
  var feedback = document.getElementById("sr-feedback");
  if (!group || !feedback) return;

  var labels = {
    1: "不満",
    2: "やや不満",
    3: "普通",
    4: "満足",
    5: "大変満足",
  };

  group.addEventListener("change", function (e) {
    var target = e.target;
    if (!target || !target.classList || !target.classList.contains("sr-input")) return;
    var value = parseInt(target.value, 10);
    var label = labels[value] || "";
    feedback.textContent = "評価:" + label + "(" + value + "/5)";
    feedback.classList.remove("is-confirmed");
    void feedback.offsetWidth;
    feedback.classList.add("is-confirmed");
  });
})();

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

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