range 滑块输入
<input type="range"> 是 HTML5 引入的滑块控件,允许用户通过拖动滑块在指定的数值范围内选择一个值。该控件适用于音量调节、亮度控制、价格筛选等需要直觉化数值选择的场景,提供比数字输入框更流畅的交互体验。
前置知识
阅读本节前,建议先了解:week 周输入
基础概念
什么是 range 输入
type="range" 输入框渲染为一个滑动条(slider),用户通过拖动滑块来选择数值。主要特点:
- 直觉化交互:拖动滑块比手动输入数字更直观
- 范围限制:自动将值约束在 min/max 范围内
- 连续调节:适合需要微调的参数
- 触摸友好:在移动设备上滑动操作自然流畅
- 视觉反馈:滑块位置直观反映当前值
浏览器支持
| 浏览器 | 支持情况 | 控件外观 |
|---|---|---|
| Chrome | ✅ 完整支持 | 水平滑块(蓝色) |
| Firefox | ✅ 完整支持 | 水平滑块(灰色) |
| Safari | ✅ 完整支持 | 水平滑块(灰色) |
| Edge | ✅ 完整支持 | 水平滑块(蓝色) |
| Opera | ✅ 完整支持 | 水平滑块(蓝色) |
提交值
range 提交的值始终为数字类型字符串,默认范围是 0 到 100:
volume=75语法
基本用法
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>range 滑块示例</title>
</head>
<body>
<h2>音量控制</h2>
<form>
<label for="volume">音量:</label>
<input type="range" id="volume" name="volume">
<span id="volume-value">50</span>
<button type="submit">保存</button>
</form>
<script>
// 实时显示滑块值
const volume = document.getElementById('volume');
const volumeValue = document.getElementById('volume-value');
volume.addEventListener('input', function () {
volumeValue.textContent = this.value;
});
</script>
</body>
</html>min、max 和 step 属性
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>range 属性示例</title>
</head>
<body>
<h2>温度调节</h2>
<form>
<label for="temperature">温度:</label>
<input
type="range"
id="temperature"
name="temperature"
min="16"
max="32"
step="0.5"
value="24"
>
<span id="temp-display">24°C</span>
</form>
</body>
</html>| 属性 | 说明 | 默认值 |
|---|---|---|
min | 最小值 | 0 |
max | 最大值 | 100 |
step | 步进值 | 1 |
value | 默认值 | min 和 max 的中间值 |
详细说明
实时显示滑块值
滑块控件默认不显示当前数值,需要通过 JavaScript 配合 <output> 元素或 <span> 显示:
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>实时显示滑块值</title>
</head>
<body>
<h2>滑块值实时显示</h2>
<form oninput="result.value = distance.value">
<label for="distance">距离:</label>
<input
type="range"
id="distance"
name="distance"
min="1"
max="100"
value="50"
>
<output name="result" for="distance">50</output> km
</form>
</body>
</html>与 output 元素配合
使用 <output> 元素语义化地显示计算结果:
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>range 与 output 配合</title>
</head>
<body>
<h2>贷款计算器</h2>
<form id="calc-form" oninput="updateResult()">
<div>
<label for="amount">贷款金额:</label>
<input type="range" id="amount" name="amount"
min="10" max="500" step="10" value="100">
<output for="amount" id="amount-out">100</output> 万元
</div>
<div>
<label for="years">贷款年限:</label>
<input type="range" id="years" name="years"
min="1" max="30" step="1" value="20">
<output for="years" id="years-out">20</output> 年
</div>
<div>
<label for="rate">年利率:</label>
<input type="range" id="rate" name="rate"
min="3" max="8" step="0.1" value="4.9">
<output for="rate" id="rate-out">4.9</output> %
</div>
<p>月供:<output id="monthly" for="amount years rate">--</output> 元</p>
</form>
<script>
function updateResult() {
// 更新各 output 的值
document.getElementById('amount-out').value = document.getElementById('amount').value;
document.getElementById('years-out').value = document.getElementById('years').value;
document.getElementById('rate-out').value = document.getElementById('rate').value;
// 计算月供
const amount = parseFloat(document.getElementById('amount').value) * 10000;
const years = parseInt(document.getElementById('years').value);
const rate = parseFloat(document.getElementById('rate').value) / 100 / 12;
const months = years * 12;
if (rate > 0) {
const monthly = amount * rate * Math.pow(1 + rate, months)
/ (Math.pow(1 + rate, months) - 1);
document.getElementById('monthly').value = Math.round(monthly).toLocaleString();
}
}
// 初始化
updateResult();
</script>
</body>
</html>CSS 自定义样式
通过 CSS 伪元素自定义滑块外观(不同浏览器需要不同前缀):
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>range CSS 自定义</title>
<style>
/* 通用样式 */
input[type="range"] {
-webkit-appearance: none; /* 去除默认样式 */
appearance: none;
width: 300px;
height: 8px;
border-radius: 4px;
background: #e0e0e0;
outline: none;
margin: 10px 0;
}
/* WebKit (Chrome, Safari, Edge) 滑块样式 */
input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 24px;
height: 24px;
border-radius: 50%;
background: #4a90d9;
cursor: pointer;
border: 2px solid #fff;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
transition: transform 0.15s ease;
}
input[type="range"]::-webkit-slider-thumb:hover {
transform: scale(1.2);
}
input[type="range"]::-webkit-slider-thumb:active {
background: #357abd;
transform: scale(1.1);
}
/* Firefox 滑块样式 */
input[type="range"]::-moz-range-thumb {
width: 24px;
height: 24px;
border-radius: 50%;
background: #4a90d9;
cursor: pointer;
border: 2px solid #fff;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
}
/* 进度条颜色(已选择部分) */
input[type="range"]::-webkit-slider-runnable-track {
height: 8px;
border-radius: 4px;
}
/* 自定义主题 - 红色滑块 */
.range-red {
background: linear-gradient(to right, #e74c3c 0%, #e74c3c var(--progress, 50%), #ddd var(--progress, 50%), #ddd 100%);
}
.range-red::-webkit-slider-thumb {
background: #e74c3c;
}
.range-red::-moz-range-thumb {
background: #e74c3c;
}
/* 垂直滑块 */
.vertical {
writing-mode: vertical-lr;
direction: rtl;
width: 8px;
height: 300px;
}
</style>
</head>
<body>
<h2>自定义滑块样式</h2>
<h3>默认蓝色滑块</h3>
<label for="slider1">亮度:</label>
<input type="range" id="slider1" min="0" max="100" value="70">
<h3>红色主题滑块</h3>
<label for="slider2">温度:</label>
<input type="range" class="range-red" id="slider2" min="0" max="100" value="60">
<h3>垂直滑块</h3>
<input type="range" class="vertical" id="slider3" min="0" max="100" value="50">
</body>
</html>动态填充进度颜色
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>动态进度颜色</title>
<style>
input[type="range"] {
-webkit-appearance: none;
appearance: none;
width: 100%;
max-width: 400px;
height: 10px;
border-radius: 5px;
background: #eee;
outline: none;
}
input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none;
width: 22px;
height: 22px;
border-radius: 50%;
background: #4a90d9;
cursor: pointer;
border: 2px solid #fff;
box-shadow: 0 1px 4px rgba(0,0,0,0.3);
}
input[type="range"]::-moz-range-thumb {
width: 22px;
height: 22px;
border-radius: 50%;
background: #4a90d9;
cursor: pointer;
border: 2px solid #fff;
}
</style>
</head>
<body>
<h2>进度颜色填充</h2>
<label for="progress-range">完成进度:</label>
<input type="range" id="progress-range" min="0" max="100" value="60">
<span id="progress-text">60%</span>
<script>
const range = document.getElementById('progress-range');
const text = document.getElementById('progress-text');
function updateGradient() {
const val = range.value;
const min = range.min || 0;
const max = range.max || 100;
const percent = ((val - min) / (max - min)) * 100;
// 动态设置背景渐变
range.style.background =
`linear-gradient(to right, #4a90d9 ${percent}%, #eee ${percent}%)`;
text.textContent = `${val}%`;
}
range.addEventListener('input', updateGradient);
updateGradient(); // 初始化
</script>
</body>
</html>实战示例
RGB 颜色混合器
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>RGB 颜色混合器</title>
<style>
body { font-family: sans-serif; max-width: 600px; margin: 40px auto; }
.slider-group { margin-bottom: 12px; }
.slider-group label { display: inline-block; width: 40px; font-weight: bold; }
input[type="range"] {
-webkit-appearance: none;
appearance: none;
width: 300px;
height: 10px;
border-radius: 5px;
outline: none;
}
input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none;
width: 20px; height: 20px;
border-radius: 50%; cursor: pointer;
border: 2px solid #fff;
box-shadow: 0 1px 4px rgba(0,0,0,0.3);
}
#red { background: linear-gradient(to right, #000, #f00); }
#red::-webkit-slider-thumb { background: #f00; }
#green { background: linear-gradient(to right, #000, #0f0); }
#green::-webkit-slider-thumb { background: #0f0; }
#blue { background: linear-gradient(to right, #000, #00f); }
#blue::-webkit-slider-thumb { background: #00f; }
.color-box {
width: 200px; height: 200px;
border-radius: 12px;
border: 2px solid #ddd;
margin-top: 16px;
display: flex;
align-items: center;
justify-content: center;
font-family: monospace;
font-size: 18px;
color: #fff;
text-shadow: 1px 1px 2px rgba(0,0,0,0.5);
}
</style>
</head>
<body>
<h2>RGB 颜色混合器</h2>
<div class="slider-group">
<label>R</label>
<input type="range" id="red" min="0" max="255" value="100">
<span id="r-val">100</span>
</div>
<div class="slider-group">
<label>G</label>
<input type="range" id="green" min="0" max="255" value="150">
<span id="g-val">150</span>
</div>
<div class="slider-group">
<label>B</label>
<input type="range" id="blue" min="0" max="255" value="200">
<span id="b-val">200</span>
</div>
<div class="color-box" id="color-box">
<span id="color-code">#6496C8</span>
</div>
<script>
function updateColor() {
const r = document.getElementById('red').value;
const g = document.getElementById('green').value;
const b = document.getElementById('blue').value;
document.getElementById('r-val').textContent = r;
document.getElementById('g-val').textContent = g;
document.getElementById('b-val').textContent = b;
const hex = '#' + [r, g, b].map(v =>
parseInt(v).toString(16).padStart(2, '0')
).join('').toUpperCase();
document.getElementById('color-box').style.backgroundColor =
`rgb(${r}, ${g}, ${b})`;
document.getElementById('color-code').textContent = hex;
}
['red', 'green', 'blue'].forEach(id => {
document.getElementById(id).addEventListener('input', updateColor);
});
updateColor();
</script>
</body>
</html>注意事项
用户无法精确输入
range 控件只支持拖动选择,用户无法直接键入精确数值。对于需要精确输入的场景,应同时提供数字输入框:
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>range 与 number 配合</title>
</head>
<body>
<h2>价格筛选</h2>
<form>
<input type="range" id="price" name="price" min="0" max="10000" step="100" value="5000"
oninput="priceNum.value = this.value">
<input type="number" id="priceNum" name="price_num" min="0" max="10000" step="100" value="5000"
oninput="price.value = this.value">
<span>元</span>
</form>
</body>
</html>step 属性的影响
step 决定了滑块可停靠的离散值:
html
<!-- 整数步进 -->
<input type="range" min="0" max="10" step="1"> <!-- 可选 0,1,2...10 -->
<!-- 浮点步进 -->
<input type="range" min="0" max="1" step="0.01"> <!-- 可选 0.00,0.01...1.00 -->
<!-- 无步进限制 -->
<input type="range" min="0" max="10" step="any"> <!-- 任意值 -->无内置验证样式
range 控件不像其他输入类型那样在验证失败时显示明显的视觉提示(如红色边框),因为滑块值始终在 min/max 范围内。
移动端兼容性
在 iOS 上,range 滑块可能有最小宽度,超出容器时会溢出。需要通过 CSS 限制宽度:
css
input[type="range"] {
max-width: 100%;
box-sizing: border-box;
}最佳实践
- 始终显示当前值:滑块位置不够精确,必须配合
<output>或<span>显示数值 - 合理设置 step:根据业务需求选择步进粒度,避免太细或太粗
- 提供精确输入方式:对于需要精确数值的场景,同时提供数字输入框
- 自定义样式:使用 CSS 统一跨浏览器外观,提升用户体验
- 填充进度颜色:通过动态渐变背景显示已选择范围
- 配合标签:确保每个滑块都有
<label>关联,提升可访问性
下一节
继续学习:color 颜色选择器