Well in Time
有趣的 WEB 特效與技巧分享
01-29-20217 Min Read

好歌分享:飛在風中的小雨

前言

很多人可能會認為前端工程師對於美感都有一定的水準,甚至應該要會一點點設計,但現實中應該有很大一部分的前端工程師跟我一樣,其實負責處理狀態管理居多,對設計沒有太多的著墨。

雖然現實是如此,我個人還是非常喜歡欣賞網路上大神們透過 CSS、Web API 所創作的東西,今天就來分享幾個我這陣子看到覺得蠻有趣的 WEB 特效與技巧!

Motion blur

demo

忘了是從哪裡看到這個網站 - Motion Blur Scrolling Demo,驚為天人,雖然看了其實眼睛會不太舒服,但特效實在太酷,無法大聲斥責。

作者的程式碼公開在此:motionblur,我把一些看來是作者嘗試做的優化拿掉,擷取重點來解釋,大家也可以到 CodeSandbox 查看程式碼與把玩 Demo

Edit motion-blur-test

不過要注意一點,這個特效只有在電腦版的 Chrome 與 Edge 上表現最好,firefox 還 ok,Safari 則是完全崩潰,電腦或手機都無法呈現效果。

原理解析

從名稱應該就能看出端倪,既然是 motion "blur",自然會想到 CSS 的 filter:blur() 屬性,blur() 接受單一數值,例如:5px,不能是百分比,數值越大越模糊:

css-blur-sample

image source: MDN - filter

模糊是有了,但 blur 的模糊感覺跟範例中的 motion blur 好像有點差距,要讓畫面在上下捲動時,有拉長模糊的感覺才對,這種整片均勻模糊的樣子似乎不太對呀?

要解開這個謎題,得先提到一個可能較少為人知的知識:像 blur 這種 filter-function 的屬性大多都有對應的 svg-filter,透過 svg-filter 你就能更細緻的調整參數。使用方式則為在你想要套用 filter 效果的 DOM 元件上,用 filter: url() 來指定 svg 的 id,e.g.:

<body style="filter: url("#9isnV");">

blur(5px) 來說,其內部是用高斯函數的標準偏差值(stdDeviation)來決定畫面上多少 pixels 會互相交錯融合,對應的 svg 為:

<svg style="position: absolute; top: -99999px" xmlns="http://www.w3.org/2000/svg">
  <filter id="svgBlur" x="-5%" y="-5%" width="110%" height="110%">
    <feGaussianBlur in="SourceGraphic" stdDeviation="5"/>
  </filter>
</svg>

調整 stdDeviation 就能有比起單純用 blur(5px) 更豐富的效果,而根據 MDN 資料,stdDeviation 的 type 是 <number-optional-number>,也就是其實他能有第二個參數,當提供兩個參數時,一個會代表 x 軸的標準偏差值,一個則是 y 軸的。

所以謎題就揭曉了,要做出上下拉長的模糊化,我們可以調整 stdDeviation 的 y 軸值,這也是整個特效的重點。

如果把 y 值設大,例如 20,畫面就會變成這樣:

<feGaussianBlur in="SourceGraphic" stdDeviation="0,20"/>

y-deviation

因此,要做出 motion blur,就是在 scroll 的時候調整 y 值。

把調整 y 值的函式綁定到 scroll event 的 listener,並根據捲軸捲動的位置變化差距來決定 y 軸值的大小,就能造就出範例中那種動越快越模糊的 motion blur 效果(scroll event listner 的實作不難,可以到 codesandbox 查看):

// 核心程式碼
export function initializeBodyScrollMotionBlur() {
  // 動態創建 svg filter DOM 元素,將其存到 bodyBlur 物件
  const bodyBlur = createBlurSvg();
  // 將 svg filter 綁定到 body 上
  bodyBlur.applyTo(document.body);

  initializeScrollSpeedWatcher(document.documentElement, (speed) => {
    // 註冊 scroll event listener,計算捲軸滾動速度,在滑動時更改 filter DOM stdDeviation attribute。
    // 因為我們只需要改 y 軸的值,所以 x 固定為 0
    bodyBlur.setBlur({ x: 0, y: Math.abs(speed.y / 2) });
  });
}

雖然不太實用,但理解原理後還是會覺得這真的是個有趣又不太難的效果!

CSS 3D rolling

第二個想分享的在我平常訂閱的週刊 - Frontend Horse 看到的範例,united sodas 的網站:

3d-rolling-can

透過 GIF 可能看起來不是很清楚,但實際在網站上的效果很不錯,真的有罐子旋轉的感覺。

原理解析

要讓 DOM object 呈現 3D 有不少做法,利用 CSS 的 3D transforms、perspective 搭配 translate、rotate 就可以,然而週刊的作者提出的作法我覺得更為簡單且有趣,與其真的去旋轉物件,不如利用人眼錯覺,固定住 3D 模樣的罐子,只讓上方的 label 文字滾動。

具體做法如下:

找一個包含陰影的透明罐子圖案(如下圖):

3d-can-transparent

以及罐子的 Label 包裝圖片:

3d-can-label

將 Label 圖片疊加在罐子上,利用 JS 讓滾輪滾動時,將圖片從罐子右邊移至左邊。

重點在於最後要利用 clip-path 來製造出一個 svg mask,把圖片修整成貼合罐子的樣子,就可以完成這個滑順的轉動動畫!

週刊作者有提供一個 codepen 連結,可以試著把 Clip Path On 的 checkbox 開啟關閉,應該能清楚了解整體概念:

Animation based on the time uniform value

本週最後一個要分享的是從 css-doodle 的作者 blog 上看到的小技巧,這是作者發現在電腦視覺的 Shader 中,經常利用 Time Uniforms 的方式去控制動畫,這跟一般 CSS @keyframes 透過指定各時間點的屬性變化,利用 interpolation 來形成動畫的方式是不同的思考方式。

然而在 Web 世界中,其實能利用 CSS Houdini@property API 與 CSS @Keyframes,製作出一個能隨著時間變化其值的 custom property,如此一來就能達成類似 time uniforms 的方法,統一依照時間來控制所有 DOM 物件的動畫:

首先利用 @property API 客製化屬性:

@property --t {
  syntax: "<number>";
  initial-value: 0;
  inherits: true;
}

透過 @keyfames 來 anitmate 客制屬性,這邊時間用 31536000000 是因為作者想營造無限時間的動畫,用一年為區間算是個很足夠長的模擬方式:

@keyframes animate-time {
  from { --t: 0 }
  to   { --t: 31536000000 }
}

最後將 keyframes 動畫放到 :root 中,這樣所有的 css class 所吃到的 --t 就會是不斷隨著時間而更動的值,此外, anmiation 的 druation 同樣設為一年,時間才會同步:

:root {
  animation: animate-time 31536000000ms linear infinite;
}

最後在任意的 element 上頭,只要利用變動的 --t 就能在不另外指定 keyframes 的狀況下一樣產生動畫:

element {
  transform: rotate(
    calc(var(--t) / 1000 / 10 * 1turn)
  );
}

同樣的 --t 值,同時套用在其他元素動畫上時,就能營造出利用 time uniforms 來製造動畫的效果。

附上作者的 codepen 範例:

See the Pen Demo #1 for article (Chrome only) by yuanchuan (@yuanchuan) on CodePen.

結論

今天分享了三個我這週發現的有趣特效與小技巧,雖然沒有自己真正實作,但觀摩別人的創意與程式碼也能學習到非常多,除了當工作上需要使用到類似效果時,會有印象可以怎麼做之外,或許也能讓你舉一反三,融合這些技巧,製作出別出心裁的特效也說不定呢!

資料來源

  1. MDN filter
  2. Motion Blur Scrolling Demo
  3. Time Uniform For CSS Animation
  4. The book of shaders
© by Arvin Huang. All rights reserved.
theme inspired by @mhadaily
Last build: 05-05-2023