CSS 炫酷文字過渡動畫

南城大前端發表於2022-05-24

今天分享一個炫酷的文字過渡動畫效果,如下面GIF所示,曾經是否有見過這種動畫呢,想想是不是感覺挺複雜呢,通常這個過渡效果通過較為複雜的可用WebGl實現,本文通過另一種方式實現,文章尾部有神奇的程式碼,快來瞧瞧看吧~

程式碼實現

文字不斷的在切換,確定的是有一個包含純文字的陣列,在此我們定義如下的html程式碼,後面通過交替顯示其中一個span標籤來達到動畫的效果。

<div id="container">
  <span id="text1"></span>
  <span id="text2"></span>
</div>

然後定義簡單的CSS程式碼,通過定位的方式將兩個span疊在一起。

#container {
    position: absolute;
    margin: auto;
    width: 100vw;
    height: 80pt;
    top: 0;
    bottom: 0;
}

#text1, #text2 {
    position: absolute;
    width: 100%;
    display: inline-block;
    font-size: 80pt;
    text-align: center;
    user-select: none;
}

此時我們的基本結構結構已經完成了,接下來開始動畫的邏輯。兩個文字之間的動畫交替使用兩個動畫實現,filteropacity,通過計算一個 0 到 1 的函式更新兩個文字元素 filteropacity 的數值。

// 控制動畫速度
const morphTime = 1;
const cooldownTime = 0.25;

let morph = 0;
let cooldown = cooldownTime;

function doMorph() {
    morph -= cooldown;
    cooldown = 0;
    
    let fraction = morph / morphTime;
    
    if (fraction > 1) {
        cooldown = cooldownTime;
        fraction = 1;
    }
    
    setMorph(fraction);
}

function setMorph(fraction) {
    text2.style.filter = `blur(${Math.min(8 / fraction - 8, 100)}px)`;
    text2.style.opacity = `${Math.pow(fraction, 0.4) * 100}%`;
    
    fraction = 1 - fraction;
    text1.style.filter = `blur(${Math.min(8 / fraction - 8, 100)}px)`;
    text1.style.opacity = `${Math.pow(fraction, 0.4) * 100}%`;
    
}

每執行一次動畫結束後清空css中filteropacity數值。

function doCooldown() {
    morph = 0;
    
    elts.text2.style.filter = "";
    elts.text2.style.opacity = "100%";
    
    elts.text1.style.filter = "";
    elts.text1.style.opacity = "0%";
}

最後就是初始化,基於requestAnimationFrame建立動畫保障動畫的流暢。

function animate() {
    requestAnimationFrame(animate);
    
    let newTime = new Date();
    let shouldIncrementIndex = cooldown > 0;
    let dt = (newTime - time) / 1000;
    time = newTime;
    cooldown -= dt;
    
    if (cooldown <= 0) {
        if (shouldIncrementIndex) {
            textIndex++;
        }
        doMorph();
    } else {
        doCooldown();
    }
}

這個時候的動畫效果如下所示,是可以看到動畫是基於我們設定的filteropacity實現,但是離最開始的動畫效果還差很遠,接下來就是本文的重頭戲。

在HTML中新增以下SVG程式碼,主要功能就是將足夠高不透明的畫素設定為完全不透明,剩餘其他畫素設定為完全透明。

<svg id="filters">
    <defs>
        <filter id="threshold">
            <feColorMatrix in="SourceGraphic"
                    type="matrix"
                    values="1 0 0 0 0
                                    0 1 0 0 0
                                    0 0 1 0 0
                                    0 0 0 255 -140" />
        </filter>
    </defs>
</svg>

再結合一段神奇的CSS程式碼即可完成我們最後的一步,動畫效果就完成啦~

#container {
    ...
    filter: url(#threshold) blur(0.6px);
}

線上看效果:demo

最後

整體程式碼就結束啦,最關鍵的程式碼就是最後的 svgcss filter 結合,有興趣的同學可以研究一下其背後的原理。看完覺得有用,記得點贊收藏起來吧,說不定哪天就用上啦~

專注前端開發,分享前端相關技術乾貨,公眾號:南城大前端(ID: nanchengfe)

相關文章