几行代码 基于SVG+CSS clip-path 快速实现星级评分
前言
虽然星级评分的前端实现已经有很多种方案了,但是对于快速(1h内,从0-1)去了解实现此效果,那些案例涉及的知识点就比较多。于是只能在有限的时间内 利用空间换时间,用额外的div来实现星级评分效果。
太长不看版:codepen
效果
要实现上述的效果需要先做基本的拆解
- 星星有填充的 也有空心的
- 星星有填充一半的,也有填充10%的,此渲染应为动态
了解clip-path
clip-path CSS 属性使用裁剪方式创建元素的可显示区域。区域内的部分显示,区域外的隐藏。
通俗来理解就是一个白色的长方形的div 通过设置clip-path可以变成星型的不规则的div
找个svg图标
明白了clip-path属性后,下一步就找个svg图标。
https://icons.getbootstrap.com/
这里有三个icon,我们选择Star fill
原因下面来讲
懒得去翻页的可以直接看下述的SVG代码
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-star-fill" viewBox="0 0 16 16">
<path d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.282.95l-3.522 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"/>
</svg>
了解svg的clipPath与css中的clip-path
- css的clip-path属性可以引用svg中的clipPath
- css的clip-path属性可以直接用path函数生成(兼容性有坑)
https://developer.mozilla.org/zh-CN/docs/Web/SVG/Element/clipPath
我们先用第二种来绘制
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-star-fill" id="svgx" viewBox="0 0 16 16">
<clipPath id='svgclip'>
<path d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.282.95l-3.522 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"/>
</clipPath>
</svg>
<div class="s1"></div>
.s1{
width:16px;
height:16px;
background:red;
clip-path:path('M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.282.95l-3.522 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z');
}
这样是快速实现了一个小星星,如果你把这段代码在移动端执行的话会发现兼容性的问题(安卓12+微信浏览器,ios未测试)
初步看caniuse
也看不出path函数的兼容性问题.所以在实现的时候只能通过svg的clipPath来实现了
.s1{
width:100px;
height:100px;
background:red;
clip-path:url('#svgclip');
}
tips: svg的clipPath会截取掉其他内容,从而导致一个svg元素内部内容不可见(被裁剪了),实际上svg元素还是占位的。
div的width和height与svg的width、height保持一致性,裁剪的宽度是依赖svg的,为了避免不必要的额外宽高度占位。
实现宽度可变化的星
.s1{
display:inline-block;
width:8px;
height:16px;
background:red;
clip-path: url('#svgclip');
}
只需要调整div的高度 即可实现一个宽度的变化,那么,到这里就已经完善了么?
注意看我们要实现的效果其实有个空心的星边框,而我们绘制出来的div是实心的
实现一个空心的星
由于我们选择的是Star fill
,从实星变成空心的只需要利用到svg的stroke
属性
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="transparent" class="bi bi-star-fill" stroke="red" viewBox="0 0 16 16">
<path d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.282.95l-3.522 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"/>
</svg>
如果用的是空心的图标要实现反转填充就比较麻烦。
这样得到的效果就是一个空星,注意我们把fill="transparent"
设置为透明,边框stroke="red"
设置为红色
通过position定位整合div和svg
<div class="wrap">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="transparent" class="bi bi-star-fill" stroke="red" viewBox="0 0 16 16">
<path d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.282.95l-3.522 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z" />
</svg>
<div class="s1">
</div>
</div>
#svgx {
position: absolute;
z-index: -99;
}
.wrap {
position: relative;
display: inline-flex;
}
.s1 {
position: absolute;
left: 0;
top: 0px;
display: inline-flex;
width: 70%;
height: 100%;
background: blue;
clip-path: url("#svgclip");
}
我们可以动态的控制div的宽度来展示星级的填充度,设置inline-flex
而不是inline-block
的原因是避免font的空白。
详情可以见codepen