构建星级评分组件是Web开发中的经典练习,已使用多种技术反复实现。通常需要少量JavaScript代码,但仅使用CSS实现呢?是的,可以!
这是一个仅使用CSS实现的星级评分组件演示。您可以点击更新评分。
很酷,对吧?除了仅使用CSS外,HTML代码只是一个单一元素:
<input type="range">
范围输入元素是理想的选择,因为它允许用户在两个边界(最小值和最大值)之间选择数值。我们的目标是设计这个原生元素,将其转换为星级评分组件,无需额外的标记或任何脚本!我们还将在最后创建更多组件,敬请关注。
注意: 本文仅关注CSS部分。虽然我尽力考虑了UI、UX和可访问性方面,但我的组件并不完美。它可能有一些缺点(错误、可访问性问题等),因此请谨慎使用。
<input type="range">
元素您可能知道,由于所有默认的浏览器样式以及不同的内部结构,设计原生元素(如输入元素)有点棘手。例如,如果您检查范围输入元素的代码,您会在Chrome(或Safari、Edge)和Firefox之间看到不同的HTML。
幸运的是,我们有一些共同的部分,我将依赖这些部分。我将定位两个不同的元素:主元素(输入本身)和滑块元素(您使用鼠标滑动以更新值的那个元素)。
我们的CSS主要如下所示:
input[type="range"] { /* 主元素样式 */ } input[type="range"][i]::-webkit-slider-thumb { /* Chrome、Safari和Edge的滑块样式 */ } input[type="range"]::-moz-range-thumb { /* Firefox的滑块样式 */ }
唯一的缺点是我们需要重复滑块元素的样式两次。不要尝试执行以下操作:
input[type="range"][i]::-webkit-slider-thumb, input[type="range"]::-moz-range-thumb { /* 滑块样式 */ }
这不起作用,因为整个选择器无效。Chrome等不理解::-moz-*
部分,而Firefox不理解::-webkit-*
部分。为简单起见,在本文中,我将使用以下选择器:
input[type="range"]::thumb { /* 滑块样式 */ }
但是演示包含带有重复样式的真实选择器。介绍足够了,让我们开始编码吧!
我们首先定义大小:
input[type="range"] { --s: 100px; /* 控制大小 */ height: var(--s); aspect-ratio: 5; appearance: none; /* 删除默认浏览器样式 */ }
如果我们认为每颗星都位于一个正方形区域内,那么对于5星级评分,我们需要宽度等于高度的五倍,因此使用aspect-ratio: 5
。
该5值也定义为输入元素的max
属性的值。
<input type="range" max="5">
因此,我们可以依靠新增强的attr()
函数(目前仅限Chrome)来读取该值,而不是手动定义它!
input[type="range"] { --s: 100px; /* 控制大小 */ height: var(--s); aspect-ratio: attr(max type(<number>)); appearance: none; /* 删除默认浏览器样式 */ }</number>
现在您可以通过简单地调整max
属性来控制星星的数量。这很棒,因为max
属性也被浏览器内部使用,因此更新该值将控制我们的实现以及浏览器的行为。
这个增强的attr()
版本目前仅在Chrome中可用,因此我所有的演示都包含一个后备方案来帮助不支持的浏览器。
下一步是使用CSS遮罩来创建星星。我们需要形状重复五次(或更多次,取决于max
值),因此遮罩大小应等于var(--s) var(--s)
或var(--s) 100%
或简化为var(--s)
,因为默认情况下高度将等于100%。
<input type="range">
您可能会问mask-image
属性是什么?我想我告诉您它需要一些渐变并不奇怪,但它也可以是SVG。本文是关于创建星级评分组件的,但我希望星形部分保持通用性,以便您可以轻松地将其替换为任何您想要的形状。这就是为什么我在这篇文章的标题中说“还有更多”。我们稍后将看到如何使用相同的代码结构获得各种不同的变体。
这里有一个演示,展示了星形的两种不同的实现方式。一种是使用渐变,另一种是使用SVG。
在这种情况下,SVG实现看起来更简洁,代码也更短,但请记住这两种方法,因为渐变实现有时可以做得更好。
现在让我们关注滑块元素。使用最后一个演示,然后单击星星,并注意滑块的位置。
好消息是,对于所有值(从最小值到最大值),滑块始终位于给定星形的区域内,但每个星形的位置不同。如果位置始终相同,而不管值如何,那就更好了。理想情况下,为了保持一致性,滑块应始终位于星形的中心。
这是一张图,用于说明位置以及如何更新它。
这些线是每个值的滑块位置。在左侧,我们有默认位置,其中滑块从主元素的左边缘移动到右边缘。在右侧,如果我们通过在两侧添加一些空间来限制滑块的位置到较小的区域,我们将获得更好的对齐方式。该空间等于一颗星大小的一半,或var(--s)/2
。我们可以为此使用填充:
input[type="range"] { /* 主元素样式 */ } input[type="range"][i]::-webkit-slider-thumb { /* Chrome、Safari和Edge的滑块样式 */ } input[type="range"]::-moz-range-thumb { /* Firefox的滑块样式 */ }
它更好,但并不完美,因为我没有考虑滑块大小,这意味着我们没有真正的居中。这不是问题,因为我将使用等于1px的宽度使滑块的大小非常小。
input[type="range"][i]::-webkit-slider-thumb, input[type="range"]::-moz-range-thumb { /* 滑块样式 */ }
滑块现在是一条细线,位于星形的中心。我使用红色来突出显示位置,但在现实中,我不需要任何颜色,因为它将是透明的。
您可能认为我们距离最终结果还很远,但我们快完成了!缺少一个属性来完成这个难题:border-image
。
border-image
属性允许我们使用其outset
功能在元素外部绘制装饰。为此,我使滑块变小且透明。着色将使用border-image
完成。我将使用具有两种纯色的渐变作为源:
input[type="range"]::thumb { /* 滑块样式 */ }
我们编写如下内容:
<input type="range">
上述内容意味着我们将border-image
的区域从元素的每一侧扩展100px,并且渐变将填充该区域。换句话说,渐变的每种颜色将覆盖该区域的一半,即100px。
你明白逻辑了吗?我们在滑块的每一侧创建了一种溢出的着色——一种将逻辑地跟随滑块的着色,因此每次单击一颗星时,它都会滑入到位!
现在,让我们使用一个非常大的值而不是100px:
我们快完成了!着色填充了所有星星,但我们不希望它位于中间,而是位于整个选定星形上。为此,我们稍微更新一下渐变,而不是使用50%,我们使用50% var(--s)/2
。我们添加一个等于星形宽度一半的偏移量,这意味着第一种颜色将占据更多空间,我们的星级评分组件就完美了!
我们仍然可以稍微优化代码,而不是为滑块定义高度,我们将它保持为0,并且考虑border-image
的垂直outset
来扩展着色。
input[type="range"] { /* 主元素样式 */ } input[type="range"][i]::-webkit-slider-thumb { /* Chrome、Safari和Edge的滑块样式 */ } input[type="range"]::-moz-range-thumb { /* Firefox的滑块样式 */ }
我们也可以使用圆锥渐变来不同地编写渐变:
input[type="range"][i]::-webkit-slider-thumb, input[type="range"]::-moz-range-thumb { /* 滑块样式 */ }
我知道border-image
的语法不容易理解,我对解释有点快。但我有一篇非常详细的文章发表在Smashing Magazine上,我在其中用很多例子剖析了这个属性,我邀请您阅读,以便更深入地了解该属性的工作原理。
我们组件的完整代码如下:
input[type="range"]::thumb { /* 滑块样式 */ }
input[type="range"] { --s: 100px; /* 控制大小 */ height: var(--s); aspect-ratio: 5; appearance: none; /* 删除默认浏览器样式 */ }
就是这样!几行CSS代码,我们就得到了一个漂亮的星级评分组件!
如何将评分粒度设置为半星?这很常见,我们可以通过进行一些调整来完成之前的代码。
首先,我们将输入元素更新为以半步而不是全步递增:
<input type="range" max="5">
默认情况下,步长等于1,但我们可以将其更新为.5(或任何值),然后也将最小值更新为.5。在CSS方面,我们将填充从var(--s)/2
更改为var(--s)/4
,并且对渐变中的偏移量也执行相同的操作。
input[type="range"] { --s: 100px; /* 控制大小 */ height: var(--s); aspect-ratio: attr(max type(<number>)); appearance: none; /* 删除默认浏览器样式 */ }</number>
两种实现方式之间的差异是一个二分之一的因子,这也是步长值。这意味着我们可以使用attr()
并创建适用于这两种情况的通用代码。
input[type="range"] { --s: 100px; /* 控制大小 */ height: var(--s); aspect-ratio: attr(max type(<number>)); appearance: none; /* 删除默认浏览器样式 */ mask-image: /* ... */; mask-size: var(--s); }</number>
这是一个演示,其中修改步长是您需要做的所有事情来控制粒度。不要忘记,您还可以使用max
属性来控制星星的数量。
如您所知,我们可以使用键盘调整范围滑块输入的值,因此我们也可以使用键盘来控制评分。这是一件好事,但有一个警告。由于使用了mask
属性,我们不再具有指示键盘焦点的默认轮廓,这对依赖键盘输入的用户来说是一个可访问性问题。
为了获得更好的用户体验并使组件更易于访问,最好在焦点时显示轮廓。最简单的解决方案是添加一个额外的包装器:
<input type="range">
当内部的输入具有焦点时,这将具有轮廓:
input[type="range"] { /* 主元素样式 */ } input[type="range"][i]::-webkit-slider-thumb { /* Chrome、Safari和Edge的滑块样式 */ } input[type="range"]::-moz-range-thumb { /* Firefox的滑块样式 */ }
尝试在下面的示例中使用键盘来调整这两个评分:
另一个想法是考虑更复杂的遮罩配置,该配置使元素周围的小区域保持可见以显示轮廓:
input[type="range"][i]::-webkit-slider-thumb, input[type="range"]::-moz-range-thumb { /* 滑块样式 */ }
我更喜欢使用最后一种方法,因为它保持了单元素实现,但也许您的HTML结构允许您在父元素上添加焦点,您可以保持遮罩配置简单。这完全取决于您!
正如我之前所说,我们制作的不仅仅是一个星级评分组件。您可以轻松更新遮罩值以使用任何您想要的形状。
这是一个示例,我使用的是心的SVG而不是星形。
为什么不是蝴蝶?
这次我使用PNG图像作为遮罩。如果您不习惯使用SVG或渐变,则可以使用透明图像。只要您有SVG、PNG或渐变,您就可以使用此方法做任何形状的事情。
我们可以进一步定制并创建一个像下面的音量控制组件:
在最后一个示例中,我没有重复特定的形状,而是使用复杂的遮罩配置来创建信号形状。
我们从一个星级评分组件开始,最后得到了许多很酷的示例。标题本可以是“如何设计范围输入元素”,因为这就是我们所做的。我们在没有任何脚本或额外标记的情况下升级了一个原生组件,并且只使用了几行CSS代码。
你呢?你能想到另一个使用相同代码结构的漂亮组件吗?在评论区分享您的示例!
以上是仅CSS的星级等级组件等等! (第1部分)的详细内容。更多信息请关注PHP中文网其他相关文章!