用純css實現打星星效果(三)

XboxYan發表於2018-07-13

題外話

檢視原文可以有更好的排版效果哦

從後面開始,文章中的程式碼演示會用Codepen來替代。

這樣做的好處有

  1. 方便自己對所寫過的demo進行統一的管理
  2. 方便文章中的展示,前面都是直接在文章中嵌入html程式碼和css樣式,這樣就會造成css樣式名的衝突,前面的解決方式就是不斷的重新命名 starstar01star02等等這些
  3. 方便轉載到其他平臺。由於markdown語法中的html內嵌並不是一個標準語法,因而把內嵌大量html的markdown複製到其他平臺,比如segmentfault,就會出現亂碼的問題

Start

前面已經介紹了兩種純css實現打星星效果的方式,接下來繼續擴充套件更多的功能,看著更接近平時說見到的效果,我們仍然會堅持用css來實現

如何實現滑鼠滑動時有文字提示?

我們這裡說的文字變化不是說那個title效果,我們在淘寶上會見到當我們滑動滑鼠在不同的星星上時,右邊會有一個文字,分別提示類似於 滿意,非常滿意,一般, 這樣的提示效果,現在我們就來實現這樣的效果。

先看效果

https://codepen.io/xboxyan/pe…

結構

html結構還是引用上一篇的:

<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監聽mouseovermouseout事件來修改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就沒辦法了嗎?

其實還是有的,我們要用到contentattr功能,就是取到相應屬性的值,有點變數的意思,比如

<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)
}

這裡有個問題,labelinput的順序反過來了,這裡我們對調一下,所以之前的程式碼需要修復一下

<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的思路來實現一個邏輯還挺有意思的,可以從更多的角度去解決一個問題,有時反而會更簡單

相關文章