實現一個會動的鴻蒙 LOGO

2022-08-12 18:02:27

本文將帶大家簡單實現一個會動的鴻蒙 LOGO。

emmm,寫本文的動機是之前在掘金看到一篇實現鴻蒙 LOGO 的文章 -- 產品經理:鴻蒙那個開場動畫挺帥的 給咱們頁面也整一個唄

鴻蒙的 LOGO 本身是這樣的:

該篇作者最終實現的是一個字母 O 的動畫展開過程:

而本文想嘗試的,是該 LOGO 的其他一些細節,核心是倒影部分的水波效果。

實現主體

首先,我們需要對該結構進行簡單的一個拆解,因為上下部分的較大差異,雖然是一個圓,但是很明顯需要分成兩塊處理,這部分比較簡單且不是重點,我就略過分享,直接上程式碼。

我們的結構大致如下:

<div class="g-container">
    <div class="g-top">
    </div>
    <div class="g-bottom">
    </div>
</div>
@import url('https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,100;0,200;1,200&display=swap');
.g-container {
    width: 100%;
    height: 100%;
    background: #000;
}
.g-top {
    position: fixed;
    top: 0;
    left: 0;
    width: 100vw;
    height: 50vh;
    overflow: hidden;
    
    &::before {
        content: "";
        position: absolute;
        border-radius: 50%;
        bottom: 0;
        left: 50%;
        width: 200px;
        height: 200px;
        transform: translate(-50%, 100px);
        box-sizing: border-box;
        background: #000;
        border: 25px solid #fff;
        z-index: 1;
        box-shadow: 
            0 0 4px 1px rgba(255, 255, 255, .8),
            0 0 8px 2px rgba(255, 255, 255, .6);
    }
}
.g-bottom {
    position: fixed;
    top: 50vh;
    left: 0;
    width: 100vw;
    height: 50vh;
    background: #000;
    overflow: hidden;
    
    &::before {
        content: "";
        position: absolute;
        border-radius: 50%;
        top: 0;
        width: 200px;
        height: 200px;
        background: #000;
        left: 50%;
        transform: translate(-50%, -100px);
        box-sizing: border-box;
        border: 25px solid #fff;
        z-index: 2;
        box-shadow: 
            0 0 4px rgba(255, 255, 255, .8),
            0 0 8px rgba(255, 255, 255, .7),
            0 0 20px rgba(255, 255, 255, .6);
        filter: blur(4px);
    }
}

核心做的就是上下兩個半圓的實現,以及對下面部分使用了模糊濾鏡 filter: blur(),我們可以初步得到這樣一個結構:

好吧,看著確實是平平無奇。

新增 SVG feTurbulence 濾鏡。實現水波倒影效果

OK,下面就是見證奇蹟的時刻。我們給下部分的 g-bottom 新增一個 SVG feTurbulence 濾鏡,讓它產生水波倒影效果。

SVG feTurbulence 濾鏡在我的非常多篇文章中都有提到,turbulence 意為湍流,不穩定氣流,而 SVG <feTurbulence> 濾鏡能夠實現半透明的煙燻或波狀影象。通常用於實現一些特殊的紋理。濾鏡利用 Perlin 噪聲函數建立了一個影象。噪聲在模擬雲霧效果時非常有用,能產生非常複雜的質感,利用它可以實現了人造紋理比如說雲紋、大理石紋的合成。

如果你對 SVG 濾鏡還不算太瞭解,可以簡單看看我的這幾篇文章入門:有意思!強大的 SVG 濾鏡 以及這篇實戰篇: 震驚!巧用 SVG 濾鏡還能製作表情包?

emmm,所以步驟是:

  1. 實現一個 SVG feTurbulence 效果
  2. 加上 SVG animation 動畫,
  3. 再通過 CSS Filter 參照至濾鏡到 DOM 結構之上
<!-- HTML 結構下的 SVG 程式碼 -->
<svg>
    <filter id="fractal" filterUnits="objectBoundingBox" x="0%" y="0%" width="100%" height="100%">
        <feTurbulence id="turbulence" type="fractalNoise" baseFrequency="0.01 0.01" numOctaves="10">
            <animate
                 attributeName="baseFrequency"
                 dur="30s" 
                 values="0.01 0.01;0.03 0.15;0.01 0.01"
                 repeatCount="indefinite" />
        </feTurbulence>
        <feDisplacementMap in="SourceGraphic" scale="15"></feDisplacementMap>
    </filter>
</svg>
.g-bottom {
    // 通過 Filter 參照 SVG 濾鏡到 DOM 結構之上
    filter: url(#fractal);
}

Wow,僅僅是一個濾鏡的疊加,就瞬間讓動畫高大上了起來。這也是 SVG feTurbulence 濾鏡的魅力所在,完成了 CSS 一些無法實現的功能。

通過漸變及 MASK 實現光圈

再看看原圖,還有一圈圈的藍色光圈,這個使用 repeating-radial-gradientmask 可以實現。

簡單的程式碼如下:

<div></div>
div {
    background: repeating-radial-gradient(circle at 50% 100%, transparent, transparent 5px, #2c5ec8 5.2px, #2c5ec8 6.2px, transparent 6.5px);
    mask: radial-gradient(circle at 50% 100%, rgba(255, 255, 255, .8), transparent 25%, transparent);
}

repeating-radial-gradient 配合 mask 實現漸隱的光圈效果,結果如下:

把這個光圈往效果裡疊加,及其他一些小細節及文字,最終可以實現一個這樣的 LOGO 效果(雖然也不是很像,還有很多細節沒還原):

完整的程式碼你可以猛擊這裡:CSS 靈感 -- SVG 濾鏡及 filter: blur 實現鴻蒙 LOGO

腦洞一下

運用上述的 SVG feTurbulence 濾鏡,我們能不能再搞點事情呢?

我們可以利用它,嘗試去實現這樣的效果,實現圖片的部分動態波動,運用在特定的場景,能夠非常大的提升使用者體驗,讓人「哇塞」一下:

又或者是:

上述兩個效果來自:tympanus - Distortion Effect,但是它們並非是使用 CSS + SVG 實現,而是使用的 WebGL,但是它們確實可以用上述的方式復現。

假設我們有這樣一張圖:

下面,我們就利用 SVG feTurbulence 讓中間的石頭波動起來:

  1. 我們讓兩張一模一樣的圖疊加在一起(使用 div 及它的偽元素即可)
  2. 利用 clip-path 將疊在上層的圖中的石頭切割出來
  3. 利用 SVG feTurbulence 將濾鏡作用給上層的圖片

完整的程式碼如下:

<div></div>

<svg>
    <filter id="fractal" filterUnits="objectBoundingBox" x="0%" y="0%" width="100%" height="100%">
        <feTurbulence id="turbulence" type="fractalNoise" baseFrequency="0.005 0.005" numOctaves="10">
            <animate
                 attributeName="baseFrequency"
                 dur="60s" 
                 values="0.005 0.005;0.003 0.03;0.005 0.005"
                 repeatCount="indefinite" />
        </feTurbulence>
        <feDisplacementMap in="SourceGraphic" scale="15"></feDisplacementMap>
    </filter>
</svg>
div {
    position: relative;
    width: 600px;
    height: 400px;
    background-image: url(https://z3.ax1x.com/2021/09/05/hWPVqe.jpg);
    
    &::before {
        content: "";
        position: absolute;
        top: 0;
        left: 0;
        bottom: 0;
        right: 0;
        background: inherit;
        clip-path: polygon(225px 50px, 320px 50px, 320px 90%, 225px 90%);
        filter: url(#fractal);
    }
}

這樣,我們就能得到一張動起來的石頭,我們利用一張靜態圖,實現了其中部分的動態波動效果

CodePen Demo -- SVG feTurbulence Image Effect

利用這個技巧,我們可以很輕鬆的還原上述兩個使用 WebGL 實現的效果。Amazing~

最後

好了,本文到此結束,希望對你有幫助