SVG-讓世界變得柔軟

Apollozz發表於2018-12-10

這篇是之前翻譯的,因為近期在整理svg相關的一些內容,故也一併貼過來。

SVG-讓世界變得柔軟
菠蘿看到一個效果非常喜歡,當圖形靠近時有一種類似於水滴融合在一起的感覺,不會像平時的圖形那樣生硬地互相遮擋,看了網上一些資料之後嘗試著做了下面這個demo。

如果你也喜歡這個效果,可以繼續看下菠蘿翻譯的下面這篇文章,有些地方可能會因為理解不到位有些差異,有興趣的戳英文原文,文章中的GIF也在原文中有相關程式碼連結。

SVG-讓世界變得柔軟

正文:《The Gooey Effect》 by LUCAS BEBBER

SVG-讓世界變得柔軟

前陣子, Chris寫了一篇關於《Shape Blobbing in CSS》,呈現出來的效果非常棒,背後的實現技術也相當機智。但是這種使用CSS常規濾鏡的方法有它明顯的缺點:沒有透明度、水滴內不能展示內容,很難使用除了黑白之後的顏色等等。

剛好這些天我研究了一下SVG的濾鏡,用來解決CSS方式的大多數問題非常方便。這裡你可以看到一個帶膠粘效果的選單,我做了演示的效果:

SVG-讓世界變得柔軟

SVG濾鏡基礎講解

SVG濾鏡功能非常強大,所以這個話題涉及的內容比較泛,這裡我們只介紹那些基礎的屬性來理解它是如果實現這個效果的。

我們可以在大多數的瀏覽器中,把SVG濾鏡通過CSS應用到常規的DOM元素上。

下面是定義濾鏡的基本語法。

<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
  <defs>
    <filter id="name-your-filter-here">
      ...          
      <!-- insert filters here -->
      ...
    </filter>
    ...
  </defs>
</svg>
複製程式碼

把SVG濾鏡應用到一個DOM元素。

.selector {
  filter: url('#name-of-your-filter-here');

  /* you can also load filters from external SVGs this way: */
  filter: url('filters.svg#name-of-your-other-filter-here');
}
複製程式碼

在某些瀏覽器中,你可能需要給filter屬性加上私有字首才能使用。

一個元素可以包含一個或多個濾鏡基元,例如模糊、顏色轉換、陰影等。


下面我們先看一些例子。

SVG-讓世界變得柔軟

<filter id="blur">
  <feGaussianBlur in="SourceGraphic" stdDeviation="3"/>
</filter>
複製程式碼

這個濾鏡會對應用的物件做一個簡單的3px的模糊。注意一下in="SourceGraphic"屬性。

  • in屬性定義了濾鏡基元的輸入。
  • SourceGraphic則是返回元素的原始濾鏡圖形的關鍵字。
  • 所以這意味著模糊濾鏡的輸入資源是物件的原始圖形,很直觀。

下面我們來看一個很普通但是複雜很多的效果——一個陰影濾鏡。這個例子將清楚地展示如何把多個濾鏡基元連結起來。

SVG-讓世界變得柔軟

<filter id="drop-shadow">
  <feGaussianBlur in="SourceGraphic" stdDeviation="7" result="shadow" />
  <feOffset in="shadow" dx="3" dy="4" result="shadow" />
  <feColorMatrix in="shadow" mode="matrix" values="0 0 0 0 0  0 0 0 0 0  0 0 0 0 0  0 0 0 0.6 0" result="shadow" />
  <feBlend in="SourceGraphic" in2="shadow" />
</filter>
複製程式碼

先看一下第一個濾鏡基元中的result屬性和後面的in屬性。通過result屬性你可以給一個濾鏡基元的輸出結果命名,然後把這個結果替代原始的圖形應用給下一個濾鏡基元。在這個示例中,這些步驟將先模糊一個物件,使模糊的物件變暗,再移動這個被模糊和變暗的物件。

注意下最後一個元素的基元,它的意思是一些濾鏡基元可以有多個輸入(in2引數),你可以在多個濾鏡基元的任何點多次呼叫SourceGraphic。在這個示例中,最後一個濾鏡基元呼叫了SourceGraphic關鍵字和shadow,將原始的圖形放在我們畫出的陰影上方。

現在已經介紹完了SVG濾鏡的基礎知識,下面我們看一下如何實現膠粘效果。

見證奇蹟的時刻

SVG-讓世界變得柔軟

CSS實現方法基本的原理在這裡講過了,簡而言之,這個想法的關鍵就是模糊兩個或者多個的物件並增加對比度,很簡單但是效果很酷炫。

但是,正如我們之前看到的,它依然就很多缺點:

  1. 對比度改變了物件原始的顏色,使得你很難運用除了黑白之外的顏色;
  2. 把內容也一起模糊了,導致無法使用;
  3. 容器需要一個背景顏色,所以沒有透明度。

總之,這些缺點使得這個效果很雞肋。

但是有了SVG濾鏡的話,我們就可以實現很多CSS濾鏡無法單獨實現的效果,比如我們可以只提高alpha通道的對比度避免改變物件自身的顏色,我們可以使用前面使用過的SourceGraphic這個關鍵字,使內容可見。既然我們使用了alpha通道,它不僅會是透明的,且背景也必須是透明的,這點需要特別注意。

下面是基礎程式碼:

<filter id="goo">
  <feGaussianBlur in="SourceGraphic" stdDeviation="10" result="blur" />
  <feColorMatrix in="blur" mode="matrix" values="1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 18 -7" result="goo" />
  <feBlend in="SourceGraphic" in2="goo" />
</filter>
複製程式碼

程式碼很短,讓我們分解一下:

  1. 首先,我們應用了10px的模糊到物件的原始影象上,並給輸入結果取了名字;
  2. 然後,為了增加alpha通道的對比度,我們應用了一個顏色矩陣濾鏡到上一步的輸出結果上;
  3. 最後,在我們畫出來的效果上再新增一個原始影象。

關於顏色矩陣

如果你之前沒有使用過顏色矩陣濾鏡,那麼這裡需要簡單解釋一下。你可以把它當成一個有4行5列的一個表格,看起來像這樣:

SVG-讓世界變得柔軟

每一行代表一個通道(red紅色、green綠色、blue藍色和alpha透明),用來設定通道的值。前面四列中的每一列也代表一個通道,並且返回它們各自通道的當前值。然後,單元格中的數字乘以由其列表示的通道的當前值的結果新增到其行通道。例如,對於每個畫素點的色值,R行G列的0.5將向R通道新增原G值*0.5。最後一列不代表任何通道,只用於加/減,意味著一個數字將乘以255新增到其通道值中。

SVG-讓世界變得柔軟
(這裡好像沒有解釋得很清楚,自行補充一張公式圖)

這是一個冗長的解釋,但是使用過濾器非常簡單。在我們的案例中,我們只需要提高alpha通道的對比度,顏色矩陣濾鏡如下:

SVG-讓世界變得柔軟

這樣的話,RBG通道都沒有改變,將alpha通道的值乘以18,然後減去7*255,就能有效地增加透明度的對比度。這些值可以根據你的需求進行調整。

要將這個矩陣應用到feColorMatrix濾鏡中,我們只需要按順序寫好這些數字,如下所示:

SVG-讓世界變得柔軟

DEMO

到這裡我們的所有基礎步驟就準備就緒了。

SVG-讓世界變得柔軟

你可以根據你的需求定製它,例如新增一個陰影或者給不同的元素使用不同的顏色等等。

注意事項

  1. 濾鏡需要應用在元素的包裹層上,而不是元素本身;
  2. 包裹層(容器)需要有一定的溢位區域,比如需要比它的內容區域大一些,不然你會看到邊緣的鋸齒;

SVG-讓世界變得柔軟

  1. 為了能將濾鏡應用於像正方形這樣的尖銳圖形,我們需要採取稍微複雜一點的方法。這次不像之前那樣畫一個原始的圖形蓋在膠粘效果上,我們把feComposite濾鏡基元的operator屬性定義為atop去遮掉除了膠粘效果之外的東西。
<filter id="fancy-goo">
  <feGaussianBlur in="SourceGraphic" stdDeviation="10" result="blur" />
  <feColorMatrix in="blur" mode="matrix" values="1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 19 -9" result="goo" />
  <feComposite in="SourceGraphic" in2="goo" operator="atop"/>
</filter>
複製程式碼

SVG-讓世界變得柔軟

這樣的話,濾鏡就不單單能應用到複雜的膠粘效果中,也可以實現多個長方形組合起來的圓角之類的較為簡單的效果。

  1. SVG濾鏡雖然本身不大,但是非常消耗資源,因此要避免大面積地使用。

相容性

SVG濾鏡的相容性良好,但不是所有的瀏覽器都支援它們應用到常規的DOM元素上,特別是Safari。但是它們至少可以在Firefox和Chrome上正常執行,即使在安卓版本中,如果不能正常執行也會完美降級。如果你確實需要在工作中運用這個效果,可以考慮使用SVG元素替代DOM元素。

相關文章