CSS3 box-shadow兼容loading效果兼IE10+ CSS Hack介紹

一、稱爲引言的部分

週一的時候,見到條轉發較多的微博,是個頁面鏈接,頁面中有4個充分發揮CSS3 box-shadow潛力實現精湛的效果。

有4個demo4種效果哦!

比方說第三個的彩色轉啊轉的loading效果:
網上炫酷的加載中效果

是不是帥得掉渣啊!

然而這種效果的實現就像是在大街上耍猴,圍觀人挺多,喝彩聲也不少,但是,看完了,大家各回各家、各找各媽了!

好比上面那個炫炫的酷酷的轉轉加載效果,全部CSS實現的啊,好讚的來!然而,僅少部分瀏覽器支持,實際項目中壓根用不了,至少在PC上如此,純屬華而不實的東西。於是,看完了,過癮了,頁面關掉後,就直接goodbye了,估計這輩子不會再過來了。

難道就沒有簡單實用的效果嗎,最好可以向下兼容的,然後實際項目也能實用的?

有!本文就將展示如何完美向下兼容實現loading效果的,順便分享下我自己想出來的一個給IE10+瀏覽器做Hack的方法。

二、效果實現的主演們

對於IE10+瀏覽器,FireFox, Chrome, Opera瀏覽器(如無特殊說明,均值最近版本)使用CSS3 box-shadow+animation實現loading效果,而IE6-IE9瀏覽器還是老方法,使用gif loading效果的圖片,如下這個(32X32):
加載中的gif動畫圖片

我是根據IE10下CSS生成效果基礎上製作的(Photoshop製作,如何製作可參考“gif動畫圖片製作”這篇前作),PSD源文件可右鍵這裏下載。

簡潔的HTML,不違和的CSS,成就我們在新技術上的嘗試。

三、CSS3實現之box-shadow繪製

下圖是我們想要的效果(FireFox瀏覽器中放大後的截圖):
放大後的效果圖

8個點,有3個大小有規律變大,這樣旋轉的時候就有方向感和真實性。

8個點實際對應於box-shadow的8個投影,圖片大小標準32px*32px,考慮到點的八卦佈局以及大小限制,因此,我們的容器本身只有3px*3px,於是,有如下的實現代碼:

.loading {
    width: 3px; height:3px;
    border-radius: 100%;                      /* 圓角 */
    box-shadow: 0 -10px 0 1px #333,           /* 上, 1px 擴展 */
                10px 0px #333,                /* 右 */    
                0 10px #333,                  /* 下 */
                -10px 0 #333,                 /* 左 */
                              
                -7px -7px 0 .5px #333,        /* 左上, 0.5px擴展 */
                7px -7px 0 1.5px #333,        /* 右上, 1.5px擴展 */                    
                7px 7px #333,                 /* 右下 */
                -7px 7px #333;                /* 左下 */
}

如果您的瀏覽器IE9+或Chrome一夥,同時不是在RSS中閱讀本文,就會看到上面代碼的效果,就是下面這個靜止狀態的loading圈圈效果:

CSS3 box-shadow有四個值,分別表示“右偏移、下偏移、模糊大小、擴展大小”。因此,那3個稍大的圈圈就是利用了第4個參數——“擴展”來實現的。分別擴展0.5px, 1px以及1.5px.

以上就是CSS3 box-shadow的繪製,相比一開始的炫炫的彩色效果,這個要通俗易懂的多,大家都能輕鬆把玩實現的效果,只要定好位置,一切都很簡單。


CSS3 box-shadow有四個值,分別表示“右偏移、下偏移、模糊大小、擴展大小”。因此,那3個稍大的圈圈就是利用了第4個參數——“擴展”來實現的。分別擴展0.5px, 1px以及1.5px.

以上就是CSS3 box-shadow的繪製,相比一開始的炫炫的彩色效果,這個要通俗易懂的多,大家都能輕鬆把玩實現的效果,只要定好位置,一切都很簡單。

四、CSS3實現之animation與無限旋轉

一般開源的移動框架中,無限旋轉的CSS都是使用spin作爲類名以及動畫關鍵字的,大家可以約定俗成的使用,無形中有利於前端大環境的建設。

CSS代碼如下,目前在PC上,FireFox/IE10/Opera瀏覽器中animation動畫都已經不需要私有前綴了(如果您不放心,可以自己加上),於是,如下CSS3代碼:

.spin {
    -webkit-transform: rotate(360deg);
    -webkit-animation: spin 1s linear infinite; 
}
@-webkit-keyframes spin {
    from {-webkit-transform: rotate(0deg);}
      to {-webkit-transform: rotate(360deg);}
}
.spin {
    transform: rotate(360deg);
    animation: spin 1s linear infinite;
}
@keyframes spin {
    from {transform: rotate(0deg);}
      to {transform: rotate(360deg);}
}

跟上面box-shadow生成的靜態點點效果結合,如下,就有(如果你沒有效果,請檢查瀏覽器或點擊這裏查看原文):

HTML代碼爲:

<div class="loading spin"></div>

五、高不成低不就的IE9瀏覽器

IE9瀏覽器支持CSS3 box-shadow,但是不支持CSS3 animation. 於是,IE9瀏覽器下,雖有CSS生成的點點效果,但是卻無法持續旋轉。因此,考慮到兼容性,我們需要把IE9瀏覽器跟IE6-IE8歸到一起去,sorry啦,誰讓你不自動升級的

於是,我們現在的處理就是:IE6~9使用圖片(代碼如下),IE10+以及其他現代瀏覽器使用CSS3生成,如何無縫拼接?

.loading {
    width: 32px; height: 32px;
    background: url(loading-css3.gif);
}

六、IE10+瀏覽器的處理

平時處理類似漸進增強功能都是IE6-IE8是一夥,IE9+及其他瀏覽器是一夥,我都是使用:root ie9_other{}實現,簡單易懂,屢試不爽,但是,IE10+還是頭一次遇到,怎麼破?

網上有這麼個Hack,說是針對IE10瀏覽器的:

@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) { 
   /* IE10的樣式... */
}

先不說適不適用這裏的需求,單純從代碼量以及記憶難度上將,個人是畏懼了。敢問各位,上面的Hack選擇器你可以一遍就記住嗎?

因此,需要另尋它法,IE10較新,相關知識較少,那就自己動腦子想,一個小小兼容處理,有何難的!

思路
關鍵是要尋找IE9不支持,IE10支持的相關CSS樣式或選擇器,下面就是一些:

  • :valid/:invalid IE9不支持,IE10以及其他瀏覽器支持
  • :required/:optional IE9不支持,IE10以及其他瀏覽器支持
  • ::before/::after IE9不支持(IE10↘IE9支持),IE10以及其他瀏覽器支持
  • CSS Animations IE9不支持,IE10以及其他瀏覽器支持
  • CSS Gradients IE9不支持,IE10以及其他瀏覽器支持

等……

本文兼容難點就是因爲IE9不支持animation,理論上,我們是可以藉助animation本身實現IE9的向下兼容的,如何處理?在spin動畫的formto設置background:none,以及放上box-shadow相關的CSS!類似:

@keyframes spin {
    from {transform: rotate(0deg); background:none; box-shaodw: ...}
      to {transform: rotate(360deg); background:none; box-shaodw: ...}
}

然而,這種處理有兩大問題:
1. 破壞了spin的重用性;
2. 代碼冗餘;

因此,不考慮。

於是,我們可以從:valid/:invalid, :required/:optional, ::before/::after以及CSS Gradients中尋找突破。

1. :valid/:invalid僞類實現

:valid/:invalid僞類是針對表單元素的,合法還是不合法。相關tips如下:

  • 適用於單複選框、單行多行文本框、下拉框等;
  • button類型按鈕所有忽略;
  • submit類型按鈕目前Firefox 21不支持,IE10,Opera,Chrome均支持;
  • 表單元素如果設置了disabledreadonly,僞類忽略;

綜上所述,如果我們忽略FireFox瀏覽器,則可以藉助submit類型按鈕實現我們想要的效果,HTML爲:

<input type="submit" class="loading spin" hidefocus="true" />

於是,配合結構如下的CSS我們就可以得到我們想要的效果了:

/* IE6-IE9, FireFox實現 */
.loading {
    width: 32px; height: 32px;
    background: url(loading-css3.gif);
    /* 按鈕樣式重置 */
    margin: 0; padding: 0; border: 0; outline: none;
    pointer-events: none;
}
/* IE10+, Chrome, Opera */
.loading:valid {
    background: none;
    width: 3px; height:3px;
    border-radius: 100%; 
    box-shadow: ...
}

沒有照顧到CSS支持,且用戶比例也頗高的FireFox瀏覽器,顯然不是最優方法。有人可能會提議使用單行input框或多行textarea域實現。理論上,這是可行的,但是,由於單行或多行文本框在focus的時候有光標,因此,在實現的時候要多些處理,HTML的和CSS部分都有,如下紅色代碼:

<input class="loading spin" onfocus="this.blur();" hidefocus="true">
.loading {
    width: 32px; height: 32px;
    background: url(loading-css3.gif);
    /* 下面所有樣式均爲input框樣式重置,去光標 */
    margin: 0; padding: 0; border: 0; outline: none;
    line-height: 0; font-size: 0; text-indent:-1px;    
    cursor: default;
    pointer-events: none;
}

以上實現算是相當兼容的,您可以狠狠地點擊這裏:input+:valid僞類兼容loading效果demo

2. :required/:optional僞類實現

:required/:optional僞類表示表單元素是選填呢還是必填,相關tips如下:

  • 適用於單複選框、單行多行文本框、下拉框等;
  • input標籤下,無論是button類型按鈕還是submit類型按鈕,Opera瀏覽器都忽略之;其他瀏覽器均可識別;
  • button標籤下,無論是button類型按鈕還是submit類型按鈕,僅Chrome瀏覽器識別,其他瀏覽器均忽略
  • 控件disabled後依然可識別;

相比:valid/:invalid僞類,雖然都有一種瀏覽器對按鈕的支持有問題,但是,:required/:optional僞類卻沒有disabled失效的問題。因此,我們就沒有了所謂焦點獲取、文本輸入、光標閃爍等文本框問題都可以通過添加disabled避免。

因此,如下HTML與CSS代碼就可以實現比較健壯的loading效果啦!

<input class="loading spin" disabled>
/* IE6-IE9實現 */
.loading {
    width: 32px; height: 32px;
    background: url(loading-css3.gif);
    /* input框樣式重置 */
    margin: 0; padding: 0; border: 0;
}
/* IE10+以及其他或騷或帥之流 */
.loading:optional {
    background: none;
    width: 3px; height:3px;
    border-radius: 100%;
    box-shadow: ...
}

您可以狠狠地點擊這裏:\:optional僞類下漸進增強loading動畫demo

IE9以及IE10瀏覽器下的demo效果截圖如下:
IE9下效果截圖 張鑫旭-鑫空間-鑫生活IE10下效果截圖 張鑫旭-鑫空間-鑫生活

從上面截圖,我們似乎發現了一個問題——尺寸!

很好理解,IE6~IE9瀏覽器實際尺寸32px*32px, 而IE10+等瀏覽器實際尺寸3px*3px,差別明顯,如何破?

  1. 如果元素在固定容器中,且水平垂直居中佈局,無需破,效果一樣;
  2. 如果元素固定定位,absolute化,同時.loading中的margin:0改成margin:-14.5px 0 0 -14.5px即可位置兼容;
  3. 自己看着辦微調等;

難道沒有尺寸也完全一樣的方法嗎?有!下面的僞元素就可以彌補。

3. ::before/::after僞元素登場

::before/::after僞元素就是:before/:after的進階版,IE8以及原生IE9支持後者,卻不認識前者。

上面提到了單標籤實現尺寸不一的問題,我們是不是可能這樣處理,CSS3 box-shadow生成的loading效果利用僞元素生成,這樣,就可以保證外部容器寬度一致了!但,::before/::after僞元素對於表單元素而言,幾乎就是剋星,因爲表單元素都是大多都是單標籤,即使偶爾冒出個textarea也是醬油,button由於兼容性問題,這裏實際上也無法大展拳腳。

怎麼破?

循序漸進,先使用最普通的div標籤,看下面的代碼:

<div class="loading spin"></div>

普通的div誒~

/* 所有瀏覽器實現 */
.loading {
    width: 32px; height: 32px;
    background: url(loading-css3.gif);
}
/* IE10+以及其他 */
.loading::after {
    content: '';
    width: 3px; height: 3px;
    margin: 14.5px 0 0 14.5px;
    border-radius: 100%;
    box-shadow: ... ;
    position: absolute;    /* 可缺省 */
}

上面代碼實現有什麼問題呢?——雖然尺寸一致了,但IE10+以及其他現代瀏覽器::after僞元素生成的轉轉轉與背景圖片轉轉轉重複了,如下截圖效果:
僞元素生成與背景圖片重合 張鑫旭-鑫空間-鑫生活

有demo,點擊這裏查看:僞元素與原背景搞基demo

於是,我們如果能夠讓IE10+瀏覽器無背景,IE10+瀏覽器使用::after僞元素就可以了,關鍵咋整呢?

4. 元素Hack與兄弟選擇器

CSS中有個兄弟選擇器~, 在“CSS radio/checkbox單複選框元素顯隱技術”一文中有展示,您可以觀摩觀摩。以及還有相鄰兄弟選擇器+

同樣的,既然,如:valid+input可以判斷是IE10+瀏覽器,那我們也可以使用:valid+input + ~判斷其兄弟元素也是IE10+瀏覽器,比方說下面的HTML代碼:

<input class="hack">
<div class="loading spin"></div>

於是乎:

.hack:valid ~ .loading { /* IE10+瀏覽器 */ }

發現沒有,顛覆性的:CSS Hack不是CSS代碼,而是HTML元素!

於是,結合上面的::after::before僞元素生成,我們就可以得到我們等尺寸且完美漸進增強的效果了!

如下CSS:

/* 隱藏Hack元素 */
.hack { position: absolute; visibility: hidden; }

.loading {
    width: 32px; height: 32px;
    background: url(loading-css3.gif);
}
/* IE10+/FireFox/Chrome/Opera */
.hack:valid ~ .loading {
    background: none;
}
.hack:valid ~ .loading::before {
    content: '';
    width: 3px; height:3px;
    margin-left: 14.5px; margin-top: 14.5px;  /* 居中顯示 */
    border-radius: 100%;                      
    box-shadow: ...;
    position: absolute;
}

您可以狠狠地點擊這裏:CSS3利用Hack元素實現兼容loading效果demo

看看現在FireFox下的尺寸以及效果:
Hack元素處理後的效果截圖

需要說明的
這裏demo中,起Hack作用的文本框和loading元素放在了一起,我們在項目中實際使用的時候,是不能這樣子的。你想啊,你的每一個loading效果旁邊都跟着個隱藏的文本框元素,豈不是很傻很天真。

實際使用的時候,這個隱藏的Hack文本框顯然是要放在很高的父級的,由於無法與body平起平坐,因此,個人建議直接放在body標籤之下(下一節要具體展示),然後,類似:

.hack:valid ~ div .loading { /* div僅示意,實際特定類名等 */ }

整個頁面只需要一個IE10+判斷的HTML Hack元素,你的loading效果可以自由使用。

5. CSS3 gradient的近乎完美處理

本段來自結尾,

由於IE9及其以下瀏覽器不認識CSS3 背景漸變。因此,對於IE10+我們需要重置掉的background: url(loading-css3.gif)就可以巧妙使用透明漸變背景實現。相關代碼如下:

.loading {
    width: 32px; height: 32px;
    background: url(loading-css3.gif);
    /* IE10+ 去背景 */
    background:-webkit-gradient(linear, 0 0, 0 100%, from(rgba(0,0,0,0)), to(rgba(0,0,0,0)));
    background:-moz-linear-gradient(top, rgba(0,0,0,0), rgba(0,0,0,0));
    background:-ms-linear-gradient(top, rgba(0,0,0,0), rgba(0,0,0,0));
    background:-o-linear-gradient(top, rgba(0,0,0,0), rgba(0,0,0,0));
    background:linear-gradient(top, rgba(0,0,0,0), rgba(0,0,0,0));
}

於是,由於IE10+才認識::before/::after,於是,再配合上面介紹的僞元素生成旋轉動畫,頁面單標籤,沒有hack元素,同時尺寸所有瀏覽器統一,簡直屌爆了!!

您可以狠狠地點擊這裏:CSS3 background gradient漸變與兼容loading效果demo

background漸變背景remove圖片背景的處理 IE9效果

這裏之所以說“近乎完美”,是因爲IE10瀏覽器向下自帶IE9瀏覽器是認識::before/::after僞元素的,因此,會有重複背景,不過,這種情況我覺得可以忽略,你覺得呢?

七、IE10+ CSS Hack介紹

如果你上面看得還算認真,就應該知道我要講的是什麼了。

如何寫IE10+瀏覽器的hack呢?如下處理:

  1. body標籤下放入hack元素,如下截圖所示:
    Hack元素放在body標籤之下
  2. 比方說,我們的需要處理的元素全部都在#main的容器內,於是,IE10+的CSS Hack就是:
    .hack:valid ~ #main .ie10_other { }

    或者是:

    .hack:valid + #main .ie10_other { }

    差別在於,前者#main只要在Hack元素之後,後者需要是相鄰的兄弟,同時#main在Hack元素之後!

  3. over!

千言萬語不如一個demo來的實在,您可以狠狠地點擊這裏:IE10+瀏覽器hack測試兼本文loading效果使用測試demo

核心CSS爲:

.hack:valid ~ #main .loading { /* 啪啪啪 */ }

頁面效果如下(下圖爲IE10下):
loading中的效果 張鑫旭-鑫空間-鑫生活

這是IE6下的:
IE6下的loading效果截圖 張鑫旭-鑫空間-鑫生活

有人可能要說了,我只需要IE10瀏覽器的Hack,而不是IE10+和其他瀏覽器的Hack。這很簡單嘛:\0\9不是IE10喜歡的零食嘛,在後面加上這個就好了,例如:

.hack:valid ~ #main .ie10 { color: green\0; }

補充,以上IE10 hack如果不滿意,您可以試試這個:_::-ms-reveal, .selector {}

八、其他一些小tip

  1. 僞類:read-only/:read-write也是IE9不支持,IE10+以及其他瀏覽器都支持。但是,目前,FireFox瀏覽器下,需要私有前綴才能使用,即:-moz-read-only/:-moz-read-write. 同時,需要注意的是,火狐的私有僞類必須與其他瀏覽器僞類分開寫,否則無效,什麼意思呢?看下面代碼:
    <input class="test1" readonly="readonly" />
    <input class="test2" readonly="readonly" />
    .test1:read-only{background-color:#eee;}
    .test1:-moz-read-only{background-color:#eee;}
    .test2:read-only, .test2:-moz-read-only{background-color:#eee;}

    .test1所在文本框在所有IE10+及其他瀏覽器中是有#eee背景色的,而.test2所在的文本框在任何瀏覽器下都沒有效果。

    正是由於這個不能逗號並列書寫,因此,上面並沒有把:read-only放在實現方法的隊列中——雖然理論上很好用的。

    您可以狠狠地點擊這裏::read-only僞類與逗號分隔符恩怨demo

    read-only與moz前綴公用失效問題截圖

  2. 僞類中有個稱之爲:empty的僞類,內容爲空起作用,蠻有用的。有個疑問?如果我們使用::before/::after進行內容生成,那:empty僞類還起作用嗎?

    如下測試HTML以及CSS:

    <div class="empty"></div>
    .empty {
        width: 32px; height: 32px;
        background: url(loading-css3.gif);
    }
    .empty::before { content: ' '; display: block; }
    .empty:empty {
        background-color: #eee;
    }

    結果如下:
    內容生成與:empty僞類關係測試結果 張鑫旭-鑫空間-鑫生活

    表明,內容生成不會影響:empty僞類,換句話說就是,::before/::after不會影響:empty僞類的作用。

    您可以狠狠地點擊這裏:CSS3 content內容生成與empty僞類demo

九、稱爲結語的部分

基本上都是這周研究整理出來的東西,可能有遺漏,可能有更好的方法,例如,可以利用CSS3背景漸變打補丁,remove掉IE10+瀏覽器的背景圖片,這個自己還沒來得及研究。有個同事回家結婚去了,最近活有點多,沒有再多時間了。

擦,還是沒忍住,有花了些時間折騰了CSS Gradients下的處理,在結尾處嘮叨不太好,還是放到上面去吧~~

如果您發現本文有表述不準確的地方,歡迎大力指正。如果您有什麼其他的想法,歡迎交流。或評論,或郵件都可以!

感謝閱讀,希望本文的內容對你我的工作和學習有所幫助。


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