CSS秘密花園: 文本動畫

BerKidston 8年前發布 | 17K 次閱讀 CSS 前端技術

CSS Secrets 》是 @Lea Verou 最新著作,這本書講解了有關于CSS中一些小秘密。是一本CSSer值得一讀的一本書,經過一段時間的閱讀,我、@南北和@彥子一起將在W3cplus發布一系列相關的讀后感,與大家一起分享。

問題

有時候我們想要模擬文本輸入的動畫效果,就是文本一個一個的出現。這種動畫效果特別在科技網站上流行。使用的正確,讓你的網站效果直接提到另一個檔次上。

通常要實現這樣的效果都需要復雜的JavaScript腳本。盡管這只是純粹的演示,使用CSS實現這樣的效果那簡直就是白日做夢。怎么可能呢?

歐洲核子研究中心官網 就使用了這種動畫效果。

解決方案

實現這個動畫思路是包含文本的元素寬度從 0 慢慢過渡(一個字符一個字符)元素內容寬度。你可能意識到這種方法的局限性是什么:它不能在多行文本中運行。值得慶幸的是,大多數時候,只是單行文本上使用這種動畫效果,比如說標題。

另外有一點需要注意的是,動畫的效果隨著時間的增長會有所減弱。動畫持續的時間越短動畫效果越好,用戶體驗也越好;持續時間越長,動畫效果會讓用戶感覺很無聊。綜上所述,即使技術允許使用在長文本上,但應該盡量避免使用在多行文本上。

讓我們開始寫代碼吧,假設我們將這個效果用在 <h1> 的標題上,并且給文本設置等寬字體,代碼如下:

<h1>CSS is awesome!</h1>

我們可以添加一個簡單動畫,寬度從 0 過渡到標題內容的寬度:

@keyframes typing {
    from { width: 0 }
}
h1 {
    width: 7.7em; /* Width of text */
    animation: typing 8s;
}

這非常有意義,對嗎?然而,正如下圖所看到的,這是一個失敗的效果,并不是我們需要的東西:

你可能已經猜到問題所在。你會想起使用 white-space:nowrap; 來防止文本換行,因為寬度會增加,行數變為一行。第二,使用 overflow:hidden; 截取溢出文本。解決了這些問題,我們動畫才可能像是我們需要的,如下圖所示:

  • 顯而易見的問題是動畫是平滑的,但不是一個一個字符的出現。
  • 不太明顯的問題是,到目前為止,使用 em 做為寬度單位,而沒有使用 px ,雖然 em 比 px 更好,但效果仍然不佳。而且寬度為 7.7em 是從哪里來的?又是如何計算出來的呢?

解決第一個問題可以通 steps() 處理,就像前面介紹的逐幀動畫和閃爍動畫一樣。不幸的是,我們需要的步驟是字符串的字符數,這對于動態的文本是完全不可能的。然而,稍后我們將看到,使用一小段JavaScript代碼可以實現。

解決第二個問題可以使用 ch 單位, ch 單位是 CSS3中新引入的一個單位 , 1ch 的大小和字母 o 的寬度相等。新單位最未知的情況之一是因為大多數情況下,并不太在乎元素寬度是相對于字符 o 寬度。然而,等寬字體是一種特殊的字體。等寬字體每個字符的寬度都和字母 o 寬度一樣。因此,在我們示例中寬度就是 15 個字符數的 ch 寬度。

將他們放在一起:

<h1>CSS is awesome!</h1>

@keyframes typing {
    from { 
      width: 0; 
    }
}
h1 {
    width: 15ch; /* Width of text */
    overflow: hidden;
    white-space: nowrap;
    animation: typing 6s steps(15);
}

正如你看到的上圖。現在我們終于看到了預期的動畫效果:我們文本是一個一個字符的出現。然而,它仍然還不完美,難道是哪少了什么嗎?

還有最后一個效果,給字符后面添加閃爍的光標。在上一節中,我們知道如何創建閃爍動畫。可以通過偽元素來創建閃爍光標,并且使用 opacity 屬性,當然偽元素起到的作用也有限,在這個示例中,使用右邊框來替代:

@keyframes typing {
    from { width: 0 }
}
@keyframes caret {
    50% { border-color: transparent; }
}
h1 {
    width: 15ch; /* Width of text */
    overflow: hidden;
    white-space: nowrap;
    border-right: .05em solid;
    animation: typing 6s steps(15),caret 1s steps(1) infinite;
}

注意,不同于文本逐個出現的動畫,光標符需要不停的閃爍(甚至是所有字符都出來了)。因此給動畫設置一個 infinite 關鍵詞,讓他無限次播放。同時,我們沒有指定邊框顏色,主要是讓其自動獲取文本顏色。如下圖所示:

現在我們的動畫作品比較完美了,盡管維護不是很容易:根據不同的內容的字符數要為標題設置不同的樣式。不過使用JavaScript代碼就可以完美的完成這個任務:

$$('h1').forEach(function(h1) {
    var len = h1.textContent.length, s = h1.style;
    s.width = len + 'ch';
    s.animationTimingFunction = "steps("+len+"),steps(1)";
});

就只要這幾行JS代碼,不僅實現了我們要的動畫效果,代碼也易維護。

注意:也可以使用下面的一段JS代碼:

var aH1 = document.getElementsByTagName('h1');
for(var i = 0, len = aH1.length; i < len; i++){
    var textLen = aH1[i].textContent.length, s = aH1[i].style;
    s.width = textLen + 'ch';
    s.animationTimingFunction = "steps("+textLen+"),steps(1)";
}

這是不錯的,瀏覽器不支持CSS動畫會發生什么?從本質上說,他們將忽略所有有關于CSS的 animation 相關的東西,瀏覽器會能識別:

h1 {
    width: 15ch; /* Width of text */
    overflow: hidden;
    white-space: nowrap;
    border-right: .05em solid;
}

瀏覽器不支持動畫效果,會降級處理,上面的是支持 ch 效果,下面的是不支持 ch 單位的效果

正如上圖所看到的,效果好不好主要取決于瀏覽器是否支持 ch 單位。如果你想避免底部那個效果,你可以通過 em 做降級處理。如果你不希望光標字符在最后,你可以改變光標字符動畫中關鍵幀中的 border 屬性,這樣你只會看到一個透明的邊框,如下:

@keyframes caret {
    50% { border-color: currentColor; }
}
h1 {
    /* ... */
    border-right: .05em solid transparent;
    animation: typing 6s steps(15),caret 1s steps(1) infinite;
}

來自: http://www.w3cplus.com/css3/css-secrets/typing-animation.html

 

 本文由用戶 BerKidston 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!