原文:The State of CSS Reflectionscss
說明:爲方便讀者理解,本文采用意譯,非直譯;其次,原文極長,做者還給出了瀏覽器兼容方案,本譯文重點介紹
box-reflex
屬性的做用效果,不闡述兼容問題,有興趣的讀者能夠點擊原文閱讀,謝謝~html最後:翻譯不易,譯文求Star: //github.com/qiud...git
最近我在CodePen上發現了一個純CSS實現,具備漸變倒影和3D旋轉效果的柵欄動畫,他的實現方式是:利用10個<div>
元素建立10個柵條,接着再複製整份<div>
元素,並建立一個漸變遮罩造成漸變效果,以此做爲柵欄的倒影。github
這聽起來有點像用左腳的腳趾去抓你的右耳背部(譯者理解:表達的意思應該是用了複雜的方式去處理一個其實能夠用簡單方式達成的事情)!更不用說這種漸變遮罩的方式根本不適用於非單一顏色的背景。難道沒有基於CSS的更好的方法嗎? web
答案是有的,咱們有更好的方式能夠實現這種效果!但遺憾的是,這種方式的兼容性不夠好,若是咱們不想使用canvas
,但又但願可以兼容全部的主瀏覽器,上述的方法無疑仍是最好的。canvas
本文將探討今天咱們建立倒影的全部可行選擇,闡述這些「類似」的解決方案,在跨瀏覽器問題上致使的痛苦,最後就這些問題該怎麼作討論下個人想法(譯文沒這麼多內容)。瀏覽器
在討論倒影以前,咱們先看看如何建立、定位和着色柵欄條,由於這部分對全部的瀏覽器都是通用的。sass
首先咱們建立了一個.loader
包裝器幷包含10個.bar
元素ruby
<div class='loader'>
<div class='bar'></div>
<!-- 繼續建立9條 -->
</div>
複製代碼
除了直接寫HTML外,咱們也能夠用預處理器,好比Haml:app
.loader
- 10.times do .bar
複製代碼
咱們從視口的中間位置開始定位這些元素。一般咱們都是使用top: 50%
去居中,但若是咱們用bottom: 50%
後面會更方便。
div {
position: absolute;
bottom: 50%; left: 50%;
}
複製代碼
咱們給這些柵欄條定義寬度和高度,同時給它一個背景:
$bar-w: 1.25em;
$bar-h: 5 * $bar-w;
.bar {
width: $bar-w; height: $bar-h;
background: currentColor;
}
複製代碼
咱們但願柵條的底部邊緣能夠跟視口的橫向中軸線相重疊,經過前面咱們設置bottom: 50%
已經實現了這種效果。
此時,咱們全部柵條是所有堆疊在一塊兒的,他們的左邊緣與視口的縱向中軸線重合,底部邊緣則與橫向中軸線重疊,在線查看:
咱們須要將這些柵欄定位爲:第一條柵條左邊緣和最後一條柵條右邊緣與縱向中軸線之間的距離相同,這個距離老是等於條數($n
)乘以條寬($bar-w
)結果值的一半。最初的演示用的是普通的CSS
,如今咱們使用Sass
來簡化代碼量,這裏查看:
$bar-w
中間是鏈接符,不是減號,避免引發歧義,後續使用$bar_w
替代
這意味着,從全部柵條的位置開始,咱們須要把第一個柵條向左移動 0.5 * $n * $bar_w
。左邊是x
軸的負方向,這意味着前面須要加一個負號,所以第一個柵條的margin-left
值是 -.5 * $n * $bar_w
。
第二個柵條的位置則是在第一個柵條位置上往右移動一個柵條寬度的距離,那麼它的margin-left
值應該是 -.5 * $n * $bar_w + $bar_w
;
同理第三個柵條的margin-left
值爲 -.5 * $n * $bar_w + 2 * $bar_w
;
那麼最後一個柵條的margin-left
就是:-.5 * $n * $bar-w + ($n - 1) * $bar-w
.
以下圖:在線查看
$n: 10;
@for $i from 0 to $n {
.bar:nth-child(#{$i + 1}) {
margin-left: ($i - .5 * $n) * $bar-w;
}
}
複製代碼
咱們給它們設置下box-shadow
,這樣咱們能夠清楚地看到一個柵條的結束和下一個柵條的開始:
柵欄的背景顏色從最左邊的深藍色(#1e3f57
)過分到最右邊的淺藍色(#63a6c1
),這聽起來像是Sass
的mix()
函數作的事情。mix()
的第一個參數是淡藍色,第二個參數是深藍色,第三個參數(稱爲相對權重,以%爲單位)是最終混合結果中淡藍色包含的量。
對於第一個柵條,淡藍色的量應該爲 0% - 0%
,所以最終結果僅爲深藍色;
相同地,對於最後一個柵條,淡藍色的量應該爲100% -100%
,背景色的構成就是淡藍色;
對於剩下的柵條,咱們須要讓中間值均勻分佈。假設咱們有$n
個柵條,第一個是0%
,最後一個是100%
,而後咱們須要把它們分紅$n - 1
個等距間隔。以下圖:
$i
的柵條的相對權重爲:
$i * 100% / ($n - 1)
,咱們添加以下代碼:
$c: #63a6c1 #1e3f57; // 1st = light 2nd = dark
@for $i from 0 to $n {
// list of mix() arguments for current bar
$args: append($c, $i * 100% / ($n - 1));
.bar:nth-child(#{$i + 1}) {
background: mix($args...);
}
}
複製代碼
如今,這些柵欄看起來跟最初演示的同樣:在線查看
box-reflect
仍然是一個非標準屬性,許多主流瀏覽器還沒有對其進行支持,幸運的是,它能夠在webkit
瀏覽器中很好地運行,只須要加上瀏覽器的私有屬性就能夠了。
讓咱們看一下它是怎麼工做的,他的值有三部分:
-webkit-box-reflect:none | <direction> <offset>? <mask-box-image>?
複製代碼
<direction>
:倒影的方向,能夠是below
, left
, above
, right
中的任意值<offset>
:倒影與原像的距離,取值能夠是固定像素值或百分比<mask-box-image>
:設置倒影的遮罩效果,能夠是背景圖片或漸變圖像下面的交互demo闡述了這點(能夠點擊更改倒影的方向、偏移量等):
直接訪問demo自個玩吧!
在咱們的例子中,首先想到的是在.loader
中添加這個:
.loader {
-webkit-box-reflect: below 0 linear-gradient(rgba(#fff, 0), rgba(#fff, .7));
}
複製代碼
其次咱們還須要給.loader
設置尺寸,由於它包含的柵欄都是絕對定位的,此時.loader
的實際尺寸是0px X 0px
。咱們將其寬度定義爲全部柵欄寬度之和,高度則與柵欄高度一致:
$loader-w: $n * $bar-w;
.loader {
width: $loader-w; height: $bar-h;
box-shadow: 0 0 0 1px red;
}
複製代碼
添加上面的代碼後,在webkit瀏覽器中會看到下面的效果:在線查看
咱們已經能夠看到加載器的邊界和一些倒影,但它們的位置再也不正確了。咱們須要將加載器左移居中,同時讓柵欄底部與它們父元素的底部重合:
.loader { margin-left: -.5 * $loader-w; }
.bar { bottom: 0; }
複製代碼
這樣就解決了定位的問題,效果如:
// 這裏省略一堆關於Firefox的兼容方案:element()+svg的mask ......
最初在CodePen實現的動畫很是簡單,只是一個3D旋轉柵欄:
@keyframes bar {
0% {
transform: rotate(-.5turn) rotateX(-1turn);
}
75%, 100% { transform: none; }
}
複製代碼
將動畫應用在全部的柵欄上:
animation: bar 3s cubic-bezier(.81, .04, .4, .7) infinite;
複製代碼
接着爲每一個柵條添加不一樣的延時:
animation-delay: $i*50ms;
複製代碼
因爲咱們是3D旋轉柵欄,所以咱們還須要在loader
元素上添加perspective
屬性:.
.loader {
perspective: 62.5em;
}
複製代碼
但這隻在webkit
瀏覽器中使用-webkit-box-reflect
時有效。最終實現的效果:在線查看
算了,這段不用翻譯了!
大意講做者對-webkit-box-reflect
和element()+mask
(svg
的mask
標籤)解決跨瀏覽器實現倒影問題上的見解,不影響咱們理解box-reflect
的優秀,有興趣的讀者能夠去看看原文,感恩~