首页 >web前端 >css教程 >仅CSS的星级等级组件等等! (第1部分)

仅CSS的星级等级组件等等! (第1部分)

William Shakespeare
William Shakespeare原创
2025-03-07 16:38:11299浏览

A CSS-Only Star Rating Component and More! (Part 1)

构建星级评分组件是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%。

&lt;input type=&quot;range&quot;&gt;

您可能会问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 {
  /* 滑块样式 */
}

我们编写如下内容:

&lt;input type=&quot;range&quot;&gt;

上述内容意味着我们将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属性,我们不再具有指示键盘焦点的默认轮廓,这对依赖键盘输入的用户来说是一个可访问性问题。

为了获得更好的用户体验并使组件更易于访问,最好在焦点时显示轮廓。最简单的解决方案是添加一个额外的包装器:

&lt;input type=&quot;range&quot;&gt;

当内部的输入具有焦点时,这将具有轮廓:

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代码。

你呢?你能想到另一个使用相同代码结构的漂亮组件吗?在评论区分享您的示例!

文章系列

  1. 仅CSS的星级评分组件及更多!(第一部分)
  2. 仅CSS的星级评分组件及更多!(第二部分)— 3月7日推出!

以上是仅CSS的星级等级组件等等! (第1部分)的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn