基本概念總覽:如何建構拆分字母和字詞動畫。
在本文中,我想分享一些想法,說明如何解決網頁分割文字動畫和互動問題,這些方法不僅精簡、無障礙,而且適用於各種瀏覽器。試用示範。
如果您比較喜歡看影片,可以觀看這篇貼文的 YouTube 版本:
總覽
分割文字動畫的效果非常驚人。本文僅初步探討動畫的潛力,但確實提供了建構基礎。目標是逐步建立動畫。文字預設應可供閱讀,並在上方建立動畫。分割文字動作效果可能會過於誇張,甚至造成干擾,因此只有在使用者不排斥動作時,我們才會操控 HTML 或套用動作樣式。
以下概略說明工作流程和結果:
以下是我們預期的條件式結果預覽:
如果使用者偏好減少動態效果,我們會保留 HTML 文件,不加入任何動畫。如果動作沒問題,我們就會將影片切成片段。以下是 JavaScript 依字母分割文字後的 HTML 預覽。
準備動作條件
這項專案的 CSS 和 JavaScript 會使用方便取得的 @media
(prefers-reduced-motion: reduce) 媒體查詢。這項媒體查詢是決定是否分割文字的主要條件。CSS 媒體查詢會用於保留轉場和動畫,而 JavaScript 媒體查詢則用於保留 HTML 操控。
準備 CSS 條件
我使用 PostCSS 啟用媒體查詢第 5 級的語法,以便將媒體查詢布林值儲存至變數:
@custom-media --motionOK (prefers-reduced-motion: no-preference);
準備 JS 條件
在 JavaScript 中,瀏覽器提供檢查媒體查詢的方法,我使用解構,從媒體查詢檢查中擷取布林值結果並重新命名:
const {matches:motionOK} = window.matchMedia(
'(prefers-reduced-motion: no-preference)'
)
接著,我可以測試 motionOK,並在使用者未要求減少動態效果時,才變更文件。
if (motionOK) {
// document split manipulations
}
我可以使用 PostCSS 啟用巢狀草稿 1 的 @nest 語法,檢查相同的值。這樣一來,我就能將動畫的所有邏輯和樣式需求,集中儲存在一個地方:
letter-animation {
@media (--motionOK) {
/* animation styles */
}
}
有了 PostCSS 自訂屬性和 JavaScript 布林值,我們就可以視情況升級效果。接下來,我會詳細說明如何使用 JavaScript 將字串轉換為元素。
分割文字
無法使用 CSS 或 JS 為文字字母、字詞、行等個別加上動畫。 為了達到這個效果,我們需要方塊。如要為每個字母加上動畫,每個字母都必須是元素。如果想為每個字詞加上動畫,則每個字詞都必須是元素。
- 建立 JavaScript 公用函式,將字串分割成元素
- 調度這些公用程式的使用
拆分字母公用函式
建議您先從一個函式開始,這個函式會接收字串,並傳回陣列中的每個字母。
export const byLetter = text =>
[...text].map(span)
ES6 的展開語法確實有助於快速完成這項工作。
分割字詞公用函式
這個函式與拆分字母類似,會接收字串,並在陣列中傳回每個字詞。
export const byWord = text =>
text.split(' ').map(span)
JavaScript 字串的 split() 方法可讓我們指定要切片的字元。我傳遞了空白字元,表示字詞之間有空格。
建立方塊公用函式
這個效果需要為每個字母建立方塊,我們在這些函式中看到 map() 是透過 span() 函式呼叫。以下是 span() 函式。
const span = (text, index) => {
const node = document.createElement('span')
node.textContent = text
node.style.setProperty('--index', index)
return node
}
請務必注意,系統會使用陣列位置設定名為 --index 的自訂屬性。雖然有字母動畫的方塊很棒,但在 CSS 中使用索引似乎是個小小的補充,但影響很大。其中最值得注意的是交錯。我們可以使用 --index 偏移動畫,呈現交錯效果。
公用程式結論
完整的 splitting.js 模組:
const span = (text, index) => {
const node = document.createElement('span')
node.textContent = text
node.style.setProperty('--index', index)
return node
}
export const byLetter = text =>
[...text].map(span)
export const byWord = text =>
text.split(' ').map(span)
接下來,請匯入並使用這些 byLetter() 和 byWord() 函式。
分割自動化調度管理
分割公用程式準備就緒後,請按照下列步驟整合所有內容:
- 找出要分割的元素
- 分割字串,並以 HTML 取代文字
接著,CSS 會接手並為元素/方塊加上動畫效果。
尋找元素
我選擇使用屬性和值來儲存所需動畫和文字分割方式的相關資訊。我喜歡將這些宣告式選項放入 HTML。split-by 屬性用於 JavaScript,可尋找元素並為字母或字詞建立方塊。CSS 會使用 letter-animation 或 word-animation 屬性,指定子元素並套用轉換和動畫。
以下是示範這兩個屬性的 HTML 範例:
<h1 split-by="letter" letter-animation="breath">animated letters</h1>
<h1 split-by="word" word-animation="trampoline">hover the words</h1>
從 JavaScript 尋找元素
我使用 CSS 選取器語法來檢查屬性是否存在,藉此收集要分割文字的元素清單:
const splitTargets = document.querySelectorAll('[split-by]')
從 CSS 尋找元素
我還在 CSS 中使用屬性存在選取器,為所有字母動畫提供相同的基本樣式。稍後,我們將使用屬性值新增更具體的樣式,以達到效果。
letter-animation {
@media (--motionOK) {
/* animation styles */
}
}
就地分割文字
對於在 JavaScript 中找到的每個分割目標,我們會根據屬性值分割其文字,並將每個字串對應至 <span>。接著,我們可以使用建立的方塊取代元素文字:
splitTargets.forEach(node => {
const type = node.getAttribute('split-by')
let nodes = null
if (type === 'letter') {
nodes = byLetter(node.innerText)
}
else if (type === 'word') {
nodes = byWord(node.innerText)
}
if (nodes) {
node.firstChild.replaceWith(...nodes)
}
})
自動化調度管理結論
index.js完成:
import {byLetter, byWord} from './splitting.js'
const {matches:motionOK} = window.matchMedia(
'(prefers-reduced-motion: no-preference)'
)
if (motionOK) {
const splitTargets = document.querySelectorAll('[split-by]')
splitTargets.forEach(node => {
const type = node.getAttribute('split-by')
let nodes = null
if (type === 'letter')
nodes = byLetter(node.innerText)
else if (type === 'word')
nodes = byWord(node.innerText)
if (nodes)
node.firstChild.replaceWith(...nodes)
})
}
這段 JavaScript 的英文解讀如下:
- 匯入一些輔助公用函式。
- 確認使用者是否能接受動態效果,如果不行,則不執行任何操作。
- 針對要分割的每個元素。
- 根據他們希望的分組方式進行分組。
- 將文字替換為元素。
分割動畫和轉場效果
上述分割文件操作,可讓您使用 CSS 或 JavaScript 建立多種潛在動畫和效果。本文底部提供一些連結,可協助您激發分割潛力。
現在就來展現你的實力吧!我會分享 4 個 CSS 驅動的動畫和轉場效果。🤓
拆分字母
我發現下列 CSS 有助於建立分割字母效果。我將所有轉場和動畫放在動作媒體查詢後方,然後為每個新的子字母 span 提供顯示屬性,以及處理空白字元的樣式:
[letter-animation] > span {
display: inline-block;
white-space: break-spaces;
}
空白字元樣式很重要,因為這樣一來,只有一個空格的 span 就不會被版面配置引擎收合。現在來看看有狀態的有趣內容。
轉換分割字母範例
這個範例使用 CSS 轉場效果來分割文字。使用轉場效果時,我們需要為引擎提供狀態,以便在狀態之間建立動畫,我選擇了三個狀態:未懸停、懸停在句子上、懸停在字母上。
當使用者將滑鼠游標懸停在句子 (也就是容器) 上時,我會縮小所有子項,就像使用者將子項推得更遠一樣。接著,當使用者將滑鼠游標懸停在字母上時,我會將字母移到前方。
@media (--motionOK) {
[letter-animation="hover"] {
&:hover > span {
transform: scale(.75);
}
& > span {
transition: transform .3s ease;
cursor: pointer;
&:hover {
transform: scale(1.25);
}
}
}
}
範例:為分割字母加上動畫
本例使用預先定義的 @keyframe 動畫,讓每個字母無限動畫,並利用內嵌自訂屬性索引建立交錯效果。
@media (--motionOK) {
[letter-animation="breath"] > span {
animation:
breath 1200ms ease
calc(var(--index) * 100 * 1ms)
infinite alternate;
}
}
@keyframes breath {
from {
animation-timing-function: ease-out;
}
to {
transform: translateY(-5px) scale(1.25);
text-shadow: 0 0 25px var(--glow-color);
animation-timing-function: ease-in-out;
}
}
分割字詞
在這些範例中,Flexbox 是容器類型,可有效運用 ch 單位做為適當的間隔長度。
word-animation {
display: inline-flex;
flex-wrap: wrap;
gap: 1ch;
}
轉場分割字詞範例
在這個轉場範例中,我再次使用懸停效果。由於效果一開始會隱藏內容,直到使用者將滑鼠游標懸停在內容上,因此我確保只有在裝置支援懸停功能時,才會套用互動和樣式。
@media (hover) {
[word-animation="hover"] {
overflow: hidden;
overflow: clip;
& > span {
transition: transform .3s ease;
cursor: pointer;
&:not(:hover) {
transform: translateY(50%);
}
}
}
}
動畫分割字詞範例
在這個動畫範例中,我再次使用 CSS @keyframes,在一般文字段落上建立交錯的無限動畫。
[word-animation="trampoline"] > span {
display: inline-block;
transform: translateY(100%);
animation:
trampoline 3s ease
calc(var(--index) * 150 * 1ms)
infinite alternate;
}
@keyframes trampoline {
0% {
transform: translateY(100%);
animation-timing-function: ease-out;
}
50% {
transform: translateY(0);
animation-timing-function: ease-in;
}
}
結論
現在你知道我是怎麼做的了,你會怎麼做呢?🙂
讓我們嘗試各種方法,瞭解所有建構網頁的方式。建立 Codepen 或自行託管示範,並在 X 上標記我,我就會將其新增至下方的「社群重混」部分。
來源
更多示範和靈感
社群重混
- CodeSandbox 上 gnehcwu 的
<text-hover>網頁元件