折騰:2顆星星+純CSS實現星星評分交互效果

by zhangxinxu from http://www.zhangxinxu.com
本文地址:http://www.zhangxinxu.com/wordpress/?p=3568

一、星星點燈,照亮我的家門

大家都喜歡聽故事。
每篇文章也都是有故事的。
今天的故事是與星星相關的。
沒錯,講的是星星點燈的故事——
纔怪!

標題只是我腦子突然蹦出來的,唉,這首老到掉渣子的歌我居然條件反射般想起,可見——我老了!

故事其實是這樣的~~

在天氣還未如此炎熱的某天,@waylybaye微博上展示了其使用canvas繪製星星圖片,然後再保存爲png格式使用的折騰:
canvas與星星png圖的繪製

很贊,對不對!

然,故事剛剛開始,

而後我隨便吐槽了句:

這種效果兩個星星就可以完全CSS實現了,包括IE6瀏覽器,多少多餘勞動力浪費了啊~~

一石激起三層浪:
微博回覆截圖

有人對兩顆星星實現星星評分效果感興趣;有人覺得純CSS搞不定記住之前用戶所選星星。

實際上,兩顆星星(見下圖)完全可以實現兼容IE6在內的效果;而且,純CSS可是可以記住當前星星點擊個數哦!
兩顆星星

哈哈,我們的故事就此展開……

二、小星星,亮晶晶,點點像你的眼睛

正片之前先來個精彩預告,您可以狠狠地點擊這裏:兩顆星星實現的星星點擊評分效果demo

哈哈,這回不上截圖了,上截視頻,更直觀,截自Chrome瀏覽器,純CSS實現。對了,貌似忘記把《愛情公寓》電視關掉,有雜音,嘻嘻……

 

iPad黨若看不到上視頻,可以點擊下面區域查看截圖:

 

您可能會驚訝地發現,誒,怎麼點擊的星星可以記住啊,純CSS?鑫哥你確定不是在忽悠?

忽悠

我不姓趙哦~

慢慢來,先看看兩個星星如何實現兼容IE6瀏覽器的hover交互效果。

三、一閃一閃亮晶晶 滿天都是小星星

兩個星星實現原理見下圖:
兩顆星星實現兼容交互原理示意圖1 張鑫旭-鑫空間-鑫生活   兩顆星星實現兼容交互原理示意圖2 張鑫旭-鑫空間-鑫生活

  1. 背景色就是灰色平鋪;
  2. 5個小標籤,分別對應每個星星,寬度1/5,其垂直層次關係見圖1示意;
  3. 當鼠標經過某星星,例如上圖所示第3個,寬度延伸,背景顯示,hover效果即呈現;
  4. 最後,仔細觀察其他小星星的層次以及位置,不存在覆蓋的情況,於是,hover其他小星星,效果同樣存在;
  5. over!

以上就是使用兩個星星+純CSS實現hover效果的原理。

5個小星星使用a標籤,則可兼容IE6瀏覽器。

HTML結構如下:

<div class="star_bg">
    <a class="star star_1"></a>
    <a class="star star_2"></a>
    <a class="star star_3"></a>
    <a class="star star_4"></a>
    <a class="star star_5"></a>
</div>

CSS示意如下:

/* 灰色背景星星5個平鋪 */
.star_bg {
    width: 120px; height: 20px;
    background: url(star.png) repeat-x;
    position: relative;
    overflow: hidden;
}
/* 這是5個小星星們的默認狀態的定位 */
.star {
    height: 100%; width: 24px;
    line-height: 6em;
    position: absolute;
    z-index: 3;
}
.star_1 { left: 0; }
.star_2 { left: 24px; }
.star_3 { left: 48px; }
.star_4 { left: 72px; }
.star_5 { left: 96px; }

/* 鼠標hover效果實現,分別顯示背景與定寬 */
.star:hover {    
    background: url(star.png) repeat-x 0 -20px;
    left: 0; z-index: 2;
}
.star_1:hover { width: 24px; }
.star_2:hover { width: 48px; }
.star_3:hover { width: 72px; }
.star_4:hover { width: 96px; }
.star_5:hover { width: 120px; }

兩顆星星hover事故講完了,那如何記住星星點擊的故事呢?

四、城市裏 小星星 稀疏的 亮晶晶

去年年初曾介紹過“CSS radio/checkbox單複選框元素顯隱技術”,又稱“checkbox hack技術”。

利用label for與單複選框等之間的點擊關聯特性,結果:checked僞類選擇器以及兄弟選擇器實現我們想要的交互效果——例如,元素的顯示與隱藏,或者是選中的星星個數標記。

有些迷糊?不急,來個最簡單示例,跟我一步一步來:

  1. 一個單選框,以及一個對應的label標籤,如下:
    <input type="radio" id="testRadio"><label for="testRadio">觀光團</label>
  2. 點擊含“觀光團”字樣的label標籤,只要不是奇葩設備,單選框都會被選中的(因爲for值等於單選框id值);
  3. 於是,觸發瞭如下僞類:
    input:checked {}
  4. CSS3中還有兄弟選擇器,如~以及相鄰兄弟選擇器+,於是,我們可以改變label標籤的狀態,例如,文字變紅:
    input:checked + label { color: red; }
  5. 如果我們把label做成星星背景,豈不是我們點擊這個星星,觸發radio選中,就可以讓這個label標籤一直顯示星星背景?
    input:checked + label { background: url(star.png) repeat-x 0 -20px; }

以上就是實現的基本原理。

OK,下面來看看demo頁面是如何處理的。

  • 因爲要兼顧IE6瀏覽器(hover效果),因此,採用的是a標籤內嵌label標籤的形式。如果您不考慮IE6瀏覽器,牆裂推薦直接一個label標籤。於是,就有類似下面的HTML結構(第一顆星星示意):
    <input type="radio" id="starScore1" class="score score_1" value="1" name="score">
    <a href="#starScore1" class="star star_1" title="差"><label for="starScore1">差</label></a>

    a標籤負責hover效果,label標籤負責點擊效果。

  • 我們需要隱藏單選框,且爲可用性隱藏。我是使用clip實現的:
    { position: absolute; clip: rect(0 0 0 0); }
  • 僞類與兄弟選擇器控制星星在對應單選框選中中的狀態,其實與hover的CSS類似:
    .score:checked + .star {    
        background: url(star.png) repeat-x 0 -20px;
        left: 0; z-index: 1;
    }
    .score_1:checked ~ .star_1 { width: 24px; }
    .score_2:checked ~ .star_2 { width: 48px; }
    .score_3:checked ~ .star_3 { width: 72px; }
    .score_4:checked ~ .star_4 { width: 96px; }
    .score_5:checked ~ .star_5 { width: 120px; }

    於是,我們就實現了點擊記住星星個數的效果了!

  • 但,直接這樣是有問題的,見下圖示意:
  • 點擊固定顯示的星星影響hover的顯示 張鑫旭-鑫空間-鑫生活

     

    例如,點擊第三顆星星,自然星星三顆呈現。此時,鼠標hover第2顆星星,理應顯示兩顆星星,但由於下面三顆星星佔道了,因此,實際上顯示了是3顆星星,問題出現。

    問題其實不難解決。

    我們只要讓鼠標hover星星容器時候,所有背景都沒有;經過星星時候,背景出現就可以了。

    .star_bg:hover .star {  background-image: none; } /* 經過父級容器,星星背景圖去除 */

    父級背景隱藏權重要小於經過星星顯示權重,因此,我使用了!important(您也可以使用其他方法提高選擇器權重),如下:

    .star:hover { background: url(star.png) repeat-x 0 -20px!important; }

    於是,星星背景固定影響hover問題理論上解決了。//zxx: IE6上面兩段CSS都不認識,因此,hover狀態需要藉助JS解決,具體參見demo源代碼。

  • 最後一個技術點,z-index設置。根據上面的分析,星星總共有3種權重狀態,因此,相應的,也存在3種層級狀態:
    1. 默認狀態的星星層級最高,以便隨時實現hover效果,demo中其z-index值爲3;

     

    2. 正在被hover的星星需要比點擊固定顯示星星層級高。衆所周知,如果z-index值相同,後面的絕對定位元素會覆蓋前面的。這種情況下,如果第3顆點擊選中,鼠標經過第2顆星星,就會出現hover死循環——星星2被星星3覆蓋→星星2進入非hover狀態(較高層級,覆蓋星星3)→觸發星星2hover態(被星星3覆蓋)→星星2進入非hover狀態)→觸發星星2hover態→……

    因此,需要設置,hover狀態z-index:2; 選中態z-index: 1. 完整示意如下:

    .star { z-index: 3; }
    .star:hover { z-index: 2; }
    :checked + .star { z-index: 1; }
  • over again!

五、看那星星多麼美麗,摘下一顆有侷限性

這裏的純CSS實現實際是CSS3技術的應用,因此,侷限就是兼容性。IE9+瀏覽器以及移動端都能不錯實現。至於IE6~IE8瀏覽器,則……

實際上,IE7,IE8等瀏覽器點擊星星,單選框也是選中的。對於這些瀏覽器,我們可能需要額外一點JS以及部分CSS的配合,實現我們需要的效果。具體實現可參見demo源代碼,低版本IE瀏覽器JS代碼直接可見。非重點,不展示。

現在的我越來越有一種感覺,或者說需求,是不是網站可以根據瀏覽器自動加載不同的JS文件呢?

比方說,IE6~IE8加載老版本jQuery,IE9+加載新jQuery。或者這裏的,IE6-8單獨加載一個處理包,或者稱爲兼容包,類似軟件兼容補丁一樣的東西。

a與label嵌套之特性
a標籤裏面嵌套label標籤,點擊後會有何反應呢?

據測試,如果label block水平,同時for關聯控件元素,a標籤打醬油;否則,會觸發a標籤的相關行爲。

demo中,爲了IE6的hover效果,labelinline水平。貌似label標籤醬油,因此,交互是通過a標籤+JS實現的。

六、就向流星許個心願,讓你知道這裏是結語

從語義上將,實際上,星星評分就是個單選框。因此,實際開發製作的時候,建議保留單選框組,增強可訪問性。因此,從這點上講,本文所展示的CSS驅動星星評分交互的方法是很有價值的。

如果只想實現簡單,5顆星星一排,共5排的背景圖片是最好的選擇。除了背景圖大一點,其他其實都還好,可以說是一個更適合大衆的實際的方法。注意,此方法也需要保留單選框組,否則僅僅一個表象實現,實則質量不高。

本文方法好處在於,純CSS驅動,省了不少JS;同時圖片背景比較小。但是,學習以及理解成本稍高,可能並不適用於所有同行,因此,標題前綴爲“折騰”二字。還有,本文方法可能在一些低端的Android pad上有些問題,不過我表示對此不屑一顧。

故事到此結束,謝謝品鑑!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章