- 原文地址:Fractional SVG stars with CSS
- 原文作者:Samuel Kraft
- 译文出自:掘金翻译计划
不使用图片,如何构建一个星级/评级组件,支持像4.2或3.7这样的小数值? 这篇文章教你如何只使用CSS和内联svg,来制作评级分数星星组件。
笔者在一个电商公司工作,最近有个需求,需要做一个组件来显示客户评级。老版本用的是多个png图片叠加在一起,导致了不必要的请求和CLS 问题。新组件的标准是:
- 使用内联SVG而不是图片;
- 星星的数量支持动态;
- 需要支持小数值;
最终组件
下面是我们的组件:
代码:
import IconStar from 'star.svg';
const Rating = ({ value, max, className }) => {
/* 计算星星有多少需要被覆盖 */
const percentage = Math.round((value / max) * 100);
return (
<div className={styles.container}>
{
/* 用map渲染一个基于最大评分值的 IconStar 数组 */
}
{Array.from(Array(max).keys()).map((_, i) => (
<IconStar key={i} className={styles.star} />
))}
{
/* 把div放到星星组件的上面,用来遮住不需要显示的部分 */
}
<div className={styles.overlay} style={{ width: `${100 - percentage}%` }} />
</div>
);
}
组件由两部分组成:
- 基于最大评分星级的SVG图标列表(参数max);
- 一个覆盖在星星上的div,负责改变下面的星星的颜色。这就是小数部分工作的魔力。
覆盖在上面就是个普通的div,大小和下面不同的颜色/未填充的星星部分相同。我们计算div的宽度,首先用最大值除以评级,然后从100中减去这个值。
const percentage = Math.round((value / max) * 100);
<div className={styles.overlay} style={{ width: `${100 - percentage}%` }} />
添加下面的样式,给星星布局:
.container {
display: inline-flex;
align-items: center;
position: relative;
}
.star {
width: 18px;
margin-right: 2px;
display: flex;
color: #f8d448;
&:last-of-type {
margin-right: 0;
}
}
.overlay {
background-color: black;
position: absolute;
top: 0;
right: 0;
bottom: 0;
z-index: 1;
}
现在覆盖的是纯黑色,让我们来改变它的颜色:
使用 mix-blend-mode 来改变SVG颜色
最后一步,使覆盖的 div 只影响下面的星形 svg,而不要影响到背景。我们可以使用 CSS 的 mix-blend-mode 混合模式属性和颜色值来做。
颜色说明如下: 使用源色的色相和饱和度以及背景色的亮度创建一个颜色。这保留了背景的灰度,对单色/彩色图形上色很有用。
我们用这个属性给图形上色,看看会发生什么:
.overlay {
background-color: black;
mix-blend-mode: color;
position: absolute;
top: 0;
right: 0;
bottom: 0;
z-index: 1;
}
这正是我们想要的! 它改变了星星的色调和饱和度,但保持背景色不变。你可以用背景色来改变星星的颜色。例如,如果我使用background-color: red,我得到的是红色而不是灰色的星星。
浏览器的支持度非常好(所有现代浏览器都支持),但对于较老的浏览器,我们可以改用 opacity:
.overlay {
background-color: black;
mix-blend-mode: color;
position: absolute;
top: 0;
right: 0;
bottom: 0;
z-index: 1;
@supports not(mix-blend-mode: color) {
opacity: 0.7;
}
}
你可以在 这里 找到完整的源代码。如果你觉得这个 CSS 技巧有用,请动动手指点个赞,非常感谢!