LPL Ban/Pick 選人階段的遮罩效果是如何實現的?

chokcoco發表於2022-02-15

最近 S11 LPL 春季賽開賽,在看比賽的過程中,我發現新賽季的 Ban/Pick 選人階段,出現了一種新的,有意思的遮罩效果,如下圖所示:

當然,它是一個動態的效果,當選人的過程中,會有一種呼吸的效果:

Gif 圖有點糊,總的而言,就是一種接近迷霧的遮罩效果。並且,他是能夠動態變化的。

本文將探究,在 CSS 中,我們應該如何去實現類似的效果。

實現煙霧化遮罩效果

首先,我們來嘗試實現這樣一個動態遮罩:

假設沒有模糊的邊緣,及煙霧化的效果,它其實就是一個漸變:

<div></div>
div {
    width: 340px;
    height: 180px;
    border: 2px solid #5b595b;
    background: linear-gradient(
        rgba(229, 23, 49, 1),
        rgba(229, 23, 49, .9) 48%,
        transparent 55%,
    );
}

經由上述程式碼,我們可得到:

好吧,看著確實平平無奇,我們如何利用它,得到一個霧化的效果呢?

提到煙霧,聰明的同學應該能想到濾鏡,當然,是 SVG 的 <feturbulence> 濾鏡。

沒錯,又是它,<feturbulence> 確實太有意思了,我最近的兩篇關於它的文章 -- Amazing!!CSS 也能實現煙霧效果?Amazing!!CSS 也能實現極光? 可以一併閱讀。

<feturbulence>type="fractalNoise" 在模擬雲霧效果時非常好用。該濾鏡利用 Perlin 噪聲函式建立了一個影像,能夠實現半透明的煙燻或波狀影像,用於實現一些特殊的紋理。

這裡,我們利用 <feturbulence> 濾鏡簡單處理一下上述圖形:

<div></div>

<svg width="0">
  <filter id="filter">
    <feTurbulence id="turbulence" type="fractalNoise" baseFrequency=".03" numOctaves="20" />
    <feDisplacementMap in="SourceGraphic" scale="30" />
  </filter>
</svg>

CSS 中,可以利用 filter: url() 對對應的元素引入該濾鏡:

div {
    ...
    filter: url(#smoke);
}

作用了濾鏡的元素的效果:

由於我給元素加了邊框,整個邊框也被霧化了,這不是我們想要的,可以使用偽元素改造一下,邊框作用於容器,使用偽元素實現漸變,將濾鏡作用於偽元素

div {
    position: relative;
    width: 340px;
    height: 180px;
    border: 2px solid #5b595b;
    
    &::before {
        content: "";
        position: absolute;
        left: 0;
        top: 0;
        right: 0;
        bottom: 0;
        background: linear-gradient(
            30deg,
            rgba(229, 23, 49, 1),
            rgba(229, 23, 49, .9) 48%,
            transparent 55%,
        );
        filter: url(#smoke);
    }
}

改造後的效果如下:

好,又接近了一步,但是四周有很多瑕疵沒有被填滿。問題不大,我們改變一下定位的 top \ left \ right \ bottom,讓偽元素超出父容器,父容器設定 overflow: hidden 即可:

div {
    ....
    overflow: hidden;
    
    &::before {
        ....
        left: -20px;
        top: -10px;
        right: -20px;
        bottom: -20px;
        background: linear-gradient(
            30deg,
            rgba(229, 23, 49, 1),
            rgba(229, 23, 49, .9) 48%,
            transparent 55%,
        );
        filter: url(#smoke);
    }
}

調整之後,看看效果:

有點那感覺了,下一步,只需要讓煙霧元素動起來,為了讓整個效果連貫(由於 SVG 動畫本身不支援類似 animation-fill-mode: alternate 這種特性),我們還是需要寫一點 JavaScript 程式碼,控制動畫的整體迴圈。

大概的程式碼是這樣:

const filter = document.querySelector("#turbulence");
let frames = 1;
let rad = Math.PI / 180;
let bfx, bfy;

function freqAnimation() {
    frames += .35;

    bfx = 0.035;
    bfy = 0.015;

    bfx += 0.006 * Math.cos(frames * rad);
    bfy += 0.004 * Math.sin(frames * rad);

    bf = bfx.toString() + " " + bfy.toString();
    filter.setAttributeNS(null, "baseFrequency", bf);

    window.requestAnimationFrame(freqAnimation);
}

window.requestAnimationFrame(freqAnimation);

這段程式碼做的事情,其實只有一個,就是讓 SVG 的 #turbulence 濾鏡的 baseFrequency 屬性,在一個區間內無限迴圈,僅此而已。通過改變 baseFrequency,讓整個煙霧不斷變化。

至此,我們就得到了一幅完整的,會動的煙霧遮罩:

補充下框內的圖片,就能得到一開始給出的效果圖效果:

完整的程式碼,你可以戳這裡 -- CodePen Demos -- LPL BAN PICK MASK Effect

實現呼吸狀態的遮罩效果

在上述基礎上,再加入呼吸的效果,其實就非常簡單了。

我們只需要去改變漸變的一個位置即可,方法非常多,這裡我給一個較為優雅但是相容性可能沒那麼好的方法 -- CSS @property。

簡單改造上述程式碼:

@property --per {
    syntax: "<percentage>";
    inherits: false;
    initial-value: 22%;
}
div::before {
    ...
    background: linear-gradient(
        30deg,
        #ff0020,
        rgba(229, 23, 49, .9) var(--per),
        transparent calc(var(--per) + 8%),
    );
    filter: url(#smoke);
    animation: change 2s infinite ease-out;
}
@keyframes change {
    50% {
        --per: 18%;
    }
}

這樣,呼吸效果就實現了:

完整的程式碼,你可以戳這裡 -- CodePen Demos -- LPL BAN PICK MASK Effect

最後

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

想 Get 到最有意思的 CSS 資訊,千萬不要錯過我的公眾號 -- iCSS前端趣聞 ?

更多精彩 CSS 技術文章彙總在我的 Github -- iCSS ,持續更新,歡迎點個 star 訂閱收藏。

如果還有什麼疑問或者建議,可以多多交流,原創文章,文筆有限,才疏學淺,文中若有不正之處,萬望告知。

相關文章