原文: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
元素markdown
<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
的优秀,有兴趣的读者能够去看看原文,感恩~