HTML 中的范围输入是这样的
<input type="range" name="quantity" min="1" max="10">
在 支持它的浏览器中,它们看起来是这样的

这很棒。您可以将其用于任何需要从用户那里收集具有强制最小值和最大值的数字的情况。
但是您有没有注意到任何奇怪的地方?仅仅是范围输入本身并不会向用户传达他们实际将提交的数字。现在,如果您的输入类似于“您感觉如何?左边表示悲伤,右边表示快乐。” - 那么没关系,您可能不需要向用户显示数字。但我敢打赌,您需要显示数字的情况比不显示数字的情况更为常见。
公平地说,规范中提到
input 元素表示用于将元素的值设置为表示数字的字符串的控件,**但需要注意的是,确切的值并不重要**,允许 UA 提供比数字状态更简单的界面。
但是,拜托,仅仅因为我们想要一个很酷的滑块并不意味着我们应该阻止用户知道提交的值。我不会说浏览器应该更改其 UI 控件以显示该数字。我的意思是,我们应该自己构建它!
这是使用<output>
标签的完美用例,该标签专门用于表单元素计算的值。以下是如何使用它的一个超简单实现
<input type="range" name="foo">
<output for="foo" onforminput="value = foo.valueAsNumber;"></output>
更新!使用原生 JavaScript 的新版本,效果也更好。
我们的目标是显示一个“气泡”,其中显示范围输入的当前值。

从输入值设置“气泡”的值只是提取范围值并将其放在气泡中的问题
range.addEventListener("input", () => {
bubble.innerHTML = rangel.value;
});
技巧在于定位气泡沿着范围输入,使其与“拇指”一起滑动。为此,我们需要计算气泡需要向左移动多少%。因此,让我们创建一个函数来执行此操作,以使事情更简洁
range.addEventListener("input", () => {
setBubble(range, bubble);
});
function setBubble(range, bubble) {
const val = range.value;
const min = range.min ? range.min : 0;
const max = range.max ? range.max : 100;
const newVal = Number(((val - min) * 100) / (max - min));
bubble.innerHTML = val;
// Sorta magic numbers based on size of the native UI thumb
bubble.style.left = newVal = "%";
}
在这里,我们确保考虑了范围输入的 min 和 max 属性,并根据该范围内的当前值计算 0-100 之间的百分比位置。并非所有范围都是默认的 0-100 数字,因此假设范围在 0 到 200 的范围内值为 50,则为 25%。这考虑到了这一点。
但它有一个恼人的缺陷:气泡在开始时太靠左,在结束时太靠右。在范围输入上,拇指不会从左边缘悬挂,因此其中心位于开头,结尾处也是如此。就像滚动条一样,拇指的边缘停在轨道内。
我们可以在那里使用一些神奇的数字,这些数字似乎在不同浏览器之间都能很好地工作
// Sorta magic numbers based on size of the native UI thumb
bubble.style.left = `calc(${newVal}% + (${8 - newVal * 0.15}px))`;
这是最终演示
我之所以受到启发去研究这个,是因为读者 Max Globa 编写了他们的版本,我将在这里发布
Max 版本的一个很酷的方面是范围输入是 CSS 样式的,因此拇指的确切大小是已知的。JavaScript 数学中有一些感觉有点神奇的数字,但至少它们基于 CSS 中关于拇指大小的真实数字。
其他版本
Dave Olsen 移植了(原始)想法,使其不依赖于 jQuery。这是该版本
Sean Stopnik
simurai
Vincent Durand
不要忘记 范围输入可以有 datalist,它们会在上面放置一些小刻度,这有点酷。
Ana Tudor 有 一个庞大的集合,其中许多通过其设计指示当前值。
😬 本文原始版本中的旧版本(jQuery,效果不佳)
出于历史原因,将其保留在此处。
让我们引入我们的朋友 jQuery 并开始我们的 CSS。目标如下。任何范围输入,任何时间,任何最小值/最大值/步长 - 我们都会在其上方显示一个气泡,显示当前值。

让我们首先设置 output 元素的样式。我们将将其绝对定位在输入上方。一旦我们通过 JavaScript 确定了它应该是什么,这将使我们能够调整左侧的值。我们将用渐变和圆角来装饰它,甚至使用伪元素添加一个小指针三角形。
output {
position: absolute;
background-image: linear-gradient(top, #444444, #999999);
width: 40px;
height: 30px;
text-align: center;
color: white;
border-radius: 10px;
display: inline-block;
font: bold 15px/30px Georgia;
bottom: 175%;
left: 0;
margin-left: -1%;
}
output:after {
content: "";
position: absolute;
width: 0;
height: 0;
border-top: 10px solid #999999;
border-left: 5px solid transparent;
border-right: 5px solid transparent;
top: 100%;
left: 50%;
margin-left: -5px;
margin-top: -1px;
}
现在我们需要做的是观察所有范围输入的值变化。我们的目标是使气泡的左侧位置与滑块同步移动。这并不是世界上最简单的事情,因为滑块可以是任何宽度,并且可以具有任何最小值或最大值。我们将不得不进行一些计算。以下是所有 jQuery JavaScript 代码,已添加注释
// DOM Ready
$(function() {
var el, newPoint, newPlace, offset;
// Select all range inputs, watch for change
$("input[type='range']").change(function() {
// Cache this for efficiency
el = $(this);
// Measure width of range input
width = el.width();
// Figure out placement percentage between left and right of input
newPoint = (el.val() - el.attr("min")) / (el.attr("max") - el.attr("min"));
// Janky value to get pointer to line up better
offset = -1.3;
// Prevent bubble from going beyond left or right (unsupported browsers)
if (newPoint < 0) { newPlace = 0; }
else if (newPoint > 1) { newPlace = width; }
else { newPlace = width * newPoint + offset; offset -= newPoint; }
// Move bubble
el
.next("output")
.css({
left: newPlace,
marginLeft: offset + "%"
})
.text(el.val());
})
// Fake a change to position bubble at page load
.trigger('change');
});
其中一个糟糕的部分是该1.3
值。我试图将气泡三角形的尖端与滑块的中心对齐。这并不容易,因为滑块的中心永远不会完全位于左侧或右侧。该值并不完美,也并非完美实现,但总比没有好。
作为奖励,不支持范围输入的浏览器仍然可以获得气泡操作。

以上代码依赖于范围输入具有指定的min
和max
值。如果没有,它就会中断。我认为在不指定这些内容的情况下使用范围输入会很奇怪,尽管如果您不指定,它们似乎默认为 0 和 100。为了防范这种情况,您需要获取每个属性,对其进行测试,如果看起来不对,则进行修复。例如
var minValue, maxValue;
if (!el.attr("min")) { minValue = 0; } else { minValue = el.attr("min"); }
…然后在数学中使用minValue
变量。并对最大值执行类似的操作。无论如何,这是实时演示
这太棒了!谢谢 Chris!
如何处理仅在滑动时出现,然后在释放时淡出的气泡?:P
它们还不错,但是,如果这是原生实现的,那将会非常酷。
顺便说一句,如果“不稳定”值可以在滑块值每次更改时随机(当然在一定范围内)变化,那么在 Windows 中看到的奇怪偏移(Mac 和 Windows 滑块对齐方式不同)将不那么突出。但是,您已经尽力而为,它比其他“复杂”的数学方法所能产生的结果要好。
此外,当鼠标不在滑块上时,使
<output>
变暗会很酷。哦,这让我想到一个问题:例如,如果您降低<output>
元素的不透明度,它是否也会影响:after
伪元素的不透明度?太棒了。我迫不及待地想原生地做这样的事情。您的示例正是我在我们公司的一款应用程序中所做的事情
http://www.carprices.com/research.rpro.html
单击“按价格范围搜索”以查看带有伪“输出”元素的滑块。
如您所见,我在使值气泡与范围滑块“拇指”的中心对齐方面遇到了类似的困难。有趣的是,HTML5 的范围滑块没有“拇指”或其位置的概念,让您自己计算其位置。希望在广泛支持它之前,这一点会有所改变。
该网站:http://wufoo.com/html5/types/8-range.html 似乎完全空白,至少在新的 Opera 11.10 中是这样。看起来是 z-index 问题。这有点讽刺,因为 Opera 是该网站上列出的唯一完全支持范围输入的浏览器:)。
哦,这很奇怪。但我无法重现它。在这里运行 11.10,它加载正常。
哦!你说得对,运行完美。不过我在 Windows 7 上检查过。我在 Windows XP 上发现了错误。嗯……我将再次检查,如果仍然有问题,我会通知您。
好的,错误仍然存在,但显然是在 Windows XP(SP 3)上。我还没有在 Vista 上检查过。
我只需要关闭这些声明
left: -3500px;
opacity: 0;
用于“#content, h1 section”选择器,内容变得可访问。
Chris,
很棒的文章!您可以用它实现一些非常酷的效果!我一定会自己尝试一下。
谢谢
为什么不支持范围输入的浏览器仍然可以获得气泡操作是一个奖励?
您会得到两次完全相同的值……只要没有人通过 JavaScript 将该回退输入字段替换为滑块,气泡就没有必要
太棒了。首先我喜欢你对气泡的样式设计。其次,这是一个相对简单的方法,可以显著提升滑块元素的可用性。
文章写得非常棒。向Chris致敬。
IE兼容性如何?
关于“注意”部分,因为jQuery的$().attr()函数在属性不存在时返回undefined,所以你可以尝试以下方法来简化和缩短代码。
var minVal, maxVal;
minVal = el.attr("min") || 0;
maxVal = el.attr("max") || 0;
我希望我可以原生实现这些功能,这样我就不用为了实现这些简单的滑块而使用5000行代码/库了:http://www.zirgo.com/
太棒了
我试图通过范围输入创建几个变体,但是,iOS webkit上的行为略有不同,它无法像其他webkit那样“点击并设置值”。
http://codepen.io/huang47/full/nDCJi
有什么见解吗?
解决方案很简单。用output的:before/:after替换范围滑块。
这是一个解决气泡在开始时过左、在结束时过右的恼人缺陷的方案。通过计算transform的值,气泡将始终保持在相同的位置,而不是四处移动。不再需要魔法数字。仅使用一个滑块,在Chrome v. 99.0.4844.82上测试。
‘function setBubble(range, bubble){
bubble.innerHTML = range.value;
bubble.style.left = range.value + ‘%’;
//为了使气泡与滑块拇指准确对齐,需要正确的transform
bubble.style.transform = ‘translateX(-‘ + (50 + parseInt(range.value)) + ‘%)’;
return;
}’
受此帖启发
https://jsfiddle.net/4fL0ur2w
谢谢