吹き出し付きレンジスライダー
つまみの位置に金額の吹き出しが追従するレンジ入力。CSSカスタムプロパティで塗りと吹き出し位置を連動させ、価格や予算選択に使えます。
ライブデモ
使用例(お題: SaaS FlowDesk)
この技法を「SaaS FlowDesk」というテーマのダミーサイトで実際に使った例です。
HTML
<div class="fd-screen">
<div class="rb-card">
<div class="fd-brand"><span class="fd-mark">◇</span> FlowDesk</div>
<h2 class="rb-title">チーム規模を選んで料金を試算</h2>
<p class="rb-lead">利用人数のスライダーを動かすと、<br>月額のお見積りが自動で更新されます。</p>
<div class="rb-row">
<div class="rb-track-wrap">
<!-- つまみに人数の吹き出しが追従(技法の主役) -->
<output class="rb-bubble" id="rb-bubble">10 人</output>
<input id="rb-range" class="rb-range" type="range" min="1" max="100" step="1" value="10">
</div>
</div>
<div class="rb-scale">
<span>1人</span><span>100人</span>
</div>
<div class="rb-quote">
<span class="rb-quote__label">月額お見積り(Pro / 1人 ¥1,200)</span>
<span class="rb-quote__price" id="rb-price">¥12,000</span>
</div>
</div>
</div>
CSS
* { box-sizing: border-box; }
body {
margin: 0;
min-height: 100vh;
display: grid;
place-items: center;
font-family: "Segoe UI", "Hiragino Kaku Gothic ProN", system-ui, sans-serif;
background:
radial-gradient(80% 60% at 90% 0%, rgba(79, 124, 255, 0.4), transparent 60%),
#0f1b34;
color: #e8edf7;
}
.rb-card {
width: min(440px, 94vw);
padding: 24px 28px 24px;
background: #16244a;
border: 1px solid rgba(120, 150, 220, 0.22);
border-radius: 16px;
box-shadow: 0 26px 60px -24px rgba(0, 0, 0, 0.8);
}
.fd-brand {
display: flex; align-items: center; gap: 7px; margin-bottom: 12px;
font-size: 0.8rem; font-weight: 700; letter-spacing: 0.06em; color: #9fb6f0;
}
.fd-mark { color: #4f7cff; font-size: 1rem; }
.rb-title { margin: 0 0 8px; font-size: 1.12rem; font-weight: 800; }
.rb-lead { margin: 0 0 30px; font-size: 0.8rem; line-height: 1.6; color: #8ea0c4; }
.rb-row { padding-top: 16px; }
.rb-track-wrap { position: relative; }
/* 吹き出し。--posでつまみ位置に追従 */
.rb-bubble {
position: absolute; top: -38px;
left: var(--pos, 50%);
transform: translateX(-50%);
padding: 5px 12px;
font-size: 0.82rem; font-weight: 700; color: #fff;
white-space: nowrap;
background: linear-gradient(135deg, #4f7cff, #2f5fe0);
border-radius: 8px;
box-shadow: 0 8px 16px -6px rgba(79, 124, 255, 0.7);
transition: left 0.05s linear;
}
.rb-bubble::after {
content: ""; position: absolute; left: 50%; bottom: -5px;
transform: translateX(-50%);
border: 6px solid transparent; border-top-color: #3060e3; border-bottom: 0;
}
/* レンジ本体 */
.rb-range {
-webkit-appearance: none; appearance: none;
width: 100%; height: 8px; border-radius: 999px;
background: linear-gradient(90deg, #4f7cff 0 var(--pos, 50%), rgba(120,150,220,0.25) var(--pos, 50%) 100%);
outline: none; cursor: pointer;
}
.rb-range::-webkit-slider-thumb {
-webkit-appearance: none; appearance: none;
width: 22px; height: 22px; border-radius: 50%;
background: #fff; border: 3px solid #4f7cff;
box-shadow: 0 3px 8px rgba(0,0,0,0.4); cursor: pointer;
transition: transform 0.12s ease;
}
.rb-range::-webkit-slider-thumb:hover { transform: scale(1.15); }
.rb-range::-moz-range-thumb {
width: 20px; height: 20px; border-radius: 50%;
background: #fff; border: 3px solid #4f7cff; cursor: pointer;
}
.rb-scale {
display: flex; justify-content: space-between;
margin-top: 11px; font-size: 0.72rem; color: #6f80a6;
}
.rb-quote {
display: flex; align-items: center; justify-content: space-between;
margin-top: 18px; padding: 13px 16px;
background: rgba(79, 124, 255, 0.12);
border: 1px solid rgba(79, 124, 255, 0.3);
border-radius: 12px;
}
.rb-quote__label { font-size: 0.72rem; color: #9fb6f0; }
.rb-quote__price { font-size: 1.25rem; font-weight: 800; color: #fff; }
@media (prefers-reduced-motion: reduce) {
.rb-bubble, .rb-range::-webkit-slider-thumb { transition: none; }
}
JavaScript
const range = document.getElementById("rb-range");
const bubble = document.getElementById("rb-bubble");
const price = document.getElementById("rb-price");
const PER_SEAT = 1200; // 1人あたり月額
// つまみ位置を割合(%)で計算し、吹き出し・塗り・見積りに反映
function update() {
if (!range) return;
const min = Number(range.min) || 0;
const max = Number(range.max) || 100;
const val = Number(range.value);
const ratio = (val - min) / (max - min); // 0〜1
// つまみ幅ぶんの補正で端でもはみ出さないように
const pos = `calc(${ratio * 100}% + ${(0.5 - ratio) * 22}px)`;
range.style.setProperty("--pos", `${ratio * 100}%`);
if (bubble) {
bubble.style.setProperty("--pos", pos);
bubble.textContent = `${val} 人`;
}
// 月額見積りを再計算
if (price) price.textContent = "¥" + (val * PER_SEAT).toLocaleString("ja-JP");
}
if (range) {
range.addEventListener("input", update);
update();
}
コード
HTML
<div class="stage">
<div class="rb-card">
<h2 class="rb-title">予算を選択</h2>
<div class="rb-row">
<div class="rb-track-wrap">
<!-- 値を吹き出しで追従表示 -->
<output class="rb-bubble" id="rb-bubble">¥50,000</output>
<input id="rb-range" class="rb-range" type="range" min="0" max="100000" step="1000" value="50000">
</div>
</div>
<div class="rb-scale">
<span>¥0</span><span>¥100,000</span>
</div>
<p class="rb-note">スライダーを動かすと吹き出しが追従します</p>
</div>
</div>
CSS
* { box-sizing: border-box; }
body {
margin: 0;
min-height: 100vh;
display: grid;
place-items: center;
font-family: "Segoe UI", "Hiragino Kaku Gothic ProN", system-ui, sans-serif;
background: linear-gradient(135deg, #2b1055, #7597de);
color: #1f2937;
}
.stage { width: 100%; padding: 22px; display: grid; place-items: center; }
.rb-card {
width: min(420px, 94vw);
padding: 30px 28px 24px;
background: #fff;
border-radius: 18px;
box-shadow: 0 24px 56px -24px rgba(20, 10, 50, 0.6);
}
.rb-title { margin: 0 0 26px; font-size: 1.1rem; color: #1e293b; }
.rb-row { padding-top: 18px; }
.rb-track-wrap { position: relative; }
/* 吹き出し。--posでつまみ位置に追従 */
.rb-bubble {
position: absolute;
top: -38px;
left: var(--pos, 50%);
transform: translateX(-50%);
padding: 5px 11px;
font-size: 0.82rem;
font-weight: 700;
color: #fff;
white-space: nowrap;
background: linear-gradient(135deg, #7c3aed, #6366f1);
border-radius: 8px;
box-shadow: 0 8px 16px -6px rgba(124, 58, 237, 0.6);
transition: left 0.05s linear;
}
.rb-bubble::after {
content: "";
position: absolute;
left: 50%; bottom: -5px;
transform: translateX(-50%);
border: 6px solid transparent;
border-top-color: #6b4ce0;
border-bottom: 0;
}
/* レンジ本体。塗りは--posのグラデで表現 */
.rb-range {
-webkit-appearance: none;
appearance: none;
width: 100%;
height: 8px;
border-radius: 999px;
background: linear-gradient(90deg, #7c3aed 0 var(--pos, 50%), #e5e7eb var(--pos, 50%) 100%);
outline: none;
cursor: pointer;
}
.rb-range::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 22px; height: 22px;
border-radius: 50%;
background: #fff;
border: 3px solid #7c3aed;
box-shadow: 0 3px 8px rgba(0,0,0,0.25);
cursor: pointer;
transition: transform 0.12s ease;
}
.rb-range::-webkit-slider-thumb:hover { transform: scale(1.15); }
.rb-range::-moz-range-thumb {
width: 20px; height: 20px;
border-radius: 50%;
background: #fff;
border: 3px solid #7c3aed;
cursor: pointer;
}
.rb-scale {
display: flex; justify-content: space-between;
margin-top: 12px;
font-size: 0.74rem;
color: #94a3b8;
}
.rb-note { margin: 18px 0 0; font-size: 0.78rem; color: #94a3b8; text-align: center; }
@media (prefers-reduced-motion: reduce) {
.rb-bubble, .rb-range::-webkit-slider-thumb { transition: none; }
}
JavaScript
const range = document.getElementById("rb-range");
const bubble = document.getElementById("rb-bubble");
// 金額を ¥ 区切りで整形
const yen = (n) => "¥" + Number(n).toLocaleString("ja-JP");
// つまみ位置を割合(%)で計算し、吹き出しと塗りに反映
function update() {
if (!range) return;
const min = Number(range.min) || 0;
const max = Number(range.max) || 100;
const val = Number(range.value);
const ratio = (val - min) / (max - min); // 0〜1
// つまみ幅ぶんの補正で端でもはみ出さないように
const pos = `calc(${ratio * 100}% + ${(0.5 - ratio) * 22}px)`;
range.style.setProperty("--pos", `${ratio * 100}%`);
if (bubble) {
bubble.style.setProperty("--pos", pos);
bubble.textContent = yen(val);
}
}
if (range) {
range.addEventListener("input", update);
update();
}
🤖 AIエージェント用プロンプト
このままコピーしてAIに貼り付け「追加する場所」だけ書き換えればOK
あなたは熟練のフロントエンドエンジニアです。私のWebサイトに「吹き出し付きレンジスライダー」の効果を追加してください。
# 追加してほしい効果
吹き出し付きレンジスライダー(フォーム & 入力)
つまみの位置に金額の吹き出しが追従するレンジ入力。CSSカスタムプロパティで塗りと吹き出し位置を連動させ、価格や予算選択に使えます。
# 追加する場所
👉【ここに対象箇所を記入:例「トップのヒーローセクション」「お問い合わせボタン」「記事カードの一覧」など】
# 参考実装(この見た目・挙動を再現してください)
【HTML】
<div class="stage">
<div class="rb-card">
<h2 class="rb-title">予算を選択</h2>
<div class="rb-row">
<div class="rb-track-wrap">
<!-- 値を吹き出しで追従表示 -->
<output class="rb-bubble" id="rb-bubble">¥50,000</output>
<input id="rb-range" class="rb-range" type="range" min="0" max="100000" step="1000" value="50000">
</div>
</div>
<div class="rb-scale">
<span>¥0</span><span>¥100,000</span>
</div>
<p class="rb-note">スライダーを動かすと吹き出しが追従します</p>
</div>
</div>
【CSS】
* { box-sizing: border-box; }
body {
margin: 0;
min-height: 100vh;
display: grid;
place-items: center;
font-family: "Segoe UI", "Hiragino Kaku Gothic ProN", system-ui, sans-serif;
background: linear-gradient(135deg, #2b1055, #7597de);
color: #1f2937;
}
.stage { width: 100%; padding: 22px; display: grid; place-items: center; }
.rb-card {
width: min(420px, 94vw);
padding: 30px 28px 24px;
background: #fff;
border-radius: 18px;
box-shadow: 0 24px 56px -24px rgba(20, 10, 50, 0.6);
}
.rb-title { margin: 0 0 26px; font-size: 1.1rem; color: #1e293b; }
.rb-row { padding-top: 18px; }
.rb-track-wrap { position: relative; }
/* 吹き出し。--posでつまみ位置に追従 */
.rb-bubble {
position: absolute;
top: -38px;
left: var(--pos, 50%);
transform: translateX(-50%);
padding: 5px 11px;
font-size: 0.82rem;
font-weight: 700;
color: #fff;
white-space: nowrap;
background: linear-gradient(135deg, #7c3aed, #6366f1);
border-radius: 8px;
box-shadow: 0 8px 16px -6px rgba(124, 58, 237, 0.6);
transition: left 0.05s linear;
}
.rb-bubble::after {
content: "";
position: absolute;
left: 50%; bottom: -5px;
transform: translateX(-50%);
border: 6px solid transparent;
border-top-color: #6b4ce0;
border-bottom: 0;
}
/* レンジ本体。塗りは--posのグラデで表現 */
.rb-range {
-webkit-appearance: none;
appearance: none;
width: 100%;
height: 8px;
border-radius: 999px;
background: linear-gradient(90deg, #7c3aed 0 var(--pos, 50%), #e5e7eb var(--pos, 50%) 100%);
outline: none;
cursor: pointer;
}
.rb-range::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 22px; height: 22px;
border-radius: 50%;
background: #fff;
border: 3px solid #7c3aed;
box-shadow: 0 3px 8px rgba(0,0,0,0.25);
cursor: pointer;
transition: transform 0.12s ease;
}
.rb-range::-webkit-slider-thumb:hover { transform: scale(1.15); }
.rb-range::-moz-range-thumb {
width: 20px; height: 20px;
border-radius: 50%;
background: #fff;
border: 3px solid #7c3aed;
cursor: pointer;
}
.rb-scale {
display: flex; justify-content: space-between;
margin-top: 12px;
font-size: 0.74rem;
color: #94a3b8;
}
.rb-note { margin: 18px 0 0; font-size: 0.78rem; color: #94a3b8; text-align: center; }
@media (prefers-reduced-motion: reduce) {
.rb-bubble, .rb-range::-webkit-slider-thumb { transition: none; }
}
【JavaScript】
const range = document.getElementById("rb-range");
const bubble = document.getElementById("rb-bubble");
// 金額を ¥ 区切りで整形
const yen = (n) => "¥" + Number(n).toLocaleString("ja-JP");
// つまみ位置を割合(%)で計算し、吹き出しと塗りに反映
function update() {
if (!range) return;
const min = Number(range.min) || 0;
const max = Number(range.max) || 100;
const val = Number(range.value);
const ratio = (val - min) / (max - min); // 0〜1
// つまみ幅ぶんの補正で端でもはみ出さないように
const pos = `calc(${ratio * 100}% + ${(0.5 - ratio) * 22}px)`;
range.style.setProperty("--pos", `${ratio * 100}%`);
if (bubble) {
bubble.style.setProperty("--pos", pos);
bubble.textContent = yen(val);
}
}
if (range) {
range.addEventListener("input", update);
update();
}
# 外部ライブラリ
なし(追加ライブラリ不要)
# 守ってほしいこと
- 既存のHTML構造・レイアウト・デザインを壊さないこと。必要に応じてクラス名・色・サイズを私のサイトに合わせて調整してよい。
- クラス名やidが既存と衝突しないよう、必要なら接頭辞で名前空間を分けること。
- レスポンシブ対応と prefers-reduced-motion への配慮を入れること。
- 私のサイトのフレームワーク(React / Vue / 素のHTML など)に合わせて実装すること。不明な場合は素のHTML/CSS/JSで提示し、組み込み手順も説明すること。
- 変更後の確認手順も簡潔に教えてください。