单个 HTML 元素星级评定组件 CultSoft #CodingHappiness #DeveloperLife #NoErrors #TechCommunity

2025-06-11

单个 HTML 元素星级评定组件

CultSoft #CodingHappiness #DeveloperLife #NoErrors #TechCommunity

过去,创建自定义组件需要 HTML、CSS 和 JavaScript 的复杂组合。然而,近年来 CSS 的进步使我们能够仅使用 HTML 和 CSS 构建许多组件——利用浏览器中已有的逻辑。既然可以重用大部分逻辑,何必再去重新发明轮子呢?

像复选框、单选按钮和切换开关这样的简单组件可以用 HTML 和 CSS 创建,并依赖浏览器来实现功能。但我们并不局限于简单的组件,更复杂的组件也可以通过这种方式实现。

在本文中,我们将探讨如何使用单个 HTML 和一个 JavaScript 命令构建星级评分系统。

HTML

星级评定组件本质上是一个可供用户选择的数值范围。其变体可能包含 5 个数值(每颗星一个)或 10 个数值(允许半颗星),但其核心思想保持不变:用户只能选择一个数值。

HTML 提供了一种为范围设计的输入类型,我们可以将其用作组件的基础:

<input type="range">
Enter fullscreen mode Exit fullscreen mode

目前来看,这个输入没什么用。我们需要根据设计规范定义一些属性:

  1. 允许半星评级。
  2. 从 0.5 星到 5 星不等。
  3. 默认选择为 2.5 星。

根据上述规范,HTML 将如下所示:

<input type="range" min="0.5" max="5" step="0.5" value="2.5">
Enter fullscreen mode Exit fullscreen mode

此组件是一个范围输入 ( <input type="range">),允许用户以 0.5 ( ) 为增量,选择一个介于 0.5 ( min="0.5") 到 5 星 ( ) 之间的值。初始值设置为 2.5 星 ( )。max="5"step="0.5"value="2.5"

将最小值设置为 0.5 而不是 0 可能看起来有些不寻常,但这是有实际原因的。允许 0 星评价会产生 11 个潜在值,但该范围在视觉上代表了 10 个值(10 个半星),从而导致可点击区域与范围内的星数不匹配。这种设计选择确保了更好的可用性,并简化了后续的实现。

10 个和 11 个点击区域的星级评定系统比较

设置最小值 0.5 可实现更自然的点击区域

使用 11 个单选按钮创建组件可以部分解决这个问题。但这会引发新的设计问题(如何使用鼠标选择 0 值?)、可用性问题(我们应该模拟范围输入的原生行为还是单选按钮的原生行为?)以及可访问性问题(如何管理整个组件的焦点?)。 

这些问题对于另一个关于如何使用单选按钮创建评级组件的教程来说非常好。在本教程中,我们将介绍如何使用单个 HTML 元素创建该组件,为了避免这些复杂性,我选择了最小值 0.5。

我们稍后会添加一些调整,但这段代码可以作为一个不错的起点。无需任何 CSS,它在视觉上类似于标准的范围输入:

已选择一半输入范围的屏幕截图。

接下来,我们将添加一些属性。虽然它们现在看起来可能不重要,但以后会很重要:

  • 类名:有助于识别 CSS 中的范围输入。
  • 内联样式:使用自定义属性来存储输入的值。
  • 内联 JavaScript:单个命令,用于更新上述内联样式中的自定义属性。

最终代码将如下所示(格式化以便于阅读):

<input 
  type="range"
  min="0.5"
  max="5"
  step="0.5"
  value="2.5"
  class="star-rating"
  style="--val: 2.5"
  oninput="this.style='--val:'+this.value"
>
Enter fullscreen mode Exit fullscreen mode

CSS

为范围输入设置样式可能比较棘手,但也不会太复杂。遗憾的是,由于缺乏支持和标准化,它需要大量的重复工作,所以我们必须针对组件的不同元素使用供应商前缀和特定于浏览器的伪类:

  • thumb:用户可以移动该元素来更改其值。伪元素包括 ::-webkit-slider-thumbChrome 和 Safari 以及 ::-moz-range-thumbFirefox。
  • track:滑块滑动的区域或线条。伪元素包括 ::-webkit-slider-runnable-track(Chrome 和 Safari)和 ::-moz-range-track(Firefox)。

当然,我们需要针对每个浏览器应用一些特定的样式,因为它们的样式设置并不一致。例如,我们需要在 Safari 上设置高度,或者在 Firefox 上移除烦人的边框。

从这里开始,接下来的步骤如下:

  1. 定义星级评定组件的大小。
  2. 遮盖轨道,仅保留可见的星星形状。
  3. 定义仅为选定星星着色的背景。
  4. 隐藏拇指。

隐藏缩略图是可选的,具体取决于您正在构建的组件类型。在这个星级评分系统中,隐藏缩略图是合理的。但是,在用户满意度组件中,缩略图可能很有用。您可以在本文末尾探索不同的演示。

设置范围元素的样式

第一步是移除范围输入框的默认外观。这可以通过设置属性来实现appearance:none。所有现代浏览器都支持此功能,但我们可能需要添加带供应商前缀的版本,以便也能兼容旧版浏览器。

因为我们有五颗星,所以将宽度设置为高度的五倍是有意义的。aspect-ratio: 5/1可以处理这个问题,但有些浏览器仍然支持不一致,所以我们将使用自定义属性“硬编码”大小。

此外,我们想移除边框。Firefox 对范围应用了默认边框,移除边框可以确保跨浏览器的样式更加一致。

.star-rating {
  --size: 2rem;
  height: var(--size);
  width: calc(5 * var(--size));
  appearance: none;
  border: 0;
}
Enter fullscreen mode Exit fullscreen mode

在下一节中,我们将稍微完善这条规则。我们需要为 Chrome/Safari 和 Firefox 定义样式,这会带来一些重复。我们可以通过使用自定义属性来存储值并将其应用于两种样式来简化这一过程。

赛道造型

轨道将占据元素的整个尺寸,然后我们将使用渐变来为我们需要的部分着色。

我们不需要担心宽度——它会占据元素的整个宽度——但高度就另当别论了。Chrome 和 Firefox 会让轨道的高度与容器高度匹配,而 Safari 则不会。所以,我们必须明确指定高度为 100%。

接下来我们要定义颜色区域。我们将利用之前创建的 --val 和 --size 自定义属性。我们将设置一个从左到右的线性渐变,并在 --val 属性指定的点处改变颜色:

linear-gradient(90deg, #000 calc(var(--size) * var(--val)), #ddd 0);
Enter fullscreen mode Exit fullscreen mode

我们将此渐变移动到父元素中的另一个自定义属性。这样我们就可以在 Chrome/Safari 和 Firefox 中复用该值——正如我之前提到的……并且可能稍后会提到。

这样,我们就得到了一个矩形,其中较暗的区域代表所选值。当我们点击或滑动矩形时,黑色区域会发生变化,这是我们想要的功能,但它缺少视觉效果。我们需要 CSS 遮罩。

黑色和灰色矩形

我不否认,下面的部分确实很丑。我选择完全使用 CSS,不依赖外部图片或内联 SVG。你可以使用其中任何一个选项来简化代码。

以下代码用于星形评级组件,但我们可以通过更改蒙版轻松更改形状(例如,更改为圆形)。

我们将使用一组圆锥渐变,通过 CSS 蒙版来裁剪一个五角星。它考虑了范围输入的大小,因此在水平重复蒙版后,我们将得到五颗星:

conic-gradient(from -18deg at 61% 34.5%, #0000 108deg, #000 0) 0 / var(--size),
conic-gradient(from 270deg at 39% 34.5%, #0000 108deg, #000 0) 0 / var(--size),
conic-gradient(from  54deg at 68% 56%,   #0000 108deg, #000 0) 0 / var(--size),
conic-gradient(from 198deg at 32% 56%,   #0000 108deg, #000 0) 0 / var(--size),
conic-gradient(from 126deg at 50% 69%,   #0000 108deg, #000 0) 0 / var(--size);
Enter fullscreen mode Exit fullscreen mode

与上面的线性渐变一样,我们将在 Chrome/Safari 和 Firefox 的样式中应用此蒙版。为了避免代码重复,我们将在父元素的自定义属性中定义它。

最终代码如下:

.star-rating {
  --size: 2rem;
  --mask: conic-gradient(from -18deg at 61% 34.5%, #0000 108deg, #000 0) 0 0 / var(--size) var(--size),
      conic-gradient(from 270deg at 39% 34.5%, #0000 108deg, #000 0) 0 0 / var(--size) var(--size),
      conic-gradient(from 54deg at 68% 56%, #0000 108deg, #000 0) 0 0 / var(--size) var(--size),
      conic-gradient(from 198deg at 32% 56%, #0000 108deg, #000 0) 0 0 / var(--size) var(--size),
      conic-gradient(from 126deg at 50% 69%, #0000 108deg, #000 0) 0 0 / var(--size) var(--size);
  --background: linear-gradient(90deg, #000 calc(var(--size) * var(--val)), #ddd 0);
  height: var(--size);
  width: calc(5 * var(--size));
  appearance: none;
  border: 0;
}

/* Chrome and Safari */
.star-rating::-webkit-slider-runnable-track {
  height: 100%;
  mask: var(--mask);
  mask-composite: intersect;
  background: var(--background);
  -webkit-print-color-adjust: exact;
  print-color-adjust: exact;
}

/* Firefox */
.star-rating::-moz-range-track {
  height: 100%;
  mask: var(--mask);
  mask-composite: intersect;
  background: var(--bg);
  print-color-adjust: exact;
}
Enter fullscreen mode Exit fullscreen mode

请注意,Webkit 和 Firefox 的代码几乎完全相同。在这种情况下,CSS 中的 mixins 之类的功能会非常有用——尽管拥有单一支持的标准会更好。

我们还添加了一些样式(print-color-adjust: exact),以确保组件打印时与屏幕上的显示完全一致。这在使用背景时非常有用,因为背景通常默认不会打印。

拇指造型

在这个星级评定系统中,缩略图并不是特别重要。视觉效果是通过轨道本身实现的。因此,我们将缩略图隐藏起来。

我们可以通过将其不透明度设置为零来实现:

/* Chrome and Safari */
.star-rating::-webkit-slider-thumb {
  opacity: 0;
}

/* Firefox */
.star-rating::-moz-range-thumb {
  opacity: 0;
}
Enter fullscreen mode Exit fullscreen mode

你可能已经注意到,我在上面的代码片段中没有使用 CSS 嵌套(而在下面的示例中使用了)。这是因为嵌套相对较新,并且存在一些限制:许多老版本的浏览器不支持它,而且一些现代浏览器难以处理非标准的伪元素——我在 WebKit 上报告了一个关于 Safari 上此行为的 bug

示例

俗话说,一图胜千言。以下是一些可以使用单个 HTML 元素进行编码的输入范围示例。

让我们从本文描述的星级组件开始:

接下来是一个丰富多彩的例子。它的形状非常特殊,需要对范围输入的所有部分进行样式设置:范围本身、轨道和拇指:

最后,我最喜欢的一个:一个动画的、单元素的用户满意度组件。选择任意不同的表情,它们都会根据选择而移动:

结论

编写此组件的方法有很多种。我仅使用 HTML 和 CSS(使用一个内联 JavaScript 命令)就完成了,但您也可以使用图像或更多 JavaScript 来避免那种丑陋的内联。 

关键思想是,通过最少的 HTML 和 CSS 更改,您可以调整规格,并且您的星级评定系统的行为将略有不同或看起来完全不同。

也可以使用多个单选按钮来重新创建该组件,这样就无需编写 JavaScript 代码和一些 CSS 代码了。这是一种有效的方法。它需要额外的代码来确保可访问性,并复制输入框默认的行为。有些人可能会觉得这种方法更容易,而且它确实是可行的。

这是我最喜欢软件开发的原因之一:有许多不同的方法和选项,每种方法和选项都有其优点和缺点,但都可以完美实现。

希望你喜欢这篇文章。继续编码!

鏂囩珷鏉ユ簮锛�https://dev.to/alvaromontoro/single-html-element-star- rating-component-205l
PREV
使用 Node.js 和 HarperDB GenAI LIVE 构建 REST API!| 2025 年 6 月 4 日
NEXT
在 React 中管理状态:Redux 还是非 Redux?