题外话
从后面开始,文章中的代码演示会用Codepen来替代。
这样做的好处有
- 方便自己对所写过的demo进行统一的管理
- 方便文章中的展示,前面都是直接在文章中嵌入html代码和css样式,这样就会造成css样式名的冲突,前面的解决方式就是不断的重新命名
star
、star01
、star02
等等这些 - 方便转载到其他平台。由于markdown语法中的html内嵌并不是一个标准语法,因而把内嵌大量html的markdown复制到其他平台,比如segmentfault,就会出现乱码的问题
Start
前面已经介绍了两种纯css实现打星星效果的方式,接下来继续扩展更多的功能,看着更接近平时说见到的效果,我们仍然会坚持用css来实现
如何实现鼠标滑动时有文字提示?
我们这里说的文字变化不是说那个title
效果,我们在淘宝上会见到当我们滑动鼠标在不同的星星上时,右边会有一个文字,分别提示类似于 满意,非常满意,一般
, 这样的提示效果,现在我们就来实现这样的效果。
先看效果
https://codepen.io/xboxyan/pe...点击预览
结构
html结构还是引用上一篇的:
<style>
<style> .star{ display: inline-block; font-size: 0; } .star-item{ display: inline-block; width: 20px; height:20px; cursor: pointer; background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAoCAMAAADJ7yrpAAAAYFBMVEUAAAD92Un92Un92Un92Un92Un92Un92Un92Un92Un92Un92Un92Un92Un92Un92Un92Un92Un92Un92Un92Un92Un92Un92Un92Un92Un92Un92Un92Un92Un92Un92UmCTPEWAAAAH3RSTlMA9iwe++hAgPLJo13i3Td8JO3Sk4xtYkYUC76cVBIjGgBFCwAAAMtJREFUKM+1kUkOhCAQRUEFBHGep67737JRlEFNJ73wbyAv9WtRD/1O3z/AqrqzDqC7spEAkPECGagwlwRJE28wbpJAk5xjcIJ5rmBBwAsp9nLpsvJYkMWWxRk6QrHZSJFJesIU2UQnjCwLwSQ0kG4zQmzzdmcCuA5VocaQGNiyQX8G1qK/8q6jNH1wtCx3RxwhfnUkM3Vs6ToSdNUDK52NI6JL+4R1JD/HYaXriOsP9xxN+p08R0JV1ZlnzxELRBSJIPccSe1IvufoCxGAFoLwSVOBAAAAAElFTkSuQmCC') center top no-repeat; } input[type="radio"]{ position: absolute; clip: rect(0,0,0,0) } input[type="radio"]:checked~.star-item{ background-position: center bottom; } .star:hover label.star-item{ background-position: center top; } label.star-item:hover~.star-item{ background-position: center bottom; } </style> <div class="star"> <label class="star-item" for="item01" title="垃圾"></label> <input type="radio" name="item" id="item01" checked /><!--这里设置checked初始状态--> <label class="star-item" for="item02" title="很差"></label> <input type="radio" name="item" id="item02" /> <label class="star-item" for="item03" title="一般"></label> <input type="radio" name="item" id="item03" /> <label class="star-item" for="item04" title="很好"></label> <input type="radio" name="item" id="item04" /> <label class="star-item" for="item05" title="完美"></label> <input type="radio" name="item" id="item05" /> </div>
一点思路
如果想实现星星最后面有一行提示文字,按照一般的思路,可能就是在最后一颗星星后面直接添加一个标签span,然后通过js监听mouseover
和mouseout
事件来修改span的innerHTML
,只要会点js的通应该能实现,那么通过css如何实现呢?
显然是不能直接修改innerhtml
的,那么该如何修改呢?
我们可以直接用:after
伪元素来生成内容,比如
span:after{content:'我是生成的内容'}
那么我们就可以通过伪元素的content来用css生成内容
修改一下结构
<div class="star"> <label class="star-item" for="item01" title="垃圾"></label> <input type="radio" name="item" id="item01" checked /><!--这里设置checked初始状态--> <label class="star-item" for="item02" title="很差"></label> <input type="radio" name="item" id="item02" /> <label class="star-item" for="item03" title="一般"></label> <input type="radio" name="item" id="item03" /> <label class="star-item" for="item04" title="很好"></label> <input type="radio" name="item" id="item04" /> <label class="star-item" for="item05" title="完美"></label> <input type="radio" name="item" id="item05" /> <span class="star-tip"></span><!--添加一个标签来存放文字提示--> </div>
现在我们再来添加一点css来生成内容
.star-item[title="垃圾"]:hover~.star-tip:after{ contnet:"垃圾" }
这样当鼠标滑过第一个星星的时候,后面就会生成垃圾
的提示。
全部写完整就是
.star-item[title="垃圾"]:hover~.star-tip:after{ contnet:"垃圾" } .star-item[title="很差"]:hover~.star-tip:after{ contnet:"很差" } .star-item[title="一般"]:hover~.star-tip:after{ contnet:"一般" } .star-item[title="很好"]:hover~.star-tip:after{ contnet:"很好" } .star-item[title="完美"]:hover~.star-tip:after{ contnet:"完美" }
这样应该可以实现鼠标移动到哪就提示相应的文字,但是,不觉得这样写法有点太不智能了吗,完全就是复制粘贴,如果有Less
或者Sass
可以简单写一个循环就可以自动生成这些了,但是本质还是一样的,写了这么多重复的代码,也没法合并,难道css就没办法了吗?
其实还是有的,我们要用到content
的attr
功能,就是取到相应属性的值,有点变量的意思,比如
<style> span:after{content:attr(a)} </style> <span a="我是A"></span>
这样span
就会根据自身的a
属性来生成内容了
我们现在把之前添加的<span class="star-tip"></span>
去掉,不可能再根据他那生成了,我们现在需要根据label
自身来生成内容,添加如下css
.star{ position:relative;/*添加相对定位,因为生成的内容要相对于最外层了*/ } .star-item:after{/*加点样式*/ position:absolute; width:100px; font-size:14px; height:20px; line-height:20px; right:0; margin-right:-105px; color:#666 } .star-item:hover:after{ content:attr(title) }
这样还不够,我们还需要根据:checked
记住当前选项
input[type="radio"]:checked+.star-item:after{/*选择input相邻的下一个label*/ content:attr(title) }
这里有个问题,label
和input
的顺序反过来了,这里我们对调一下,所以之前的代码需要修复一下
<style> .star{ display: inline-block; font-size: 0; } .star-item{ display: inline-block; width: 20px; height:20px; cursor: pointer; background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAoCAMAAADJ7yrpAAAAYFBMVEUAAAD92Un92Un92Un92Un92Un92Un92Un92Un92Un92Un92Un92Un92Un92Un92Un92Un92Un92Un92Un92Un92Un92Un92Un92Un92Un92Un92Un92Un92Un92Un92UmCTPEWAAAAH3RSTlMA9iwe++hAgPLJo13i3Td8JO3Sk4xtYkYUC76cVBIjGgBFCwAAAMtJREFUKM+1kUkOhCAQRUEFBHGep67737JRlEFNJ73wbyAv9WtRD/1O3z/AqrqzDqC7spEAkPECGagwlwRJE28wbpJAk5xjcIJ5rmBBwAsp9nLpsvJYkMWWxRk6QrHZSJFJesIU2UQnjCwLwSQ0kG4zQmzzdmcCuA5VocaQGNiyQX8G1qK/8q6jNH1wtCx3RxwhfnUkM3Vs6ToSdNUDK52NI6JL+4R1JD/HYaXriOsP9xxN+p08R0JV1ZlnzxELRBSJIPccSe1IvufoCxGAFoLwSVOBAAAAAElFTkSuQmCC') center top no-repeat; } input[type="radio"]{ position: absolute; clip: rect(0,0,0,0) } input[type="radio"]:checked+.star-item~.star-item{/**这里需要排除掉当前选项,所以选择的是下一个(+)节点的后面的(~)节点**/ background-position: center bottom; } .star:hover label.star-item{ background-position: center top!important;/**由于前面的选择器层级较高,这里简单用!important来处理**/ } label.star-item:hover~.star-item{ background-position: center bottom!important; } </style> <div class="star"> <input type="radio" name="item" id="item01" checked /><!--这里设置checked初始状态--> <label class="star-item" for="item01" title="垃圾"></label> <input type="radio" name="item" id="item02" /> <label class="star-item" for="item02" title="很差"></label> <input type="radio" name="item" id="item03" /> <label class="star-item" for="item03" title="一般"></label> <input type="radio" name="item" id="item04" /> <label class="star-item" for="item04" title="很好"></label> <input type="radio" name="item" id="item05" /> <label class="star-item" for="item05" title="完美"></label> </div>
这样也能达到同样的效果,选中效果效果也出来了,但是选中和滑动会有重叠效果,选择需要在滑动时去掉选中效果,同样是先清空再添加的思路
.star:hover .star-item:after{ content:''!important } input[type="radio"]:checked+.star-item:after{ content:attr(title) } .star:hover .star-item:hover:after{ content:attr(title)!important }
注意里面的层级覆盖关系,可以多试一下。
下面奉献完整代码
<style> .star{ display: inline-block; font-size: 0; position:relative; } .star-item{ display: inline-block; width: 20px; height:20px; cursor: pointer; background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAoCAMAAADJ7yrpAAAAYFBMVEUAAAD92Un92Un92Un92Un92Un92Un92Un92Un92Un92Un92Un92Un92Un92Un92Un92Un92Un92Un92Un92Un92Un92Un92Un92Un92Un92Un92Un92Un92Un92Un92UmCTPEWAAAAH3RSTlMA9iwe++hAgPLJo13i3Td8JO3Sk4xtYkYUC76cVBIjGgBFCwAAAMtJREFUKM+1kUkOhCAQRUEFBHGep67737JRlEFNJ73wbyAv9WtRD/1O3z/AqrqzDqC7spEAkPECGagwlwRJE28wbpJAk5xjcIJ5rmBBwAsp9nLpsvJYkMWWxRk6QrHZSJFJesIU2UQnjCwLwSQ0kG4zQmzzdmcCuA5VocaQGNiyQX8G1qK/8q6jNH1wtCx3RxwhfnUkM3Vs6ToSdNUDK52NI6JL+4R1JD/HYaXriOsP9xxN+p08R0JV1ZlnzxELRBSJIPccSe1IvufoCxGAFoLwSVOBAAAAAElFTkSuQmCC') center top no-repeat; } input[type="radio"]{ position: absolute; clip: rect(0,0,0,0) } input[type="radio"]:checked+.star-item~.star-item{/**这里需要排除掉当前选项,所以选择的是下一个(+)节点的后面的(~)节点**/ background-position: center bottom; } .star:hover label.star-item{ background-position: center top!important;/**由于前面的选择器层级较高,这里简单用!important来处理**/ } label.star-item:hover~.star-item{ background-position: center bottom!important; } .star-item:after{/*加点样式*/ position:absolute; width:100px; font-size:14px; height:20px; line-height:20px; right:0; margin-right:-105px; color:#666 } .star:hover .star-item:after{ content:''!important } input[type="radio"]:checked+.star-item:after{ content:attr(title) } .star:hover .star-item:hover:after{ content:attr(title)!important } </style> <div class="star"> <input type="radio" name="item" id="item01" checked /><!--这里设置checked初始状态--> <label class="star-item" for="item01" title="垃圾"></label> <input type="radio" name="item" id="item02" /> <label class="star-item" for="item02" title="很差"></label> <input type="radio" name="item" id="item03" /> <label class="star-item" for="item03" title="一般"></label> <input type="radio" name="item" id="item04" /> <label class="star-item" for="item04" title="很好"></label> <input type="radio" name="item" id="item05" /> <label class="star-item" for="item05" title="完美"></label> </div>
codepen效果
https://codepen.io/xboxyan/pe...点击预览
小节
通过一番努力,这个打星星效果基本上满足一般的业务需求,没有用到任何js代码,完美兼容ie8浏览器,应该能体现出css的强大之处吧,虽然css现在还比较蹩脚,但是用css的思路来实现一个逻辑还挺有意思的,可以从更多的角度去解决一个问题,有时反而会更简单