螺旋文字滾動(dòng)特效源碼解析,你學(xué)會(huì)了嗎?
圖片
如圖所示,今天看到一個(gè)很炫酷的雙文字螺旋滾動(dòng)特效,兩行文字呈螺旋狀變化,在網(wǎng)站中這樣的效果對(duì)用戶很有吸引力。本文將基于原網(wǎng)站解析如何實(shí)現(xiàn)這個(gè)炫酷的效果,基于這個(gè)動(dòng)圖可以分析出需要實(shí)現(xiàn)的要點(diǎn):
- 文字呈螺旋狀滾動(dòng)
- 滾動(dòng)過(guò)程中文字大小變化
- 動(dòng)畫過(guò)程無(wú)縫鏈接
- 兩行文字滾動(dòng)
實(shí)現(xiàn)過(guò)程
文字展示
為了方便更改文案將文案定義變量,通過(guò)JS代碼動(dòng)態(tài)創(chuàng)建DOM,定義文案、螺旋的角度以及動(dòng)畫的持續(xù)時(shí)間:
const words = "螺旋文字滾動(dòng)特效";
const ANGLE = 360;
const ANIMATION_DURATION = 4000;
將文案創(chuàng)建元素添加到頁(yè)面中:
const characters = words.split("").forEach((char, i) => {
const createElement = (offset) => {
const div = document.createElement("div");
div.innerText = char;
div.classList.add("character");
div.setAttribute("data-offset", offset);
return div;
};
document.querySelector("#spiral").append(createElement(0));
document
.querySelector("#spiral2")
.append(createElement(-1 * (ANIMATION_DURATION / 2)));
});
因?yàn)橛?行文字滾動(dòng),所以這里添加了2個(gè)spiral。
<div id="spiral" class="spiral"></div>
<div id="spiral2" class="spiral"></div>
給 spiral 設(shè)置flex布局,此時(shí)的頁(yè)面效果如下:
.spiral{
display: flex;
align-items: center;
gap: 10px;
position: absolute;
color: #e0ecef;
font-family: "sans-serif";
}
圖片
讓文字動(dòng)起來(lái)
這里的動(dòng)畫基于CSS Houdini @property實(shí)現(xiàn),首先定義一個(gè)自定義屬性--angle,接受角度值,初始值為0度。
@property --angle {
syntax: '<angle>';
initial-value: 0deg;
inherits: false;
}
設(shè)置關(guān)鍵幀動(dòng)畫,修改定義的--angle屬性從0度旋轉(zhuǎn)到360度。
@keyframes spiral {
0% { --angle: 0deg; }
100% { --angle: 360deg; }
}
給每個(gè)文字的增加animation動(dòng)畫關(guān)聯(lián)定義的關(guān)鍵幀動(dòng)畫spiral。
.character{
transform: translateY(calc(sin(var(--angle)) * 100px)) scale(calc(cos(var(--angle)) * 0.5 + 0.5));
animation: spiral 4s linear infinite;
}
重點(diǎn)代碼transform變換,使用transform屬性結(jié)合calc函數(shù)和三角函數(shù)來(lái)實(shí)現(xiàn)Y軸的正弦波形偏移和縮放效果。
同時(shí)在動(dòng)畫中應(yīng)用了前面定義的spiral動(dòng)畫。結(jié)合這兩個(gè)函數(shù),transform 屬性效果如下:
- Y 軸位移: 元素根據(jù) --angle 的值在 Y 軸上上下移動(dòng),形成波動(dòng)效果。
- 縮放效果: 元素的大小根據(jù) --angle 的值進(jìn)行動(dòng)態(tài)縮放,形成從小到大或從大到小的變化。
此時(shí)的動(dòng)畫效果:
圖片
螺旋滾動(dòng)
此時(shí)我們的文字已經(jīng)滾動(dòng)起來(lái)了,只需要最后一步關(guān)鍵的代碼就可以實(shí)現(xiàn)螺旋滾動(dòng)效果,仔細(xì)看原始效果就能發(fā)現(xiàn)其實(shí)每個(gè)文字滾動(dòng)的動(dòng)畫軌跡都是一樣的,唯一的區(qū)別就是執(zhí)行的動(dòng)畫延遲時(shí)間不同,形成了一個(gè)波動(dòng)起伏的效果。
增加延遲動(dòng)畫CSS,由于我們的文字是通過(guò)JS創(chuàng)建的,所以需要在 createElement 中增加以下代碼即可,根據(jù)動(dòng)畫持續(xù)時(shí)間和當(dāng)前文字索引計(jì)算延遲時(shí)間:
div.style.animationDelay = `-${i * (ANIMATION_DURATION / 16) - offset}ms`
由于 --angle 設(shè)置了關(guān)鍵幀動(dòng)畫,是一個(gè)動(dòng)態(tài)變化的變量,這段代碼會(huì)使得元素在頁(yè)面上呈現(xiàn)出螺旋或波動(dòng)的動(dòng)畫效果,增強(qiáng)視覺(jué)吸引力。
此時(shí)我們的動(dòng)畫效果基本就完成了,如下所示:
圖片
兼容火狐
由于Firefox不支持@property動(dòng)畫,原作者寫了火狐兼容代碼,使用JavaScript來(lái)實(shí)現(xiàn)動(dòng)畫效果。
定義一個(gè)animation動(dòng)畫函數(shù),使用 requestAnimationFrame 方法實(shí)現(xiàn)平滑的動(dòng)畫效果。
const animation = () => {
ANGLE -= 1;
//...
requestAnimationFrame(animation);
};
在動(dòng)畫函數(shù)中遍歷所有文字元素來(lái)設(shè)置動(dòng)畫。
document.querySelectorAll(".spiral *").forEach((el, i) => {
// ...
});
計(jì)算Y軸偏移和縮放,使用三角函數(shù)計(jì)算每個(gè)元素的Y軸偏移量和縮放比例:
const translateY = Math.sin(ANGLE * (Math.PI / 120)) * 100;
const scale = Math.cos(ANGLE * (Math.PI / 120)) * 0.5 + 0.5;
設(shè)置動(dòng)畫延遲,根據(jù)元素索引和數(shù)據(jù)屬性data-offset計(jì)算動(dòng)畫的延遲時(shí)間。
const offset = parseInt(el.dataset.offset);
const delay = i * (ANIMATION_DURATION / 16) - offset;
最后動(dòng)態(tài)設(shè)置CSS變換屬性transform來(lái)應(yīng)用Y軸偏移和縮放。在定時(shí)器中使用delay延遲時(shí)間執(zhí)行動(dòng)畫。
setTimeout(() => {
el.style.transform = `translateY(${translateY}px) scale(${scale})`;
}, delay);
火狐瀏覽器執(zhí)行動(dòng)畫函數(shù)。
let isFirefox = typeof InstallTrigger !== 'undefined';
if(isFirefox){
animation();
}
最后
通過(guò)結(jié)合 JavaScript 和 CSS,我們成功實(shí)現(xiàn)了一個(gè)動(dòng)態(tài)的螺旋文字滾動(dòng)特效。該特效不僅展示了字符的動(dòng)態(tài)變化,還通過(guò)延遲時(shí)間結(jié)合動(dòng)畫效果增強(qiáng)了視覺(jué)吸引力。本質(zhì)實(shí)現(xiàn)這個(gè)效果是不需要 JavaScript,為了兼容火狐和動(dòng)態(tài)創(chuàng)建文案DOM才使用了相關(guān) JavaScript。有興趣的可以嘗試使用純CSS實(shí)現(xiàn)這個(gè)炫酷的螺旋文字滾動(dòng)特效。