Skip to content

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默认值minmax 的中间值

详细说明

实时显示滑块值

滑块控件默认不显示当前数值,需要通过 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;
}

最佳实践

  1. 始终显示当前值:滑块位置不够精确,必须配合 <output><span> 显示数值
  2. 合理设置 step:根据业务需求选择步进粒度,避免太细或太粗
  3. 提供精确输入方式:对于需要精确数值的场景,同时提供数字输入框
  4. 自定义样式:使用 CSS 统一跨浏览器外观,提升用户体验
  5. 填充进度颜色:通过动态渐变背景显示已选择范围
  6. 配合标签:确保每个滑块都有 <label> 关联,提升可访问性

下一节

继续学习:color 颜色选择器

参考链接