一场噩梦:了解范围输入

标签: css  html  java  人工智能  chrome

您可能已经看到了一堆 教程就如何风格的范围内输入。 尽管这是有关该主题的另一篇文章,但它与如何获得任何特定的视觉结果无关。 取而代之的是,它探究了浏览器的不一致之处,详细说明了每种行为在屏幕上显示该滑块的方式。 理解这一点很重要,因为它有助于我们清楚地知道我们是否可以使滑块在所有浏览器中保持一致的外观和行为,以及这样做的必要样式。

观察范围输入

任何事情之前,我们需要确保浏览器的公开范围里面输入DOM。

在Chrome中,我们打开DevTools,转到SettingsPreferencesElements ,并确保启用了Show user agent shadow DOM选项。

一系列的Chrome屏幕截图,说明了上述步骤。
Chrome屏幕截图的顺序说明了上述步骤。

在Firefox中,我们转到about:config并确保将devtools.inspector.showAllAnonymousContent标志设置为true

一系列Firefox屏幕截图,说明了上述步骤。
Firefox屏幕截图的序列说明了上述步骤。

很长时间以来,我坚信Edge无法提供查看此类元素内部内容的方法。 但是,在弄乱它的同时,我发现有志愿的地方(还有一些愚蠢的运气)就有办法! 我们需要调出DevTools,然后转到要检查的范围input ,右键单击它,选择Inspect Element和bam,现在DOM Explorer面板显示了滑块的结构!

一系列Edge屏幕截图,说明了上述步骤。
Edge屏幕截图序列说明了上述步骤。

显然,这是一个错误 但这也非常有用,所以我没有抱怨。

里面的结构

从一开始,我们就可以看到潜在问题的根源:每个浏览器中都有不同的野兽。

在Chrome中,在影子DOM的顶部,我们有一个div我们无法再访问它。 当支持/deep/时,这曾经是可能的,但是后来被认为可以穿透阴影屏障是一个错误,因此曾经有用的功能被删除了。 在此div内,轨道还有另一个,在div ,拇指有第三个div 最后两个都清楚地标有id属性,但令我感到奇怪的是,虽然我们可以使用::-webkit-slider-runnable-track访问该曲目,并使用::-webkit-slider-thumb ,只有track div具有带有该值的pseudo属性。

我们在范围输入中包含的结构的Chrome屏幕截图。
Chrome的内部结构。

在Firefox中,我们还看到了三个div元素,只是这一次它们没有嵌套-它们全部都是兄弟姐妹。 此外,它们只是普通的div元素,没有任何属性标记,因此,当初次查看它们时,我们无法得知是哪个组件。 幸运的是,在检查器中选择它们会突出显示页面上的相应组件,这就是我们可以分辨出第一个是轨道,第二个是进度并且第三个是拇指的方法。

Firefox的屏幕截图,我们在范围输入中拥有该结构。
Firefox的内部结构。

我们可以进入轨道(第一div带) ::-moz-range-track ,进度(第二div )与::-moz-range-progress和拇指(最后div )与::-moz-range-thumb

Edge中的结构要复杂得多,在一定程度上可以对滑块的样式进行更大程度的控制。 但是,我们只能访问带有-ms-前缀ID的元素,这意味着我们也无法访问很多元素,采用我们经常需要更改的烘焙样式,例如overflow: hidden在元素之间的元素实际input及其轨迹或拇指的父级上的transition

我们在范围输入中包含的结构的边缘屏幕截图。
Edge的内部结构。

具有不同的结构,并且无法访问内部所有元素以按我们希望的方式对所有样式进行样式设置,这意味着即使必须使用其他伪元素,在所有浏览器中实现相同的结果也可能非常困难,甚至甚至不可能。适用于每种浏览器,有助于设置个性化样式。

我们应该始终以尽量减少个人风格为目标,但是有时候这是不可能的,因为设置相同的风格会由于结构不同而产生非常不同的结果。 例如,在轨道上设置诸如opacityfilter甚至transform属性也会影响Chrome和Edge(这是轨道的子代/后代)中的拇指,但不会影响Firefox(它是其兄弟姐妹)中的拇指。

我发现设置通用样式的最有效方法是使用Sass mixin,因为以下操作不起作用:

input::-webkit-slider-runnable-track, 
input::-moz-range-track, 
input::-ms-track { /* common styles */ }

为了使其工作,我们需要这样编写:

input::-webkit-slider-runnable-track { /* common styles */ }
input::-moz-range-track { /* common styles */ }
input::-ms-track { /* common styles */ }

但这是很多重复和可维护性的噩梦。 这就是使mixin解决方案成为最明智的选择的原因:我们只需编写一次通用样式即可,因此,如果我们决定修改通用样式,则只需要在一个地方进行更改即可。

@mixin track() { /* common styles */ }

input {
  &::-webkit-slider-runnable-track { @include track }
  &::-moz-range-track { @include track }
  &::-ms-track { @include track }
}

请注意,我在这里使用Sass,但是您可以使用任何其他预处理器。 只要您喜欢它,就可以避免重复,并使代码更易于维护,这是好的。

初始样式

接下来,我们看一下滑块及其组件附带的一些默认样式,以便更好地了解需要显式设置哪些属性,以避免浏览器之间的视觉不一致。

只是提前警告:事情是混乱而复杂的。 不仅仅是我们在不同的浏览器中具有不同的默认值,而且更改一个元素上的属性可能会以意想不到的方式更改另一个属性(例如,设置background也会更改color并添加border )。

WebKit浏览器和Edge(因为是的,Edge还应用了很多WebKit前缀的东西)对于某些属性(例如,与尺寸,边框和背景有关的属性)也具有两个默认级别,如果我们可以称其为–设置-webkit-appearance: none (没有设置,我们设置的样式将无法在这些浏览器中使用),并且在设置之后。 但是,重点将是设置-webkit-appearance: none后的默认值-webkit-appearance: none因为在WebKit浏览器中,如果不设置此范围,我们将无法设置范围输入的样式,而我们经历所有这些的全部原因是为了了解我们如何设置滑块样式可以使我们的生活更轻松。

请注意,在范围input和拇指上-webkit-appearance: none设置-webkit-appearance: none设置(由于某种原因,轨道已默认设置),导致滑块在Chrome和Edge中完全消失。 为什么会发生这种情况,我们将在本文稍后讨论。

实际范围输入元素

我考虑过的第一个属性check box-sizing在所有浏览器中都具有相同的值-content content-box 我们可以通过在DevTools的“ 计算”选项卡中查找box-sizing属性来看到这一点。

三个浏览器中的DevTools的比较屏幕截图,显示了范围输入的框大小的计算值。
对所有三种浏览器(从上到下:Chrome,Firefox,Edge)的范围input box-sizing ,进行比较。

可悲的是,这并不表示即将发生的事情。 一旦查看了为元素提供框的属性,即marginborderpaddingwidthheight ,这一点就变得显而易见。

默认情况下,Chrome和Edge中的margin2px ,而Firefox中的margin0 .7em

在继续之前,让我们看看如何获​​得上面的值。 我们获得的计算长度值始终是px值。

但是,Chrome向我们展示了如何设置浏览器样式(用户代理样式表规则集位于灰色背景)。 有时我们没有明确设置计算值,所以没有用,但是在这种情况下,我们可以看到margin确实设置为px值。

Chrome DevTools的屏幕截图,显示了在哪里可以找到如何设置浏览器样式。
跟踪Chrome中的浏览器样式( margin大小写)。

Firefox在某些情况下还允许我们跟踪浏览器样式的来源,如以下屏幕截图所示:

跟踪Firefox中的浏览器样式,以及如何在我们的范围input margin范围内使它失败。

但是,在这种情况下这是行不通的,因此我们可以做的是查看DevTools中的计算值,然后检查在以下情况之一下这些计算值是否发生了变化:

  1. 当更改inputhtml上的font-size时,需要将其设置为emrem值。
  2. 更改视口时,表示使用%值或视口单位设置了该值。 不过,在很多情况下,可以安全地跳过这一点。
Gif录制,显示如何更改范围输入上的字体大小,如何在Firefox中更改边距值。
在Firefox中更改范围inputfont-size也会更改其margin值。

Edge也是如此,我们可以在其中跟踪用户样式的来源,但不能跟踪浏览器样式的来源,因此我们需要检查计算出的px值是否还取决于其他任何内容。

Gif记录显示如何更改范围输入上的字体大小不会更改Edge中的边距值。
更改Edge中input的范围的font-size不会更改其margin值。

无论如何,这都意味着margin是一个属性,如果我们想在浏览器中实现一致的外观,则需要在input[type='range']明确设置。

既然我们已经提到了font-size ,那么我们也要对其进行检查。 当然,这也是不一致的。

首先,我们在Chrome中有13.3333px ,尽管小数点可能表明这是我们将数字除以3的倍数的计算结果,但似乎是这样设置的,并且与视口尺寸或父级或根font-size

Chrome DevTools的屏幕截图,其中显示了设置了输入字体大小的用户代理规则。
Chrome中input的范围的font-size

Firefox向我们显示了相同的计算值,除了这似乎来自于将font速记设置为-moz-field ,我最初对此非常困惑,尤其是因为background-color设置为-moz-Field ,它应该是相同,因为CSS关键字不区分大小写。 但是,如果它们相同,那么对于这两个属性,如何才能使其成为有效值? 显然,此关键字是某种别名,用于使输入看起来像当前操作系统上的任何输入。

Firefox DevTools的屏幕截图,显示了如何设置输入的字体大小。
Firefox中input的范围的font-size

最后,Edge为我们提供了16px的计算值,这似乎是从其父级继承的,或者设置为1em ,如以下记录所示:

Edge DevTools的记录,显示输入的字体大小的计算值以及更改父级的字体大小时如何改变。
Edge中input的范围的font-size

这很重要,因为我们通常通常希望使用em单位设置滑块和控件(及其组件)的尺寸,以使它们相对于页面上文本的尺寸保持不变–当我们使用时,它们看起来不会太小当我们减小文字大小时,增加文字大小或太大。 而且,如果我们要以em单位设置尺寸,则此处的浏览器之间存在明显的font-size差异,这将导致我们在某些浏览器中范围input较小,而在其他浏览器中范围input较大。

因此,我始终确保在实际的滑块上显式设置font-size 或者,即使此时其他与字体相关的属性都无关紧要,我也可以设置font简写形式。 也许它们会在将来出现,但是稍后我们讨论刻度线和刻度线标签时会更多。

在继续介绍边框之前,我们首先来看一下color属性。 在Chrome中为rgb(196,196,196)设置),这使其比silverrgb(192,192,192) / #c0c0c0 rgb(192,192,192)稍轻,而在Edge和Firefox中,计算值为rgb(0,0,0) (这是纯black )。 我们无法知道在Edge中如何设置此值,但是在Firefox中,它是通过另一个类似的关键字-moz-fieldtext

三种浏览器中DevTools的比较屏幕截图,显示了范围输入的颜色计算值。
范围inputcolor ,对比所有三种浏览器(从上到下:Chrome,Firefox,Edge)。

border在Chrome中设置为initial ),相当于none medium currentcolorborder-styleborder-widthborder-color )。 一个有多厚medium边界是完全依赖于浏览器,但它至少厚如thin一个无处不在。 特别是在Chrome中,我们在此处获得的计算值为0

Chrome DevTools屏幕截图,显示了如何设置输入边框。
Chrome中范围inputborder

在Firefox中,我们也为border设置了一个none medium currentcolor值,尽管在这里medium似乎等于0.566667px ,该值不依赖于元素或根font-size或视口尺寸。

Firefox DevTools的屏幕截图,显示了如何设置输入边框。
Firefox中范围inputborder

我们看不到在Edge中如何设置所有内容,但是border-styleborder-width的计算值分别为none0 当我们更改color属性时, border-color也会改变,这意味着,就像在其他浏览器中一样,它被设置为currentcolor

Edge DevTools的记录,显示输入的边框属性的计算值以及更改元素的color属性时边框颜色的变化。
border范围的input的边缘。

在Chrome和Edge中, padding均为0

Chrome和Edge浏览器中的DevTools的比较屏幕截图,显示了范围输入的填充计算值。
范围inputpadding ,比较看Chrome(顶部)和Edge(底部)。

但是,如果我们要获得像素完美的结果,则需要显式设置它,因为在Firefox中将其设置为1px

Firefox DevTools的屏幕截图,显示了如何设置输入的填充。
在Firefox中input范围的padding

现在让我们绕道而行,然后检查背景,然后再尝试理解尺寸的值。 在这里,我们得到的计算值在Edge和Firefox中是transparent / rgba(0, 0, 0, 0) rgb(255,255,255) ,但是在Chrome中是rgb(255,255,255) (纯white )。

三种浏览器中DevTools的对比屏幕截图,显示了范围输入的背景色计算值。
范围inputbackground-color ,对比所有三种浏览器(从上到下:Chrome,Firefox,Edge)。

最后,让我们看一下尺寸。 我将其保存为最后,因为这是事情开始变得非常混乱的地方。

Chrome和Edge都为我们提供了129pxwidth计算值。 与以前的属性不同,我们无法在Chrome中的任何位置设置此属性,这通常会使我相信这取决于父对象,它像所有block元素一样水平延伸以适应所有情况(在这里绝对不是这种情况) )或儿童。 在“计算”面板中,还有一个-webkit-logical-width属性,其属性值为129px 起初我对此有些困惑,但是事实证明它是相对于写入模式的等效方式 –换句话说,它是水平写入模式的width和垂直写入模式的height

Gif录音显示了如何更改范围输入上的字体大小不会更改其在Chrome中的宽度值。
在Chrome中更改范围inputfont-size不会更改其width值。

无论如何,它都不取决于input本身或根元素的font-size ,也不取决于任何一个浏览器中的视口尺寸。

Gif记录显示如何更改范围输入上的字体大小不会更改Edge中的宽度值。
更改Edge中input的范围的font-size不会更改其width值。

Firefox在这里很奇怪,默认width返回一个160px的计算值。 但是,此计算值确实取决于范围inputfont-size -似乎是12em

Gif记录显示了如何更改范围输入上的字体大小,以及如何在Firefox中更改其宽度值。
在Firefox中更改范围inputfont-size也会更改其width值。

对于height ,Chrome和Edge再次一致,给我们提供了21px的计算值。 就像width ,我看不到在Chrome DevTools的用户代理样式表中的任何位置进行设置,通常在元素的height取决于其内容时会发生这种情况。

Gif记录显示如何更改范围输入上的字体大小不会更改其在Chrome中的高度值。
在Chrome中更改范围inputfont-size不会更改其height值。

此值也不取决于两个浏览器中的font-size

Gif记录显示如何更改范围输入上的字体大小不会更改Edge中的高度值。
更改Edge中input的范围的font-size不会更改其height值。

Firefox再次与众不同,为我们提供了17.3333px作为计算值,这又取决于inputfont-size 1.3em

Gif记录显示了如何更改范围输入上的字体大小,以及如何在Firefox中更改其高度值。
在Firefox中更改范围inputfont-size也会更改其height值。

但这并不比margin情况差,对吗? 好吧,到目前为止,还不是! 但这将要改变,因为我们现在要进入轨道组件。

范围跟踪组件

关于我们尚未考虑的实际input维度,还有另一种可能性:它们受到其组成部分的影响。 因此,让我们在轨道上明确设置一些尺寸,看看是否会影响滑块的尺寸。

显然,在这种情况下,对于width ,实际的滑块没有任何变化,但是当涉及到轨道width时,我们可以发现更多的不一致性,默认情况下,该width拉伸以填充父inputcontent-box 。所有三个浏览器。

在Firefox中,如果我们明确地设置一个width ,任意width的轨道上,然后轨道借此width ,我们给它,扩大境外母公司滑块或收缩内,但始终不离不弃,这中间对齐。 一点也不差,但是可悲的是,事实证明Firefox是唯一在这里表现理智的浏览器。

Gif记录显示了如何更改轨道组件的宽度不会影响Firefox中输入的范围的宽度,而仅影响轨道的宽度。此外,轨迹和实际范围输入始终在中间水平对齐。
在轨道上显式设置width更改Firefox中轨道的width ,但不会更改父滑块的width

在Chrome中,我们设置的磁道width被完全忽略了,看起来没有一种理智的方法使它的值不依赖于父滑块的值。

Gif录音显示了如何更改轨道组件的宽度在Chrome中什么都没做。
更改轨道的width不会在Chrome中执行任何操作(计算值仍为129px )。

至于疯狂的方式,使用transform: scaleX(factor)似乎是使轨道比其父滑块更宽或更窄的唯一方法。 请注意,这样做也会引起很多副作用。 拇指也被水平缩放,并且其运动仅限于Chrome和Edge中的缩小轨道(因为拇指是这些浏览器中轨道的子级),但在Firefox中则不保留,其大小得以保留,其运动为仍然仅限于输入,而不是缩小的轨迹(因为轨迹和拇指在这里是同级的)。 轨道上的任何横向paddingbordermargin也将被缩放。

移至“边缘”,轨道将再次采用我们设置的任何width

Gif记录显示Edge如何允许我们更改轨道的宽度而无需更改父滑块的宽度。
Edge还允许我们设置与父滑块不同的轨道width

但是,这与Firefox不同。 虽然将width设置为大于轨道上父滑块的width会使其向外扩展,但两者并未中间对齐。 而是将轨道的左边界限制与其范围input父级的左内容限制保持左对齐。 这种对齐方式不一致本身并不是什么大问题-仅在::-ms-track上设置的margin-left可以解决此问题。

但是,父滑块content-box之外的所有content-box都会在Edge content-box被剪切掉。 这不等同于在实际input上将overflow设置为hidden ,这会删去padding-box而非content-box 之外的所有 content-box 因此,无法通过设置“ overflow: visible在滑块上overflow: visible来解决。

这种裁剪是由input和轨道之间具有overflow: hidden的元素引起的overflow: hidden ,但是,由于我们无法访问它们,因此我们也无法解决此问题。 设置所有内容以使任何组件(包括其box-shadow )都不会超出范围的content-box是某些情况下的一种选择,但并非总是如此。

对于height ,Firefox的行为与width类似。 轨道会垂直扩展或缩小到我们设置的height ,而不会影响父滑块,并且始终保持垂直对齐。

Gif记录显示了如何更改轨道组件上的高度如何不影响Firefox中输入的范围高度,而仅影响轨道的高度。此外,轨迹和实际范围输入始终在中间垂直对齐。
在轨道上明确设置height更改Firefox中轨道的height ,但不会更改父滑块的height

在实际input或轨道上未设置任何样式的此height的默认值为.2em

Gif录音,显示如何在Firefox中更改轨道上的字体大小如何更改其计算的高度。
更改轨道上的font-size更改其在Firefox中的计算height

width ,Chrome允许轨道采用我们设置的height ,如果此处未使用%值,它也会使父滑块的content-box扩展或缩小,以使border-box轨道border-box完全适合它。 使用%值时,实际的滑块和轨道在垂直方向上居中对齐。

Gif记录,显示如果我们设置的值为%值,则更改轨道组件上的高度如何不会影响Chrome中输入的范围的高度。否则,轨道会扩展或收缩,以使轨道完全适合。此外,在%的情况下,轨道和实际范围输入始终会垂直居中对齐。
明确设置一个height的轨道上%变化的height在Chrome的轨道,但不是父滑块的那个。 使用其他单位,实际范围input会垂直扩展或缩小,以使轨道完全适合内部。

在没有设置任何自定义样式的情况下,我们获得的height的计算值与滑块相同,并且不会随着font-size改变。

Gif记录显示如何更改轨道上的字体大小不会更改其在Chrome中的计算高度。
更改轨道上的font-size不会更改其在Chrome中的计算height

边缘呢? 好了,我们可以独立于父滑块的height更改轨道的height ,并且它们都保持中间垂直对齐,但这仅是只要我们设置的轨道height小于实际input的初始height input 在此之上,轨道的计算height始终等于父范围的height

Gif记录显示了如何更改轨道组件上的高度不会影响Edge中输入的范围的高度。轨迹和实际范围输入始终在中间垂直对齐。但是,轨道的高度受父滑块的高度限制。
在Edge中的轨道上明确设置height不会更改父滑块的height ,并且两者是中间对齐的。 但是,轨道的height受实际inputheight限制。

初始轨道高度为11px ,此值与font-size或视口无关。

Gif记录显示如何更改轨道上的字体大小不会更改其在Edge中的计算高度。
更改轨道上的font-size不会更改其在Edge中的计算height

转移到一些不太费事的事情上,我们有了box-sizing 这是Chrome中的border-box ,Edge和Firefox中的content-box ,因此,如果我们要使用非零的borderpadding ,则box-sizing是我们需要显式设置的属性,以使情况平整。

三种浏览器中DevTools的比较屏幕截图,显示了该轨道的盒装大小的计算值。
box-sizing的轨道,比较一下这三种浏览器(从上到下:Chrome浏览器,火狐,边缘)。

在所有三种浏览器中,默认的轨迹marginpadding都为0最后,这是一致性的绿洲!

三种浏览器中的DevTools的比较屏幕截图,显示了轨道裕量的计算值。
box-sizing的轨道,比较一下这三种浏览器(从上到下:Chrome浏览器,火狐,边缘)。

color属性的值可以从所有三个浏览器的父滑块继承。

Chrome和Firefox浏览器中的DevTools的比较屏幕截图,显示了轨道颜色的计算值。
赛道的color ,Chrome(顶部)和Firefox(底部)的对比。

即使如此,Edge在这里还是很奇怪,将其更改为white ,尽管将其设置为initial会将其更改为black ,这是我们实际input的值。

在Edge中将颜色重置为初始颜色。
在Edge中将color重置为initial color

设置-webkit-appearance: none Edge中实际input上的-webkit-appearance: none会使轨道上color的计算值transparent (如果我们自己尚未显式设置color值)。 另外,一旦我们在轨道上添加了background ,计算出的轨道color突然变为black

在Edge中的轨道上添加背景会将其计算的颜色从白色更改为黑色。
在Edge中添加background轨道的意外结果。

在某种程度上,继承color属性的功能对于主题化很有用,尽管继承自定义属性在这里可以做更多的事情。 For example, consider we want to use a silver for secondary things and an orange for what we want highlighted. We can define two CSS variables on the body and then use them across the page, even inside our range inputs.

body {
  --fading: #bbb;
  --impact: #f90
}

h2 { border-bottom: solid .125em var(--impact) }

h6 { color: var(--fading) }

[type='range']:focus { box-shadow: 0 0 2px var(--impact) }

@mixin track() { background: var(--fading) }

@mixin thumb() { background: var(--impact) }

Sadly, while this works in Chrome and Firefox, Edge doesn't currently allow custom properties on the range input to be inherited down to its components.

Screenshots of the expected result (and what we get in Chrome and Firefox) vs. the result we get in Edge (neither the thumb or the track show up)
Expected result (left) vs. result in Edge (right), where no track or thumb show up ( live demo ).

By default, there is no border on the track in Chrome or Firefox ( border-width is 0 and border-style is none ).

Comparative screenshots of DevTools in Chrome and Firefox browsers showing the computed values of border for the track.
The border of the track, comparative look at Chrome (top) and Firefox (bottom).

Edge has no border on the track if we have no background set on the actual input and no background set on the track itself. However, once that changes, we get a thin ( 1px ) black track border .

Adding a background on the track or actual input in Edge gives the track a solid 1px black border.
Another unexpected consequence of adding a track or parent slider background in Edge.

The default background-color is shown to be inherited as white, but then somehow we get a computed value of rgba(0,0,0,0) ( transparent ) in Chrome (both before and after -webkit-appearance: none ). This also makes me wonder how come we can see the track before, since there's no background-color or background-image to give us anything visible. Firefox gives us a computed value of rgb(153,153,153) ( #999 ) and Edge transparent (even though we might initially think it's some kind of silver, that is not the background of the ::-ms-track element – more on that a bit later).

Comparative screenshots of DevTools in the three browsers showing the computed values of background-color for the track.
The background-color of the track, comparative look at all three browsers (from top to bottom: Chrome, Firefox, Edge).

The range thumb component

Ready for the most annoying inconsistency yet? The thumb moves within the limits of the track's content-box in Chrome and within the limits of the actual input 's content-box in Firefox and Edge, even when we make the track longer or shorter than the input (Chrome doesn't allow this, forcing the track's border-box to fit the slider's content-box horizontally).

The way Chrome behaves is illustrated below:

Chrome only moves the thumb within the left and right limits of the track's content-box.
Recording of the thumb motion in Chrome from one end of the slider to the other.

The padding is transparent, while the content-box and the border are semitransparent. We've used orange for the actual slider, red for the track and purple for the thumb.

For Firefox, things are a bit different:

Firefox moves the thumb within the left and right limits of the actual range input's content-box.
Recording of the thumb motion in Firefox from one end of the slider to the other (the three cases from top to bottom: the border-box of the track perfectly fits the content-box of the slider horizontally, it's longer and it's shorter).

In Chrome, the thumb is the child of the track, while in Firefox it's its sibling, so, looking at it this way, it makes sense that Chrome would move the thumb within the limits of the track's content-box and Firefox would move it within the limits of the slider's content-box . However, the thumb is inside the track in Edge too and it still moves within the limits of the slider's content-box .

动画的gif。 Shows how Edge moves the thumb within the left and right limits of the actual range input's content-box.
Recording of the thumb motion in Edge from one end of the slider to the other (the three cases from top to bottom: the border-box of the track perfectly fits the content-box of the slider horizontally, it's longer and it's shorter).

While this looks very strange at first, it's because Edge forces the position of the track to static and we cannot change that, even if we set it to relative with !important .

动画的gif。 Recording of the following steps: 1) checking the computed value of the position property on the track in Edge DevTools - it's static 2) setting ::-ms-track { position: relative } 3) checking the computed value again - it's still static 4) adding !important to the rule previously set on the track 5) checking the computed value a third time - annoyingly, it's still static!
Trying (and failing) to change the value of the position property on the track in Edge.

This means we may style our slider exactly the same for all browsers, but if its content-box doesn't coincide to that of its track horizontally (so if we have a non-zero lateral padding or border on the track), it won't move within the same limits in all browsers.

Furthermore, if we scale the track horizontally, then Chrome and Firefox behave as they did before, the thumb moving within the limits of the now scaled track's content-box in Chrome and within the limits of the actual input 's content-box in Firefox. However, Edge makes the thumb move within an interval whose width equals that of the track's border-box , but starts from the left limit of the track's padding-box , which is probably explained by the fact that the transform property creates a stacking context .

Edge moves the thumb within an interval equal to the scaled track's border-box, starting from the left limit of the padding-box
Recording of the thumb motion in Edge when the track is scaled horizontally.

Vertically, the thumb is middle-aligned to the track in Firefox, seemingly middle-aligned in Edge, though I've been getting very confusing different results over multiple tests of the same situation, and the top of its border-box is aligned to the top of the track's content-box in Chrome once we've set -webkit-appearance: none on the actual input and on the thumb so that we can style the slider.

While the Chrome decision seems weird at first, is annoying in most cases and lately has even contributed to breaking things in… Edge (but more about that in a moment), there is some logic behind it. By default, the height of the track in Chrome is determined by that of the thumb and if we look at things this way, the top alignment doesn't seem like complete insanity anymore.

However, we often want a thumb that's bigger than the track's height and is middle aligned to the track. We can correct the Chrome alignment with margin-top in the styles we set on the ::-webkit-slider-thumb pseudo.

Unfortunately, this way we're breaking the vertical alignment in Edge. This is because Edge now applies the styles set via ::-webkit-slider-thumb as well. At least we have the option of resetting margin-top to 0 in the styles we set on ::-ms-thumb . The demo below shows a very simple example of this in action.

由thebabydino( @thebabydino )上CodePen

Just like in the case of the track, the value of the box-sizing property is border-box in Chrome and content-box in Edge and Firefox, so, for consistent results across browsers, we need to set it explicitly if we want to have a non-zero border or padding on the thumb.

The margin and padding are both 0 by default in all three browsers.

After setting -webkit-appearance: none on both the slider and the thumb (setting it on just one of the two doesn't change anything), the dimensions of the thumb are reset from 10x21 (dimensions that don't depend on the font-size ) to 129x0 in Chrome. The height of the track and actual slider also get reset to 0 , since they depend on that of their content (the thumb inside, whose height has become 0 ).

动画的gif。 Shows Chrome DevTools with the thumb selected. Changing the font-size on the thumb doesn't change its dimensions. Setting -webkit-appearance: none on both the thumb and the actual slider resets its dimensions to 129x0
The thumb box model in Chrome.

This is also why explicitly setting a height on the thumb makes the track take the same height .

According to Chrome DevTools, there is no border in either case, even though, before setting -webkit-appearance: none , it sure looks like there is one.

屏幕截图。 Before setting -webkit-appearance:none, it looks like there is a border on the thumb, even though Chrome DevTools says there isn't.
How the slider looks in Chrome before setting -webkit-appearance: none .

If that's not a border , it might be an outline or a box-shadow with no blur and a positive spread. But, according to Chrome DevTools, we don't have an outline , nor box-shadow on the thumb.

屏幕截图。 The computed value for outline in Chrome DevTools is none 0px rgb(196, 196, 196), while that for box-shadow is none.
Computed values for outline and box-shadow in Chrome DevTools.

Setting -webkit-appearance: none in Edge makes the thumb dimensions go from 11x11 (values that don't depend on the font-size ) to 0x0 . Explicitly setting a height on the thumb makes the track take the initial height ( 11px ).

动画的gif。 Shows Edge DevTools with the thumb selected. Changing the font-size on the thumb doesn't change its dimensions. Setting -webkit-appearance: none on both the thumb and the actual slider resets its dimensions to 0x0
The thumb box model in Edge.

In Edge, there's initially no border on the thumb. However, after setting a background on either the actual range input or any of its components, we suddenly get a solid 1px white lateral one (left and right, but not top and bottom), which visually turns to black in the :active state (even though Edge DevTools doesn't seem to notice that). Setting -webkit-appearance: none removes the border-width .

动画的gif。 Shows Edge DevTools with the thumb selected. There is originally no border, but setting a background on either the slider or its components makes the lateral borders solid 1px white ones. Setting -webkit-appearance: none on both the thumb and the actual slider removes this border (as well as making both thumb dimensions 0).
The thumb border in Edge.

In Firefox, without setting a property like background on the range input or its components, the dimensions of the thumb are 1.666x3.333 and, in this case, they don't change with the font-size . However, if we set something like background: transparent on the slider (or any background value on its components), then both the width and height of the thumb become 1em .

动画的gif。 Shows Firefox DevTools with the thumb selected. Changing the font-size on the thumb doesn't change initially its dimensions. However, after setting a background on the actual input, the thumb dimensions become equal to the font-size (1em).
The thumb box model in Firefox.

In Firefox, if we are to believe what we see in DevTools, we initially have a solid thick grey ( rgb(153, 153, 153) ) border .

屏幕截图。 Shows Firefox DevTools displaying the computed values for the slider thumb border.
The thumb border in Firefox DevTools.

Visually however, I can't spot this thick grey border anywhere.

Screenshot of the slider in its initial state in Firefox, before setting a background on it or on any of its components. I cannot see any border on the thumb, even Firefox DevTools says there is a pretty thick one.
How the slider looks initially in Firefox, before setting a background on it or on any of its components.

After setting a background on the actual range input or one of its components, the thumb border actually becomes visually detectable and it seems to be .1em .

动画的gif。 Shows Firefox DevTools with the thumb selected. In DevTools we originally see a thickish grey border, with a different width on every side, but setting a background on either the slider or its components makes this border thinner an uniform around the thumb. Its width varies with the font-size and it seems to be .1em.
The thumb border in Firefox.

In Chrome and in Edge, the border-radius is always 0 .

屏幕截图。 Top: screenshot of Chrome DevTools showing the computed value for the thumb's border-radius is 0. Bottom: screenshot of Edge DevTools showing the computed value for the thumb's border-radius is 0.
The thumb border-radius in Chrome (top) and Edge (bottom).

In Firefox however, we have a .5em value for this property, both before and after setting a background on the range input or on its components, even though the initial shape of the thumb doesn't look like a rectangle with rounded corners.

动画的gif。 Shows Firefox DevTools with the thumb selected. In DevTools, we change the font-size on the thumb and, from the way the computed border-radius value changes, we get that it's set to .5em.
The thumb border-radius in Firefox.

The strange initial shape of the thumb in Firefox has made me wonder whether it doesn't have a clip-path set, but that's not the case according to DevTools.

屏幕截图。 Shows Firefox DevTools with the thumb selected. The computed value for the clip-path property on the thumb is none.
The thumb clip-path in Firefox.

More likely, the thumb shape is due to the -moz-field setting, though, at least on Windows 10, this doesn't make it look like every other slider.

屏幕截图。 The initial appearance of the slider in Firefox vs. the appearance of a native Windows slider.
Initial appearance of slider in Firefox vs. appearance of a native Windows 10 slider.

The thumb's background-color is reported as being rgba(0, 0, 0, 0) ( transparent ) by Chrome DevTools, even though it looks grey before setting -webkit-appearance: none . We also don't seem to have a background-image that could explain the gradient or the lines on the thumb before setting -webkit-appearance: none . Firefox DevTools reports it as being rgb(240, 240, 240) , even though it looks blue as long as we don't have a background explicitly set on the actual range input or on any of its components.

屏幕截图。 Top: screenshot of Chrome DevTools showing the computed value for background-color on the thumb is rgba(0, 0, 0, 0) and the computed value for background-image is none. Bottom: screenshot of Firefox DevTools showing the computed value for background-color on the thumb is rgb(240, 240, 240).
The thumb background-color in Chrome (top) and Firefox (bottom).

In Edge, the background-color is rgb(33, 33, 33) before setting -webkit-appearance: none and transparent after.

动画的gif。 Shows Edge DevTools with the thumb selected. The computed value for the thumb's background-color is rgb(33, 33, 33). In DevTools, we set -webkit-appearance: none on the actual slider and on the thumb. The computed value for the thumb's background-color becomes transparent.
The thumb background-color in Edge.

The range progress (fill) component

We only have dedicated pseudo-elements for this in Firefox ( ::-moz-range-progress ) and in Edge ( ::-ms-fill-lower ). Note that this element is a sibling of the track in Firefox and a descendant in Edge. This means that it's sized relative to the actual input in Firefox, but relative to the track in Edge.

In order to better understand this, consider that the track's border-box perfectly fits horizontally within the slider's content-box and that the track has both a border and a padding .

In Firefox, the left limit of the border-box of the progress component always coincides with the left limit of the slider's content-box . When the current slider value is its minimum value, the right limit of the border-box of our progress also coincides with the left limit of the slider's content-box . When the current slider value is its maximum value, the right limit of the border-box of our progress coincides with the right limit of the slider's content-box .

This means the width of the border-box of our progress goes from 0 to the width of the slider's content-box . In general, when the thumb is at x% of the distance between the two limit value, the width of the border-box for our progress is x% of that of the slider's content-box .

This is shown in the recording below. The padding area is always transparent, while the border area and content-box are semitransparent (orange for the actual input , red for the track, grey for the progress and purple for the thumb).

动画的gif。 Shows the slider in Firefox with the thumb at the minimum value. The width of the border-box of the progress component is 0 in this case. We drag the thumb to the maximum slider value. The width of the border-box of the progress component equals that of the slider's content-box in this case.
How the width of the ::-moz-range-progress component changes in Firefox.

In Edge however, the left limit of the fill's border-box always coincides with the left limit of the track's content-box while the right limit of the fill's border-box always coincides with the vertical line that splits the thumb's border-box into two equal halves. This means that when the current slider value is its minimum value, the right limit of the fill's border-box is half the thumb's border-box to the right of the left limit of the track's content-box . And when the current slider value is its maximum value, the right limit of the fill's border-box is half the thumb's border-box to the left of the right limit of the track's content-box .

This means the width of the border-box of our progress goes from half the width of the thumb's border-box minus the track's left border and padding to the width of the track's content-box plus the track's right padding and border minus half the width of the thumb's border-box . In general, when the thumb is at x% of the distance between the two limit value, the width of the border-box for our progress is its minimum width plus x% of the difference between its maximum and its minimum width .

This is all illustrated by the following recording of this live demo you can play with:

动画的gif。 Shows the slider in Edge with the thumb at the minimum value. The width of the border-box of the progress component is half the width of the thumb's border-box minus the track's left border and padding in this case. We drag the thumb to the maximum slider value. The width of the border-box of the progress component equals that of the track's content-box plus the track's right padding and border minus half the width of the thumb's border-box.
How the width of the ::-ms-fill-lower component changes in Edge.

While the description of the Edge approach above might make it seem more complicated, I've come to the conclusion that this is the best way to vary the width of this component as the Firefox approach may cause some issues.

For example, consider the case when we have no border or padding on the track for cross browser consistency and the height of the both the fill's and thumb's border-box equal to that of the track. Furthermore, the thumb is a disc ( border-radius: 50% ).

In Edge, all is fine:

Animated gif illustrating how the case described above works in Edge using a slider with a grey track and orange progress.
How our example works in Edge.

But in Firefox, things look awkward ( live demo ):

Animated gif illustrating how the case described above works in Firefox using a slider with a grey track and orange progress.
How our example works in Firefox.

The good news is that we don't have other annoying and hard to get around inconsistencies in the case of this component.

box-sizing has the same computed value in both browsers – content-box .

屏幕截图。 Top half shows Firefox DevTools with the progress component selected. The computed value for box-sizing is shown to be content-box. Bottom half shows Edge DevTools with the lower fill component selected. The computed value for box-sizing is shown to be content-box in this case too.
The computed value for box-sizing in the case of the progress (fill) component: Firefox (top) and Edge (bottom).

In Firefox, the height of the progress is .2em , while the padding , border and margin are all 0 .

动画的gif。 Shows Firefox DevTools with the progress component selected. Changing the font-size on this component also changes its height, allowing us to see it was set as .2em.
The height of the progress in Firefox.

In Edge, the fill's height is equal to that of the track's content-box , with the padding , border and margin all being 0 , just like in Firefox.

动画的gif。 Shows Edge DevTools with the fill component selected. The height of the fill is the same as that of the track's content-box. We set box-sizing: border-box on the track and give it a vertical padding to check this. The height of the fill shrinks accordingly.
The height of the fill in Edge.

Initially, the background of this element is rgba(0, 0, 0, 0) ( transparent , which is why we don't see it at first) in Firefox and rgb(0, 120, 115) in Edge.

屏幕截图。 Top half shows Firefox DevTools with the progress selected. The computed value for the background-color of the progress is rgba(0, 0, 0, 0). Bottom half shows Edge DevTools with the lower fill selected. The computed value for the fill's background-color is rgb(0, 120, 115).
The background-color of the progress (fill) in Firefox (top) and Edge (bottom).

In both cases, the computed value of the color property is rgb(0, 0, 0) (solid black ).

屏幕截图。 Top half shows Firefox DevTools with the progress component selected. The computed value for color is shown to be rgb(0, 0, 0). Bottom half shows Edge DevTools with the lower fill component selected. The computed value for color is shown to be rgb(0, 0, 0) in this case too.
The computed value for color in the case of the progress (fill) component: Firefox (top) and Edge (bottom).

WebKit browsers don't provide such a component and, since we don't have a way of accessing and using a track's ::before or ::after pseudos anymore, our only option of emulating this remains layering an extra, non-repeating background on top of the track's existing one for these browsers and making the size of this extra layer along the x axis depend depend on the current value of the range input .

The simplest way of doing this nowadays is by using a current value --val CSS variable, which holds the slider's current value. We update this variable every time the slider's value changes and we make the background-size of this top layer a calc() value depending on --val . This way, we don't have to recompute anything when the value of the range input changes – our calc() value is dynamic, so updating the --val variable is enough (not just for this background-size , but also for other styles that may depend on it as well).

由thebabydino( @thebabydino )上CodePen

Also doing this for Firefox is an option if the way ::-moz-range-progress increases doesn't look good for our particular use case.

Edge also provides a ::-ms-fill-upper which is basically the complementary of the lower one and it's the silver background of this pseudo-element that we initially see to the right of the thumb, not that of the track (the track is transparent ).

Tick marks and labels

Edge is the only browser that shows tick marks by default. They're shown on the track, delimiting two, five, ten, twenty sections, the exact number depending initially on the track width . The only style we can change for these tick marks is the color property as this is inherited from the track (so setting color: transparent on the track removes the initial tick marks in Edge).

屏幕截图。 Shows Edge DevTools with the SVG group containing the tick lines selected. Unfortunately, I cannot access this group, its children, its SVG parent or the SVG container to modify their styles. I can only access the track (which is the SVG container's parent) via ::-ms-track. Since the color property is inherited and the tick lines use currentColor as the stroke value, changing the color on the track also changes the stroke of the tick lines.
The structure that generates the initial tick marks on the track in Edge.

The spec says that tick marks and labels can be added by linking a datalist element, for whose option children we may specify a label attribute if we want that particular tick mark to also have a label.

Unfortunately, though not at all surprising anymore at this point, browsers have a mind of their own here too. Firefox doesn't show anything – no tick marks, no labels. Chrome shows the tick marks, but only allows us to control their position along the slider with the option values. It doesn't allow us to style them in any way and it doesn't show any labels.

屏幕截图。 Shows the range input with the tick marks generated in Chrome when adding a datalist.
Tick marks in Chrome.

Also, setting -webkit-appearance: none on the actual slider (which is something that we need to to in order to be able to style it) makes these tick marks disappear.

Edge joins the club and doesn't show any labels either and it doesn't allow much control over the look of the ticks either. While adding the datalist allows us to control which tick marks are shown where on the track, we cannot style them beyond changing the color property on the track component.

屏幕截图。 Shows the range input with the tick marks generated in Edge when adding a datalist.
Tick marks in Edge.

In Edge, we also have ::-ms-ticks-before and ::-ms-ticks-after pseudo-elements. These are pretty much what they sound like – tick marks before and after the track. However, I'm having a hard time understanding how they really work.

They're hidden by display: none , so changing this property to block makes them visible if we also explicitly set a slider height , even though doing this does not change their own height .

动画的gif。 Illustrates the steps above to make the tick marks created by ::-ms-ticks-after visible.
How to make tick marks crested by ::-ms-ticks-after visible in Edge.

Beyond that, we can set properties like margin , padding , height , background , color in order to control their look. However, I have no idea how to control the thickness of individual ticks, how to give individual ticks gradient backgrounds or how to make some of them major and some minor.

So, at the end of the day, our best option if we want a nice cross-browser result remains using repeating-linear-gradient for the ticks and the label element for the values corresponding to these ticks.

由thebabydino( @thebabydino )上CodePen

Tooltip/ current value display

Edge is the only browser that provides a tooltip via ::-ms-tooltip , but this doesn't show up in the DOM, cannot really be styled (we can only choose to hide it by setting display: none on it) and can only display integer values, so it's completely useless for a range input between let's say .1 and .4 – all the values it displays are 0 !

动画的gif。 Dragging the thumb in Edge results in the tooltip displaying always 0 if both the minimum and the maximum are subunitary.
::-ms-tooltip when range limits are both subunitary.

So our best bet is to just hide this and use the output element for all browsers, again taking advantage of the possibility of storing the current slider value into a --val variable and then using a calc() value depending on this variable for the position.

由thebabydino( @thebabydino )上CodePen

方向

The good news is that every browser allows us to create vertical sliders. The bad news is, as you may have guessed… every browser provides a different way of doing this, none of which is the one presented in the spec (setting a width smaller than the height on the range input ). WebKit browsers have opted for -webkit-appearance: slider-vertical , Edge for writing-mode: bt-lr , while Firefox controls this via an orient attribute with a value of 'vertical' .

The really bad news is that, for WebKit browsers, making a slider vertical this way leaves us unable to set any custom styles on it (as setting custom styles requires a value of none for -webkit-appearance ).

Our best option is to just style our range input as a horizontal one and then rotate it with a CSS transform .

由thebabydino( @thebabydino )上CodePen

翻译自: https://css-tricks.com/sliding-nightmare-understanding-range-input/

版权声明:本文为cunqu9743原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/cunqu9743/article/details/106998226