關於 CSS 反射倒影的研究思考

原文:The State of CSS Reflectionscss

譯者:nzbinhtml

友情提示:因爲演示 demo 的兼容性,推薦火狐瀏覽。該文章篇幅較長,內容龐雜,有必定難度。而我本人學識有限,加之時間倉促,所翻譯內容可能有不恰當及晦澀之處。歡迎你們拍磚指正。web

我最近在 codePen 上看到了這個 加載程序,一個純 CSS 製做的帶有漸變反射的 3D 旋轉豎條。它的製做方法是:爲每一個豎條建立一個元素,而後經過複製每個元素來製做反射倒影,最後在反射倒影上添加漸變背景來製做漸隱的效果。聽上去有點複雜,並且建立漸隱效果的漸變背景在非純色背景下是無效的。有沒有更好的 CSS 方法呢?canvas

答案是‘確定’的,也是‘否認’的。‘確定’是由於確實有能夠作的方法,‘否認’是由於有些方法還不存在。使人遺憾的是,這些代碼只能用預處理器(主要經過循環來實現壓縮功能)壓縮一點點。若是咱們不想使用 canvas 而且想兼容主流瀏覽器的當前版本,複製豎條來製做倒影以及經過漸變背景來製做漸隱效果的方法仍然是最好的。瀏覽器

這篇文章主要探索現有的製做反射倒影的方法、舉例說明可能的解決方案、跨瀏覽器問題以及個人一些想法。sass

基本設置

建立豎條元素

首先建立一個 .loader 元素以及在其中建立10個 .bar 元素安全

HTML
<div class='loader'>
  <div class='bar'></div>
  <!-- repeat to create 9 more bars -->
</div>

把一樣的事情寫不少遍是一件痛苦的事,因此在該狀況下使用一個預處理器會變得很簡單。咱們在這裏使用 Haml 模板,固然也有人會選擇其餘的模板。app

Haml
.loader
  - 10.times do
  .bar

 經過絕對定位把全部元素放到視圖的中間。大多數狀況下,咱們會使用 top: 50% ,可是如今,使用 bottom: 50% 會使後面的操做更簡單。svg

CSS
div {
  position: absolute;
  bottom: 50%; left: 50%;
}

給豎條設置 width 和 height ,爲了能看到它再設置一個 background函數

SCSS
$bar-w: 1.25em;
$bar-h: 5 * $bar-w;

.bar {
  width: $bar-w; 
height
: $bar-h; background: currentColor; }

咱們但願豎條的底部貼合視圖的水平中心線。設置 bottom: 50% 已經能夠了。

如今全部的豎條都重合在一塊兒,它們的左邊貼在垂直中心線上,底部貼在水平中心線上。

See the Pen bar loader 1.1 creating the bars by Ana Tudor (@thebabydino) on CodePen.

定位豎條

咱們須要讓最左邊的豎條和最右邊的豎條到垂直中心線的距離相等。這個距離就是豎條數量( $n )的一半乘以豎條的 width( $bar-w )。原始 demo 用的是普通的 CSS,咱們會使用 Sass 來減小代碼量。

See the Pen initial (stacked) vs. final (distributed) by Ana Tudor (@thebabydino) on CodePen.

這意味着,從豎條的起始位置開始,咱們須要將第一個豎條向左移動 5 * $n * $bar-w 。左側是 x 軸的負方向,須要在前面加 - 號。因此第一個豎條的 margin-left 就是 -.5 * $n * $bar-w

第二個豎條(以 0 爲基數,索引值是 1)就是向右(x 軸的正方向)移動 1 個豎條的寬度($bar-w)。因此第二個豎條的 margin-left 就是 -.5 * $n * $bar-w + $bar-w

第三個豎條(以 0 爲基數,索引值是 2)就是向右(x 軸的正方向)移動 2 個豎條的寬度。因此第三個豎條的 margin-left 就是 -.5 * $n * $bar-w + 2 * $bar-w

最後一個(以 0 爲基數,索引值是 $n - 1)就是向右(x軸的正方向)移動 $n - 1 個豎條的寬度。因此最後一個豎條 margin-left 就是 -.5 * $n * $bar-w + ($n - 1) * $bar-w

See the Pen bar distribution by Ana Tudor (@thebabydino) on CodePen.

一般狀況下,若是咱們認爲當前豎條的索引值是 $i (以 0 爲基數),那麼 $i 豎條的 margin-left 就是 -.5 * $n * $bar-w + $i * $bar-w ,能夠簡化爲 ($i - .5 * $n) * $bar-w

這就容許咱們使用 Sass 的循環來定位豎條。

SCSS
$n: 10;

@for $i from 0 to $n {
  .bar:nth-child(#{$i + 1}) {
  margin-left: ($i - .5 * $n) * $bar-w;
  }
}

 爲了看清楚豎條的邊界,咱們給它一個 box-shadow

See the Pen bar loader 1.2 positioning the bars by Ana Tudor (@thebabydino) on CodePen.

給豎條添加漸變

豎條的背景色是從最左邊的深藍色( #1e3f57 )過渡到最右邊的淺藍色( #63a6c1 )。這聽上去很像 the Sass mix() function 所作的。第一個參數是淺藍色,第二個參數是深藍色,第三個參數(稱做相對權重)表示將多少( % 表示)淺藍色混合進去。

對於第一個豎條,這個數量就是 0% ( 0% 數量的淺藍色),混合結果就是深藍色。

對於最後一個豎條,這個數量是 100%( 100% 數量的淺藍色,也就是 0% 數量的深藍色),獲得的背景色就是淺藍色。

對於剩下的豎條,咱們須要平均分佈的中間值。若是咱們有 $n 個豎條,第一個豎條在 0% 的位置,最後一個豎條在 100% 的位置,那麼咱們須要在二者之間平分紅 $n - 1 個區間。

See the Pen distribute n points on 100% interval (interactive) by Ana Tudor (@thebabydino) on CodePen.

通常來講,索引值爲 $i 的豎條的相對權重是 $i * 100% / ($n - 1),這意味着咱們要添加以下代碼:

SCSS
$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...);
  }
}

如今這些豎條看起來就和原始 demo 的同樣了:

See the Pen bar loader #1.3 shading the bars by Ana Tudor (@thebabydino) on CodePen.

探索反射的方案

WebKit瀏覽器:-webkit-box-reflect

很遺憾,這不是一個標準屬性!我不知道爲何這個屬性沒有標準化。這一屬性首次出如今Safari瀏覽器上時,我還不知道 CSS。 可是對於 WebKit 內核的瀏覽器,這是一個很是好的實現方法。它作了不少工做。它的使用很簡單,即便在不支持該屬性的瀏覽器上,除了不顯示反射之外,並無什麼其餘影響。

讓咱們看看它是怎麼工做的,它須要三個參數值:

  • 方向:包含 belowleft , above , right
  • offset 偏移值(可選):指定反射的開始位置到元素的底邊的距離(這是一個 CSS 長度值)。
  • 圖片遮罩 mask(可選):能夠是 CSS 漸變值。

See the Pen how `-webkit-box-reflect` works by Ana Tudor (@thebabydino) on CodePen.

注意linear-gradient() 能夠有更多的顏色斷點,也能夠用 radial-gradient() 替換。

在咱們的 demo 中,我首先想到的就是給 .loader 元素添加這一屬性。

SCSS
.loader {
  -webkit-box-reflect: below 0 linear-gradient(rgba(#fff), rgba(#fff, .7));
}

可是在 WebKit 瀏覽器中測試時,咱們並無看到反射。

See the Pen bar loader 2.1.1 -webkit-box-reflect by Ana Tudor (@thebabydino) on CodePen.

這裏發生了什麼?咱們給全部的元素設置了絕對定位,可是並無設置 .loader 元素的尺寸。因此這是一個寬高都爲 0 的元素。

讓咱們給這個元素一個明確的尺寸,高度 height 等於豎條的高度 $bar-h ,寬度等於全部豎條的 width 之和 $n * $bar-w 。爲了看清元素的邊界,咱們暫時給它一個 box-shadow

SCSS
$loader-w: $n * $bar-w;

.loader {
  width: $loader-w; height: $bar-h;
  box-shadow: 0 0 0 1px red;
}

我之因此用 box-shadow 而不用 box-shadow 是由於若是子元素溢出父元素,在不一樣的瀏覽器上使用 outline 突出物體的效果是不同的。

outline屬性在WebKit瀏覽器中的對比。Edge(上)vs. Firefox(下)

 

添加以上代碼後的結果能夠在 WebKit 瀏覽器中看到以下效果:

See the Pen bar loader 2.1.2 explicitly sizing the loader by Ana Tudor (@thebabydino) on CodePen.

若是你用的不是 WebKit 瀏覽器,看下面的圖片,就是這個樣子:

如今咱們能夠看到 loader 元素的邊界和倒影,可是位置不正確。咱們但願 loader 元素在水平中間的位置,因此把它向左移動 width 的一半。咱們也但願子元素的底部與父元素的底部貼合,因此設置子元素 bottom: 0

SCSS
.loader { margin-left: -.5 * $loader-w; }

.bar { bottom: 0; }

修正位置以後的樣子以下:

See the Pen bar loader 2.1.3 tweaking loader and bar positions by Ana Tudor (@thebabydino) on CodePen.

火狐瀏覽器 element() + mask

element() 製做反射

element() 函數(如今仍然有效,必須在火狐瀏覽器中使用而且添加 -moz- 前綴)給咱們提供了一個像真實圖片同樣能夠任意使用的圖像值。它須要一個參數值,就是咱們但願以 background 仍是 border-image 顯示的被選元素的 id 。這容許咱們作不少事情,好比使用能夠控制的圖片做爲背景 。咱們也能夠在 Firefox 中製做一個反射元素。

須要着重瞭解的一點就是 element() 函數不是遞歸函數,咱們不能建立使用元素做爲自身背景的圖像。這在建立反射的loader元素的僞類上使用是安全的,所以咱們不用建立額外的元素。

好吧,讓咱們看看如何操做。首先給 loader 元素一個 id 。轉到樣式表,咱們從適用於 WebKit 瀏覽器的CSS着手。在 loader 元素上添加一個 ::after 僞類

CSS
.loader::after {
  position: absolute;
  top: 0; right: 0; bottom: 0; left: 0;
  box-shadow: 0 0 0 2px currentColor;
  color: crimson;
  content: 'REFLECTION';
}

爲了在最終效果中看清僞類的邊界和方向,咱們設置了一些暫時性的樣式,咱們想讓它是顛倒的。

See the Pen bar loader 2.2.1 adding a pseudo by Ana Tudor (@thebabydino) on CodePen.

如今咱們須要以底邊爲基準把 ::after 僞類鏡像過來。爲了作到這一點,使用 scaleY() 屬性而且選擇合適的 transform-origin

如下的可交互 demo 說明了包含多個縮放因子以及變換中心的定向縮放是如何工做的:

See the Pen how CSS scaling w.r.t. various origins works by Ana Tudor (@thebabydino) on CodePen.

注意:縮放因子的數值和變換中心能夠超出 demo 中規定的限制。

在演示 demo 中,須要 scaleY(-1) 而且 transform-origin 在 ::after 僞類的底邊上。

使用scaleY(-1)和一個合適的 transform-origin 來鏡像元素

 

咱們把這些設置添加到代碼中,而且用 element() 函數把 ::after 僞類的背景設置爲 #loader

CSS
.loader::after {
  transform-origin: 0 100%;
  transform: scaleY(-1);
  background: -moz-element(#loader);
}

注意:因爲特別的緣由咱們使用 .loaderr 做爲選擇器而且因爲 element() 函數參數的須要咱們設置它的 id 爲 #loader

添加以上代碼後的效果以下所示(只在 Firefox 瀏覽器中有效)

See the Pen bar loader 2.2.2 -moz-element() for reflecting pseudo by Ana Tudor (@thebabydino) on CodePen.

對於使用其餘瀏覽器閱讀這篇文章的朋友,如下是截圖

在Firefox中使用 element() 製做的反射效果

 

用 mask 製做漸變

咱們使用和 WebKit 狀況下同樣的方法給反射添加漸變。在 WebKit 的狀況下,遮罩是 -webkit-box-reflect 屬性的一部分。而如今,咱們討論 CSS 的 mask 屬性,它須要引用 SVG 做爲值。

CSS
mask: url(#fader);

 #fader 元素是一個包含長方形的SVG mask 元素。

SVG
<svg>
  <mask id='fader' maskContentUnits='objectBoundingBox'>
    <rect width='1' height='1'/>
  </mask>
</svg>

咱們能夠用 Haml 模板壓縮一下

Haml
%svg
  %mask#fader(maskContentUnits='objectBoundingBox')
    %rect(width='1' height='1')

可是,若是咱們加上以上代碼,咱們的反射倒影消失了,在 Firefox 中查看以下 demo

See the Pen bar loader 2.2.3 adding a SVG mask by Ana Tudor (@thebabydino) on CodePen.

這是由於,默認狀況下,SVG 圖形會有一個純黑色的 fill ,徹底不透明,可是,咱們的 遮罩 默認是有透明度的。所以爲了實現反射漸變的效果咱們須要給長方形一個 fill (需引入 SVG linearGradient

Haml
%rect(width='1' height='1' fill='url(#grad)')

一個 SVG linearGradient 由定義的兩個點 x1 , y1 , x2 , y2 組成。 x1 和 y1 是漸變線的起始點(0%)座標,而 x2 和 y2 是這條線的終點(100%)座標。若是這些數值是空的,默認設爲 0% , 0% , 100% , 0% 。這些數值描繪了從指定元素(因爲 gradientUnits 的默認值是 objectBoundingBox)的左上( 0% 0% )到右上( 100% 0% )的一條線。這意味着,默認狀況下,漸變是從左到右。

可是在咱們的例子中,咱們但願漸變從 top 到 bottom ,因此咱們將 x2 的值從 100% 設置爲 0% 而且將 y2 的值從 0% 設置爲 100% 。這使得指定元素的漸變向量從左上角( 0% 0% )指向左下角( 0% 100% )。

Haml
%linearGradient#grad(x2='0%' y2='100%')

在 linearGradient 元素以內,咱們至少須要兩個 stop 元素。其中有三個特定的屬性, 偏移值 offset , 顏色斷點 stop-color, 透明度斷點 stop-color

  1.  偏移值 offset:可使用百分比 %,一般在 0% 到 100% 之間,和 CSS 漸變同樣。也可使用數值,一般是從 0 到 1 。
  2.  顏色斷點 stop-color:理論上可使用關鍵字 hexrgb() , rgba() , hsl() 或者 hsla() ,實際上 Safari 不支持半透明數值 ,所以若是想設置漸變爲半透明,咱們須要依賴第三個屬性。
  3.  透明度斷點 stop-opacity:能夠設置從 0(徹底透明)到 1(徹底不透明)的數值。

咱們須要記住應用漸變遮罩的僞類已經經過 scaleY(-1) 屬性鏡像過來了,這意味着漸變遮罩的底部在視覺上是頂端。所以漸變是從頂部(視覺下端)的徹底透明到底部(視覺上端)的 .7

由於漸變是從上到下,因此第一個斷點徹底透明的。

Haml
%linearGradient#grad(x2='0%' y2='100%')
  %stop(offset='0' stop-color='#fff' stop-opacity='0')
  %stop(offset='1' stop-color='#fff' stop-opacity='.7')

添加線性漸變以後,在Firefox中就是咱們想要的結果了

實時效果以下:

See the Pen bar loader 2.2.4 linearGradient it by Ana Tudor (@thebabydino) on CodePen.

SVG漸變的問題

在咱們的例子中,由於遮罩漸變是垂直的因此看起來很簡單。可是若是漸變不是垂直、水平或者從一個角到另外一個角怎麼辦?若是咱們想要一個特定角度的漸變怎麼辦?

SVG中 有一個 gradientTransform 屬性,它能夠經過指定 x1y1 , x2 ,  y2 來旋轉漸變線。有人可能會認爲這是製做具備特定角度的 CSS 漸變的簡單方法。可是,並無想象的那麼簡單!

想想從金色到深紅色漸變的例子。爲了看得清楚一點,咱們在二者之間 50% 的位置設置一個劇烈的過渡。首先咱們將這個漸變的 CSS 角度設置爲 0deg 。這意味着漸變會從底部(金色)過渡到頂部(深紅色)。建立這個漸變的CSS 以下:

CSS
background-image: linear-gradient(0deg, #e18728 50%, #d14730 0);

若是你還不明白 CSS 線性漸變的工做原理,你能夠看一下Patrick Brosset 作的這個 優秀做品

咱們看到的結果以下:

See the Pen CSS linear-gradient at 0deg with sharp stop at 50% by Ana Tudor (@thebabydino) on CodePen.

爲了製做 SVG 的漸變,咱們設置 y1100%,  y2 爲 0% 以及把 x1 和 x2 設置成相同的數值(簡單起見設置爲 0)。這意味着漸變線從底部垂直上升到頂部。咱們同時把斷點的偏移值設置爲 50%

Jade
linearGradient#g(y1='100%' x2='0%' y2='0%' gradientTransform='rotate(0 .5 .5)')
  stop(offset='50%' stop-color='#e18728')
  stop(offset='50%' stop-color='#d14730')

編輯注:我問 Ana 爲何她如今要使用 Jade 模板。她說:我起初使用 Haml 模板是由於我想避免引入我不須要的循環變量,而以後使用 Jade 模板是由於它容許變量和計算。

這個漸變尚未旋轉,由於 gradientTransform 的值是 rotate(0 .5 .5) 。其中後兩個數值表示漸變旋轉的座標。其中 0 0 表示左上角, 1 1 表示右下角, .5 .5 表示中心。

實時效果以下:

See the Pen SVG linearGradient bottom to top rotated by 0deg with sharp stop at 50% by Ana Tudor (@thebabydino) on CodePen.

若是咱們但願漸變從左到右,在 CSS 漸變中,咱們把角度從 0deg 設置爲 90deg

CSS
background-image: linear-gradient(90deg, #e18728 50%, #d14730 0);

See the Pen CSS linear-gradient at 90deg with sharp stop at 50% by Ana Tudor (@thebabydino) on CodePen.

爲了在 SVG 漸變中獲得一樣的結果,咱們將 gradientTransform 的值設置爲 rotate(90 .5 .5)

Jade
linearGradient#g(y1='100%' x2='0%' y2='0%' gradientTransform='rotate(90 .5 .5)')
  // same stops as before

See the Pen SVG linearGradient bottom to top rotated by 90deg with sharp stop at 50% by Ana Tudor (@thebabydino) on CodePen.

到目前爲止,一切正常。用 SVG 來代替 CSS 漸變並無遇到太多問題。讓咱們嘗試一下其餘的角度。在下面的可交互 demo 中,左側是一個 CSS 漸變,右邊是一個SVG 漸變。紫色的線是漸變線,它與金色和深紅色的交界線是垂直的。拖拽滑塊能夠同時改變 CSS 和 SVG 的漸變角度。咱們會看到一些錯誤:有些數值不是 90deg 的倍數。

See the Pen CSS vs. SVG gradient, same angle (interactive, responsive) by Ana Tudor (@thebabydino) on CodePen.

如以上 demo 所示,有些數值不是 90deg 的倍數,咱們沒法獲得相同的結果。只有當咱們設置漸變的元素是正方形時結果是相同的。這意味着咱們能夠給一個更大的正方形元素設置漸變,而後裁剪成實際的形狀。然而作這些工做會讓 element() 和 mask 來建立漸變倒影的方法更加複雜。

Edge:能夠全用SVG嗎?

使人遺憾的是,以上提到的兩種方法在 Edge 中都沒有用。所以既能在 Edge 中運行又無需手動複製每一個豎條的僅有的方法就是,放下前面的工做從新制做 SVG 加載器。這中方法具備跨瀏覽器的優點。

總的來講,咱們建立一個帶有 viewBox 的 SVG 元素,以便把 0 0 點放在中間。咱們定義一個豎條,它的底邊在 x 軸上,左邊在 y 軸上。而後咱們在 #loader 羣組中根據須要複製(經過 SVG use 元素)屢次。咱們如以前同樣放置這些豎條的位置。

Jade
- var bar_w = 125, bar_h = 5 * bar_w;
- var n = 10;
- var vb_w = n * bar_w;
- var vb_h = 2 * bar_h;
- var vb_x = -.5 * vb_w, vb_y = -.5 * vb_h;

svg(viewBox=[vb_x, vb_y, vb_w, vb_h].join(' '))
  defs
    rect#bar(y=-bar_h width=bar_w height=bar_h)

  g#loader
    - for(var i = 0; i < n; i++) {
      - var x = (i - .5 * n) * bar_w;
      use(xlink:href='#bar' x=x)
    - }

以上代碼的效果以下:

See the Pen bar loader 2.3.1 creating and positioning SVG bars by Ana Tudor (@thebabydino) on CodePen.

如今咱們已經建立了全部豎條,咱們想把 svg 元素的位置調整的更準確並且咱們使用 flexbox 屬性。同時咱們也和以前同樣給豎條添加漸變色。咱們用Sass作這些事情:

SCSS
$n: 10;
$c: #63a6c1 #1e3f57;
$bar-w: 1.25em;
$bar-h: 5 * $bar-w;
$loader-w: $n * $bar-w;
$loader-h: 2 * $bar-h;

body {
  display: flex;
  justify-content: center;
  margin: 0;
  height: 100vh;
}

svg {
  align-self: center;
  width: $loader-w; height: $loader-h;
}

@for $i from 0 to $n {
  $args: append($c, $i * 100%/($n - 1));

  [id='loader'] use:nth-child(#{$i + 1}) {
    fill: mix($args...);
  }
}

添加以上代碼後的效果以下:

See the Pen bar loader 2.3.2 sizing + positioning the SVG & shading the bars by Ana Tudor (@thebabydino) on CodePen.

複製 #loader 羣組(再次使用 use 元素)。經過 scale(1 -1) 方法鏡像克隆體而且給它添加一個遮罩,和咱們以前給僞類元素設置的同樣。默認狀況下,SVG 元素相對於 SVG 畫布的 0 0 點縮放,這個點正好位於loader 元素的底邊上,能夠很完美的將 loader 元素鏡像過來,咱們不用設置 transform-origin

Jade/SVG
use(xlink:href='#loader' transform='scale(1 -1)')

使用 transform 屬性代替CSS變換,由於 CSS 變換在 Edge 中不支持。

如今咱們有了反射倒影,以下所示:

See the Pen bar loader 2.3.3 getting the reflection by Ana Tudor (@thebabydino) on CodePen.

最後一步就是用 mask 給反射添加漸變。它的方法及代碼和以前都是同樣的,咱們再也不贅述。全部的代碼都在下面的 Pen 中

See the Pen bar loader 2.3.4 fading the reflection by Ana Tudor (@thebabydino) on CodePen.

動畫

原始案例中的 CSS 動畫很簡單,就是用3D方式旋轉豎條:

CSS
@keyframes bar {
  0% {
  transform: rotate(-.5turn) rotateX(-1turn);
  }
  75%, 100% { transform: none; }
}

全部的豎條都是一樣的動畫:

CSS
animation: bar 3s cubic-bezier(.81, .04, .4, .7) infinite;

咱們只是給循環的豎條添加了不一樣的延遲時間。

SCSS
animation-delay: $i*50ms;

由於咱們但願旋轉的豎條具備3D效果,全部咱們給 loader 元素添加一個 perspective 屬性

可是使用 -webkit-box-reflect 方法後和預期的同樣只能在 WebKit 瀏覽器中執行。

在Chrome瀏覽器中使用 -webkit-box-reflect 屬性後的最終結果

咱們同時添加了一張背景圖片來看一下它的表現效果。只能在 WebKit 瀏覽器中預覽的效果以下:

See the Pen bar loader 3.1 animating the bars by Ana Tudor (@thebabydino) on CodePen.

咱們也嘗試在 Firefox 中執行動畫。可是,若是咱們把動畫添加到以前在 Firefox 中運行良好的代碼中,好像出現了一些問題。

在Firefox中使用element()和mask方法作的動畫雛形

 

這裏出現了一些問題,下面的demo能夠在Firefox中實時檢測:

See the Pen bar loader 3.2.1 adding animation by Ana Tudor (@thebabydino) on CodePen.

第一個問題就是反射在僞類的邊界處被切斷。咱們能夠經過增長 loader 元素的尺寸來修復這一問題(僞類元素不受影響):

SCSS
$loader-w: ($n + 1) * $bar-w + $bar-h;

可是咱們對於其他的兩個問題就一籌莫展了。當豎條進行3D旋轉時,反射沒法平滑的渲染更新;以及 perspective 屬性致使了豎條的消失。

 添加perspective屬性的結果                                                 沒有添加perspective屬性的結果

如下是實時的顯示結果:

See the Pen bar loader 3.2.2 tweaks by Ana Tudor (@thebabydino) on CodePen.

所有都用 SVG 的方案怎麼樣?很不幸,上面的例子中,咱們只用 CSS 的 3D 變化製做動畫。在 Edge 中,SVG 元素不支持 CSS 的變換屬性,因此咱們以前在建立倒影時使用了 SVG 的 transform 屬性。可是 transform 屬性是嚴格的 2D 模式,咱們只能使用 JavaScript 。

因此就目前來看,想要製做一個兼容全部瀏覽器而且不用複製每個豎條的加載動畫是不可能了。咱們如今能作的就是建立兩個 loader 元素,每個都有相同數量的豎條。

Haml
- 2.times do
  .loader
    - 10.times do 
      .bar

豎條的樣式和以前同樣,咱們使用 scale(-1) 來鏡像第二個loader元素。

CSS
.loader:nth-child(2) {
  transform: scaleY(-1);
}

咱們添加豎條動畫後獲得以下結果:

See the Pen bar loader 3.3.1 reflection via duplication by Ana Tudor (@thebabydino) on CodePen.

如今咱們須要給反射添加漸變。遺憾的是,咱們不能在第二個 loader 元素上使用 mask ,由於它只在跨瀏覽器的 SVG 元素上有效。Edge 目前還不支持 HTML 元素的遮罩效果,可是你能夠給官方提建議。

咱們只能在第二個 loader 元素上添加漸變背景。這樣一來咱們就不能使用圖片背景了。漸變背景只在純色背景或者有限的狀況下才有效。咱們在第二個 loader 元素的 ::after 上添加漸變背景而且設置的大一點,這樣就不會擋住旋轉的豎條。

SCSS
$bgc: #eee;
$cover-h: $bar-w + $bar-h;
$cover-w: $n * $bar-w + $cover-h;

html { background: $bgc; }

.loader:nth-child(2)::after {
  margin-left: -.5 * $cover-w;
  width: $cover-w; height: $cover-h;
  background: linear-gradient($bgc $bar-w, rgba($bgc, .3));
  content: '';
}

最終結果以下:

See the Pen bar loader 3.3.2 emulate fading with cover by Ana Tudor (@thebabydino) on CodePen.

最後的思考

咱們須要一個更好的跨瀏覽器解決方案。我相信製做物體的反射並不須要像咱們在這個例子中同樣複製全部的子元素。爲了製做能夠放置在圖像背景 background 上的漸變反射,咱們不能替換成 SVG 的方案(其自身也有不少問題)。

哪種方案更好? -webkit-box-reflect 仍是 element()mask ?我也不知道。我我的喜歡同時使用。

雖然使用 :reflection 僞類元素 看上去很合理,可是我曾經確信我不想使用額外的元素製做反射。可是如今有比不用插入額外元素更讓我喜歡的事情。使用 element() 能夠在不一樣方向上自由建立多個反射,以及用不一樣的方式變換反射,好比 3D 旋轉或者傾斜。這正是我喜歡它的緣由。並且用 SVG 作遮罩意味着咱們能夠在反射上應用更復雜的遮罩同時得到更酷的效果。

另外一方面,能力越強,責任越大。也許你沒有時間去接觸強大功能背後的複雜細節。有時你只是想要一個簡單的方法來得到一個簡單的結果。

相關文章
相關標籤/搜索