by zhangxinxu from http://www.zhangxinxu.com
本文地址:http://www.zhangxinxu.com/wordpress/?p=3568
一、星星點燈,照亮我的家門
大家都喜歡聽故事。
每篇文章也都是有故事的。
今天的故事是與星星相關的。
沒錯,講的是星星點燈的故事——
纔怪!
標題只是我腦子突然蹦出來的,唉,這首老到掉渣子的歌我居然條件反射般想起,可見——我老了!
故事其實是這樣的~~
在天氣還未如此炎熱的某天,@waylybaye微博上展示了其使用canvas
繪製星星圖片,然後再保存爲png
格式使用的折騰:
很贊,對不對!
然,故事剛剛開始,
而後我隨便吐槽了句:
這種效果兩個星星就可以完全CSS實現了,包括IE6瀏覽器,多少多餘勞動力浪費了啊~~
一石激起三層浪:
有人對兩顆星星實現星星評分效果感興趣;有人覺得純CSS搞不定記住之前用戶所選星星。
實際上,兩顆星星(見下圖)完全可以實現兼容IE6在內的效果;而且,純CSS可是可以記住當前星星點擊個數哦!
哈哈,我們的故事就此展開……
二、小星星,亮晶晶,點點像你的眼睛
正片之前先來個精彩預告,您可以狠狠地點擊這裏:兩顆星星實現的星星點擊評分效果demo
哈哈,這回不上截圖了,上截視頻,更直觀,截自Chrome瀏覽器,純CSS實現。對了,貌似忘記把《愛情公寓》電視關掉,有雜音,嘻嘻……
iPad黨若看不到上視頻,可以點擊下面區域查看截圖:
您可能會驚訝地發現,誒,怎麼點擊的星星可以記住啊,純CSS?鑫哥你確定不是在忽悠?
我不姓趙哦~
慢慢來,先看看兩個星星如何實現兼容IE6瀏覽器的hover交互效果。
三、一閃一閃亮晶晶 滿天都是小星星
兩個星星實現原理見下圖:
- 背景色就是灰色平鋪;
- 5個小標籤,分別對應每個星星,寬度
1/5
,其垂直層次關係見圖1
示意; - 當鼠標經過某星星,例如上圖所示第3個,寬度延伸,背景顯示,
hover
效果即呈現; - 最後,仔細觀察其他小星星的層次以及位置,不存在覆蓋的情況,於是,
hover
其他小星星,效果同樣存在; - 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
僞類選擇器以及兄弟選擇器實現我們想要的交互效果——例如,元素的顯示與隱藏,或者是選中的星星個數標記。
有些迷糊?不急,來個最簡單示例,跟我一步一步來:
- 一個單選框,以及一個對應的
label
標籤,如下:<input type="radio" id="testRadio"><label for="testRadio">觀光團</label>
- 點擊含“觀光團”字樣的
label
標籤,只要不是奇葩設備,單選框都會被選中的(因爲for
值等於單選框id
值); - 於是,觸發瞭如下僞類:
input:checked {}
- CSS3中還有兄弟選擇器,如
~
以及相鄰兄弟選擇器+
,於是,我們可以改變label
標籤的狀態,例如,文字變紅:input:checked + label { color: red; }
- 如果我們把
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第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
效果,label
是inline
水平。貌似label
標籤醬油,因此,交互是通過a
標籤+JS實現的。
六、就向流星許個心願,讓你知道這裏是結語
從語義上將,實際上,星星評分就是個單選框。因此,實際開發製作的時候,建議保留單選框組,增強可訪問性。因此,從這點上講,本文所展示的CSS驅動星星評分交互的方法是很有價值的。
如果只想實現簡單,5顆星星一排,共5排的背景圖片是最好的選擇。除了背景圖大一點,其他其實都還好,可以說是一個更適合大衆的實際的方法。注意,此方法也需要保留單選框組,否則僅僅一個表象實現,實則質量不高。
本文方法好處在於,純CSS驅動,省了不少JS;同時圖片背景比較小。但是,學習以及理解成本稍高,可能並不適用於所有同行,因此,標題前綴爲“折騰”二字。還有,本文方法可能在一些低端的Android pad上有些問題,不過我表示對此不屑一顧。
故事到此結束,謝謝品鑑!