html5 %3cdiv%3e,换一种方式来实现CSS评分组件

评分组件想必大家都碰到过了吧,纯 CSS 方式网上也有很多实现,一般都是通过 input[type="radio"] 实现,比如这个

大致原理如下通过 flex-direction: row-reverse 或者其他手段(dirction:rtl、transform:scaleX(-1)),将元素位置翻转

配合 :checked 和 ~ 选中视觉上的前面兄弟节点

实现非常精妙,无需 js 接入,兼容性也不错,不过这里还有两个瑕疵视觉展示和页面结构不一致,比如给每个 input 添加 value 属性,需要倒序来加,不符合一般人的认知

879e21298f3d6b165497068c6eed9367.png

优化

上面提到的两个瑕疵其实都是元素位置翻转引起的,目的也是为了实现视觉上的前置兄弟节点选择器,有没有什么办法规避这个问题呢?答案就是重置,处理如下默认情况下都是选中的样式

配合 :checked 和 ~ 选中后面的元素,样式设置为未选中的样式

具体实现如下,html 为正常结构

下面是关键样式[type="radio"]{

-webkit-appearance: none;

width: 20px;

height: 20px;

-webkit-mask: url("data:image/svg+xml,%3Csvg width='12' height='11' viewBox='0 0 12 11' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M6 0l1.693 3.67 4.013.476L8.74 6.89l.788 3.964L6 8.88l-3.527 1.974.788-3.964L.294 4.146l4.013-.476L6 0z' fill='%23F67600'/%3E%3C/svg%3E");

-webkit-mask-size: 20px;

-webkit-mask-repeat: no-repeat;

-webkit-mask-position: center;

background-color: coral; /*默认是选中的样式,橙色*/

margin: 0;

transition: .2s;

}

[type="radio"]:checked~[type="radio"]{

background-color: #E8EAED; /*未选中的样式,灰色*/

}这里的星星图形是通过 mask 实现的,根据实际需求也可采用传统背景图片的方式

可以看到优化后的方案代码更加精简了,html 也符合常规认知,键盘切换也正常了

d352c938f4ac2c452af04885fec3fd79.png

当然这个实现也还是有点瑕疵的,由于默认是选中状态,所以即使没有任何 :checked, 也会是全部高亮(满分)的情况,不会有0分的情况,所以推荐默认把最后一项设置 checked 属性。当然实际场景也并不会有0分的选项,很多场景下都是默认满分,所以这个小问题无伤大雅~

半颗星的实现

在上面的基础上,半颗星也很容易,只需要使用 10 个 input,每个只占据一半的空间即可10个input

每个input宽度为之前的一半

配合 nth-child(odd)、nth-child(even)设置显示区域

具体实现如下

下面是关键样式.rate-half [type="radio"]{

width: 10px; /* 宽度设置一半 */

}

.rate-half [type="radio"]:nth-child(odd){

-webkit-mask-position: left; /* 设置星星的显示区域 */

}

.rate-half [type="radio"]:nth-child(even){

-webkit-mask-position: right;

}

以上源码可查看 codepen

更好的实现

上面的实现已经非常完美了,无需 js,兼容性也不错,但是还是有些需要改进的地方,比如html 修改起来比较麻烦,从 5 分制改成 10 分制需要改动每一个 input 的 value 属性

星星的数量修改起来比较麻烦,从 5 颗星改成 10 颗星,需要手动添加新的 input 节点

js 获取当前值相对比较麻烦,需要使用 document.quertSelector([type="radio"][name="rate"]:checked).value,不太符合语意,新手可能不太熟悉

那么,还有没有其他方式可以实现类似的效果呢?可以这样想一下,评分组件本质上也是一个表单输入组件,不考虑样式的话,普通的 input 也完全可以实现同样的输入功能,只是需要手动键盘输入而已。那有没有不需要手动输入的只需要简单拖拽就可以完成表单输入的呢?答案就是 input range范围选择器

0df3151eeda53b7dab946eeaca955897.png

范围选择器有一些默认值最小值 min 为 0

最大值 max 为 100

默认值 value 为区域范围的一半,50

默认步长 step 为 1

现在和上面的评分组件对照起来,就可以很容易得出下面的结构

这是一个可以输入 0~5 整数的组件,不能有小数出现,功能已经完全满足了

input range 的 shadow dom

现在可以开始改造样式了,在开始之前,可以在 Chrome 中开启 shadow-dom 的显示,方式为在控制台右上角 setting > preferences > Elements,勾选 Show user agent shadow DOM (已经勾选过的可以忽略)

83a12995029aeda8ff8becbe2682591b.png

这时便可很清楚的看到 input range 的内部结构

b0bacee7dac63b848ac9bbc2cde43c4c.png

这里一共有三层,分别对应的选择器如下容器 input[type="range" i]::-webkit-slider-container

轨道 input[type="range" i]::-webkit-slider-runnable-track

滑块 input[type="range" i]::-webkit-slider-thumb

input range 自定义样式

很多时候默认样式不是我们需要的,而且也不易修改,比如 Chrome 中 input range 的已滑动蓝色区域,这部分是无法修改的(Firefox 可以,这里只针对于 Chrome,其他浏览器原理类似),首先要做的就是重置input[type="range"]{

-webkit-appearance: none;

}

然后,由于滑块也是占据空间的,为了消除这个影响,可以将宽度设置为 0,当然也需要重置默认样式input[type="range" i]::-webkit-slider-thumb {

-webkit-appearance: none;

width: 0;

}

由于 Chrome 没有已滑动区域和未滑动区域的区分,这里采用足够大的 box-shadow 来覆盖实现input[type="range" i]::-webkit-slider-thumb {

box-shadow: 999px 0px 0px 999px #E8EAED; /*可以实现一个右侧的足够大的阴影*/

}

通过以上几步可以实现一个这样的效果,可以先停下来体会一下?

12d2859c5176d597f24beb3f6512a054.png

最后一步,加上 mask 遮罩,实现镂空效果input[type="range" i]::-webkit-slider-runnable-track {

-webkit-mask: url("data:image/svg+xml,%3Csvg width='12' height='11' viewBox='0 0 12 11' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M6 0l1.693 3.67 4.013.476L8.74 6.89l.788 3.964L6 8.88l-3.527 1.974.788-3.964L.294 4.146l4.013-.476L6 0z' fill='%23F67600'/%3E%3C/svg%3E"); /*星星图案*/

-webkit-mask-size: 20px;

-webkit-mask-repeat: repeat-x;

}

用一张动图描述一下效果

8c706ad87c49c874f6ebe458ef36df26.png

以上源码可查看 codepen

相关扩展

那么,现在来扩展一下,比如实现一个 10 颗星,总分 100 分的评分组件,支持半颗星,实现如下

还需要修改一下宽度input[type="range"]{

width: 200px; /*每个星星的尺寸为20 * 20,10颗星宽度就是200*/

}

这样就得到了一个 10 颗心的评分组件

4df1a7e50a5a872a5801b5037db51534.png

有时候,如果需要仅仅作为展示,比如一些电影评分,添加 disabled 就可以了~

55d9d9e344b7fbbc082f491046049e0b.png

Firefox 的兼容

Firefox 也可以采用类似的原理,只需要换上对应的选择器即可,如下容器 input[type=range](没有单独的容器,用最外层代替)

轨道 input[type=range]::-moz-range-track

滑块 input[type=range]::-moz-range-thumb

但是,Firefox 还有一个表示进度的选择器 ::-moz-range-progress,这样就可以不用 box-shadow 来遮盖了,所以,针对 Firefox 的另一种实现方式如下input[type=range]{

-webkit-mask: url("data:image/svg+xml,%3Csvg width='12' height='11' viewBox='0 0 12 11' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M6 0l1.693 3.67 4.013.476L8.74 6.89l.788 3.964L6 8.88l-3.527 1.974.788-3.964L.294 4.146l4.013-.476L6 0z' fill='%23F67600'/%3E%3C/svg%3E");

-webkit-mask-size: 20px;

-webkit-mask-repeat: repeat-x;

height: 20px;

}

input[type=range]::-moz-range-track{

background: #E8EAED;

height: inherit;

}

input[type=range]::-moz-range-progress {

background: coral;

height: inherit;

}

input[type=range]::-moz-range-thumb {

width: 0;

opacity: 0;

}

动图演示如下

202101080507496981.png

可以看到这里是单独的两层,和 Chrome 用阴影遮挡可不一样,因此可以实现更加灵活的效果,比如不依赖 mask 遮罩,分别设置不同的背景,下面是示意代码input[type=range]::-moz-range-track{

background: 未选中的星星;

height: inherit;

}

input[type=range]::-moz-range-progress {

background: 选中的星星;

height: inherit;

}

这样,在 Firefox 中这样的效果也能实现(前提是上面的可以遮挡住下面的)

2d4abea65668c626d59145105cfa7302.png

最后

首先说说这个方式的优点html 结构非常简单,就一个 input 元素

属性修改非常方便,只用设置 step、max等相关属性即可

语义非常友好,默认表单提交也天然支持

当然键盘切换也是没有问题

移动端支持友好,可以滑动选择

js 获取评分也符合常规表单,只需要 input.value 即可

当然,还是有一些局限IE 支持不够友好,理论上也是可以兼容的,尝试了一下在滑动的过程中会闪烁,体验不佳

没有 hover 样式

所以,如果你的项目不需要关照 IE ,大可以使用 input range 的方式~

b739ec46bb5c46d9c0aa4ce35ba1ea56.png

关于找一找教程网

本站文章仅代表作者观点,不代表本站立场,所有文章非营利性免费分享。

本站提供了软件编程、网站开发技术、服务器运维、人工智能等等IT技术文章,希望广大程序员努力学习,让我们用科技改变世界。

[换一种方式来实现CSS评分组件]http://www.zyiz.net/tech/detail-150682.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值