奇思妙想 CSS 文字動畫

ChokCoco發表於2021-03-08

之前有些過兩篇關於字型的文章,是關於如何定義字型的:

本文將會和這篇 -- CSS 奇思妙想邊框動畫類似,講一些文字效果,利用不同的屬性搭配,實現各式各樣的文字動效。

Google Font

在寫各種 DEMO 的時候,有的時候一些特殊的字型能更好的體現動畫的效果。這裡講一個快速引入不同格式字型的小技巧。

就是 Google Font 這個網站,上面有非常多的不同的開源字型:

image

當我們相中了一個我們喜歡的字型,它也提供了非常快速的便捷的引入方式。選中對應的字型,選擇 +Select this style,便可以通過 link@import 兩種方式引入:

image

使用 link 標籤引入:

<link rel="preconnect" href="https://fonts.gstatic.com">
<link href="https://fonts.googleapis.com/css2?family=Source+Code+Pro:wght@200&display=swap" rel="stylesheet">

OR,在 CSS 程式碼中,使用 @import 引入:

<style>
@import url('https://fonts.googleapis.com/css2?family=Source+Code+Pro:wght@200&display=swap');
</style>

上述兩種方式內部其實都是使用的 @font-face 進行了字型的定義。

我們可以通過 @font-face 快速宣告指定一個自定義字型。類似這樣:

@font-face {
  font-family: "Open Sans";
  src: url("/fonts/OpenSans-Regular-webfont.woff2") format("woff2"),
       url("/fonts/OpenSans-Regular-webfont.woff") format("woff");
}

這樣,利用 Google Font,我們就可以便捷的享受各種字型了。

我在我的個人專案或者一些 DEMO 中,需要一些藝術字型或者特殊字型展示不一樣的效果時,經常會使用這種方式。而至於在業務中,是否需要引入一些特殊字型,就見仁見智了。


接下來,就會分門別類的看看,字型在 CSS 中,和不同是屬性相結合,能夠鼓搗出什麼樣的效果。

文字與陰影

通過將字型與字型陰影 text-shadow,相結合,陰影的不同運用方式,產生不一樣的效果。

我們通過一系列 Demo 來看看。

長陰影文字效果

通過多層次,顏色逐漸變化(透明)的陰影變化,可以生成長陰影:

div {
  text-shadow: 0px 0px #992400, 1px 1px rgba(152, 36, 1, 0.98), 2px 2px rgba(151, 37, 2, 0.96), 3px 3px rgba(151, 37, 2, 0.94), 4px 4px rgba(150, 37, 3, 0.92), 5px 5px rgba(149, 38, 4, 0.9), 6px 6px rgba(148, 38, 5, 0.88), 7px 7px rgba(148, 39, 5, 0.86), 8px 8px rgba(147, 39, 6, 0.84), 9px 9px rgba(146, 39, 7, 0.82), 10px 10px rgba(145, 40, 8, 0.8), 11px 11px rgba(145, 40, 8, 0.78), 12px 12px rgba(144, 41, 9, 0.76), 13px 13px rgba(143, 41, 10, 0.74), 14px 14px rgba(142, 41, 11, 0.72), 15px 15px rgba(142, 42, 11, 0.7), 16px 16px rgba(141, 42, 12, 0.68), 17px 17px rgba(140, 43, 13, 0.66), 18px 18px rgba(139, 43, 14, 0.64), 19px 19px rgba(138, 43, 15, 0.62), 20px 20px rgba(138, 44, 15, 0.6), 21px 21px rgba(137, 44, 16, 0.58), 22px 22px rgba(136, 45, 17, 0.56), 23px 23px rgba(135, 45, 18, 0.54), 24px 24px rgba(135, 45, 18, 0.52), 25px 25px rgba(134, 46, 19, 0.5), 26px 26px rgba(133, 46, 20, 0.48), 27px 27px rgba(132, 47, 21, 0.46), 28px 28px rgba(132, 47, 21, 0.44), 29px 29px rgba(131, 48, 22, 0.42), 30px 30px rgba(130, 48, 23, 0.4), 31px 31px rgba(129, 48, 24, 0.38), 32px 32px rgba(129, 49, 24, 0.36), 33px 33px rgba(128, 49, 25, 0.34), 34px 34px rgba(127, 50, 26, 0.32), 35px 35px rgba(126, 50, 27, 0.3), 36px 36px rgba(125, 50, 28, 0.28), 37px 37px rgba(125, 51, 28, 0.26), 38px 38px rgba(124, 51, 29, 0.24), 39px 39px rgba(123, 52, 30, 0.22), 40px 40px rgba(122, 52, 31, 0.2), 41px 41px rgba(122, 52, 31, 0.18), 42px 42px rgba(121, 53, 32, 0.16), 43px 43px rgba(120, 53, 33, 0.14), 44px 44px rgba(119, 54, 34, 0.12), 45px 45px rgba(119, 54, 34, 0.1), 46px 46px rgba(118, 54, 35, 0.08), 47px 47px rgba(117, 55, 36, 0.06), 48px 48px rgba(116, 55, 37, 0.04), 49px 49px rgba(116, 56, 37, 0.02), 50px 50px rgba(115, 56, 38, 0);
}

image

當然,多重陰影以及每重的顏色我們很難一個一個手動去寫,在寫長陰影的時候通常需要藉助 SASSLESS 去幫助節省時間:

@function makelongrightshadow($color) {
    $val: 0px 0px $color;

    @for $i from 1 through 50 {
        $color: fade-out(desaturate($color, 1%), .02);
        $val: #{$val}, #{$i}px #{$i}px #{$color};
    }

    @return $val;
}
div {
    text-shadow: makeLongShadow(hsl(14, 100%, 30%));
}

立體陰影文字效果

如果多層陰影,但是顏色變化沒那麼強烈,能夠塑造一種立體的效果。

div {
  text-shadow: 0 -1px 0 #ffffff, 0 1px 0 #2e2e2e, 0 2px 0 #2c2c2c, 0 3px 0 #2a2a2a, 0 4px 0 #282828, 0 5px 0 #262626, 0 6px 0 #242424, 0 7px 0 #222222, 0 8px 0 #202020, 0 9px 0 #1e1e1e, 0 10px 0 #1c1c1c, 0 11px 0 #1a1a1a, 0 12px 0 #181818, 0 13px 0 #161616, 0 14px 0 #141414, 0 15px 0 #121212);
}

image

內嵌陰影文字效果

合理的陰影顏色和背景底色搭配,搭配,可以實現類似內嵌效果的陰影。

div {
  color: #202020;
  background-color: #2d2d2d;
  letter-spacing: .1em;
  text-shadow: -1px -1px 1px #111111, 2px 2px 1px #363636;
}

image

CodePen Demo -- 5 text shadow effects in css3

氖光效果(Neon)

氖光效果,英文名叫 Neon,是我在 Codepen 上看到的最多的效果之一。它的原理非常簡單,卻可以產生非常酷炫的效果。

我們只需要設定 3~n 層陰影效果,每一層的模糊半徑(文字陰影的第三個引數)間隔較大,並且每一層的陰影顏色相同即可。

p {
    color: #fff;
    text-shadow: 
        0 0 10px #0ebeff,
        0 0 20px #0ebeff,
        0 0 50px #0ebeff,
        0 0 100px #0ebeff,
        0 0 200px #0ebeff
}

當然,通常運用 Neon 效果時,背景底色都是偏黑色。

合理運用 Neon 效果,就可以製作非常多有意思的動效。譬如作用於滑鼠 hover 上去的效果:

p {
    transition: .2s;
 
    &:hover {
        text-shadow: 0 0 10px #0ebeff, 0 0 20px #0ebeff, 0 0 50px #0ebeff, 0 0 100px #0ebeff, 0 0 200px #0ebeff;
    }
}

CodePen Demo -- Neon Demo

CodePen 上有一個 2K+ 讚的 DEMO,實現了非常讚的 Neon 效果,可以戳進去看看 CodePen -- Neon Glow

也可以選取適當合適的字型,配合動畫效果,實現一種漸進的亮燈效果:

<p>
  <span id="n">n</span>
  <span id="e">e</span>
  <span id="o">o</span>
  <span id="n2">n</span>
</p>
p:hover span {
  animation: flicker 1s linear forwards;
}
p:hover #e {
  animation-delay: .2s;
}
p:hover #o {
  animation-delay: .5s;
}
p:hover #n2 {
  animation-delay: .6s;
}

@keyframes flicker {
  0% {
    color: #333;
  }
  5%, 15%, 25%, 30%, 100% {
    color: #fff;
    text-shadow: 
      0px 0px 5px var(--color),
      0px 0px 10px var(--color),
      0px 0px 20px var(--color),
      0px 0px 50px var(--color);
      
  }
  10%, 20% {
    color: #333;
    text-shadow: none;
  }
}

截 GIF 圖的幀率不太夠,看著效果不太好,可以點進下面的 DEMO 感受下:

CodePen Demo -- Neon Demo

文字與背景

CSS 中的背景 background,也提供了一些屬性用於增強文字的效果。

background-clip 與文字

背景中有個屬性為 background-clip, 其作用就是設定元素的背景(背景圖片或顏色)的填充規則

box-sizing 的取值非常類似,通常而言,它有 3 個取值,border-boxpadding-boxcontent-box,後面規範新增了一個 background-clip。時至今日,部分瀏覽器仍需要新增字首 webkit 進行使用 -webkit-background-clip

使用了這個屬性的意思是,以區塊內的文字作為裁剪區域向外裁剪,文字的背景即為區塊的背景,文字之外的區域都將被裁剪掉。

看個最簡單的 Demo ,沒有使用 background-clip:text :

<div>Clip</div>

<style>
div {
  font-size: 180px;
  font-weight: bold;
  color: deeppink;
  background: url($img) no-repeat center center;
  background-size: cover;
}
</style>

效果如下:

image

CodePen Demo

使用 background-clip:text

我們稍微改造下上面的程式碼,新增 -webkit-background-clip:text

div {
  font-size: 180px;
  font-weight: bold;
  color: deeppink;
  background: url($img) no-repeat center center;
  background-size: cover;
  background-clip: text;
}

效果如下:

image

CodePen Demo

看到這裡,可能有人就納悶了,這不就是文字設定 color 屬性嘛。

別急,由於文字設定了顏色,擋住了 div 塊的背景,如果將文字設定為透明呢?文字是可以設定為透明的 color: transparent

div {
  color: transparent;
  background-clip: text;
}

效果如下:

image

CodePen Demo

通過將文字設定為透明,原本 div 的背景就顯現出來了,而文字以外的區域全部被裁剪了,這就是 background-clip:text 的作用。

利用 background-clip 圖文搭配

這樣,我們可以選取合適的圖片合適的字型,實現任意風格的文字效果。

image

CodePen Demo -- background-clip: text & Image text

又或者,利用這個效果實現一張創意海報:

利用 background-clip 實現漸變文字

再者,利用這個屬性,也可以輕鬆的實現漸變色的文字:

{
    background: linear-gradient(45deg, #009688, yellowgreen, pink, #03a9f4, #9c27b0, #8bc34a);
    background-clip: text;
}

配合 background-position 或者 filter: hue-rotate(),讓漸變動起來:

{
    background: linear-gradient(45deg, #009688, yellowgreen, pink, #03a9f4, #9c27b0, #8bc34a);
    background-clip: text;
    animation: huerotate 5s infinite;
}

@keyframes huerotate {
    100% {
        filter: hue-rotate(360deg);
    }
}

CodePen Demo -- background-clip: text 文字漸變色

利用 background-clip 給文字增加高光動畫

利用 background-clip, 我們還可以輕鬆的給文字增加高光動畫。

譬如這樣:

其本質也是利用了 background-clip,虛擬碼如下:

<p data-text="Lorem ipsum dolor"> Lorem ipsum dolor </p>
p {
    position: relative;
    color: transparent;
    background-color: #E8A95B;
    background-clip: text;
}
p::after {
    content: attr(data-text);
    position: absolute;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    background-image: linear-gradient(120deg, transparent 0%, transparent 6rem, white 11rem, transparent 11.15rem, transparent 15rem, rgba(255, 255, 255, 0.3) 20rem, transparent 25rem, transparent 27rem, rgba(255, 255, 255, 0.6) 32rem, white 33rem, rgba(255, 255, 255, 0.3) 33.15rem, transparent 38rem, transparent 40rem, rgba(255, 255, 255, 0.3) 45rem, transparent 50rem, transparent 100%);
    background-clip: text;
    background-size: 150% 100%;
    background-repeat: no-repeat;
    animation: shine 5s infinite linear;
}
@keyframes shine {
	0% {
		background-position: 50% 0;
	}
	100% {
		background-position: -190% 0;
	}
}

去掉偽元素的 background-clip: text,就能看懂原理:

CodePen Demo -- shine Text && background-clip

mask 與文字

還有一個與背景相關的屬性 -- mask

之前在多篇文章都提到了 mask,比較詳細的一篇是 -- 奇妙的 CSS MASK,本文不對 mask 的基本概念做過多講解,向下閱讀時,如果對一些 mask 的用法感到疑惑,可以再去看看。

只需要記住核心的,使用 mask 最重要結論就是:新增了 mask 屬性的元素,其內容會與 mask 表示的漸變的 transparent 的重疊部分,並且重疊部分將會變得透明。

利用 mask,我們可以實現各種文字的出場特效:

<div>
    <p>Hello MASK</p>
</div>

核心的 CSS 程式碼:

div {
    mask: radial-gradient(circle at 50% 0%, #000, transparent 30%);
    animation: scale 6s infinite;
}
@keyframes scale {
    0% {
        mask-size: 100% 100%;
    }
    60%,
    100% {
        mask-size: 150% 800%;
    }
}

改變不同的方向,又或者是這樣:

CodePen Demo -- MASK Text Effect

文字與混合模式(mix-blend-mode)及濾鏡(filter)

接下來,就到了非常有意思的混合模式及濾鏡了。這兩個屬性給 CSS 世界增添了非常多的趣味性,活靈活用,會感嘆 CSS 居然如此的強大美妙。

之前有多非常多篇關於混合模式濾鏡的文章,一些基礎的用法就不再贅述。

給文字新增邊框,生成鏤空文字

在 CSS 中,我們可以利用 -webkit-text-stroke,給文字快速的新增邊框,利用這個,可以快速生成鏤空型的文字:

p {
    -webkit-text-stroke: 3px #373750;
}

image

當然,我們看到,用到的屬性 -webkit-text-stroke 帶了 webkit 字首,存在一定的相容性問題。

所以,在更早的時候,我們還會使用 text-shadow,生成鏤空文字。

p {
    text-shadow: 0 0 5px #fff;
}

可以看到,因為使用的是陰影,所以有很明顯的虛化的感覺,存在一定的瑕疵。

還有一種非常繞的方法,利用混合模式加上濾鏡,也能生成鏤空文字。

p {
    position: relative;
    color: #fff;

    &::after {
        content: 'Magic Text';
        position: absolute;
        left: 0;
        top: 0;
        color: #fff;
        mix-blend-mode: difference;
        filter: blur(1px);
    }
}

這裡利用 filter: blur(1px) 生成了一個比原字型稍微大一點點的字型覆蓋在原字型之上,再利用 mix-blend-mode: difference 消除掉了同色的部分,只留下了利用模糊濾鏡多出來的那一部分。

mix-blend-mode: difference: 差值模式(Difference),作用是檢視每個通道中的顏色資訊,比較底色和繪圖色,用較亮的畫素點的畫素值減去較暗的畫素點的畫素值。與白色混合將使底色反相;與黑色混合則不產生變化。

示意動圖如下:

CodePen Demo -- Hollow TEXT EFFECT

利用混合模式,生成漸變色鏤空文字

好,回到上面的 -webkit-text-stroke,拿到了鏤空文字後,我們還可以利用混合模式 mix-blend-mode: multiply 生成漸變色的文字。

mix-blend-mode: multiply: 正片疊底(multiply),將兩個顏色的畫素值相乘,然後除以255得到的結果就是最終色的畫素值。通常執行正片疊底模式後的顏色比原來兩種顏色都深。任何顏色和黑色正片疊底得到的仍然是黑色,任何顏色和白色執行正片疊底則保持原來的顏色不變,而與其他顏色執行此模式會產生暗室中以此種顏色照明的效果。

p {
    position: relative;
    -webkit-text-stroke: 3px #9a9acc;

    &::before{
		content: ' ';
		width: 100%;
		height: 100%;
		position: absolute;
		left: 0;
		top: 0;
		background-image: linear-gradient(45deg, #ff269b, #2ab5f5, #ffbf00);
		mix-blend-mode: multiply;
	}
}

在這裡,mix-blend-mode: multiply 發揮的作用和 mask 非常的類似,我們其實是生成了一幅漸變圖案,但是隻有在文字輪廓內,漸變顏色才會顯現。

當然,上述效果和整體的黑色底色也是有關係的。

示意圖如下:

CodePen Demo -- Hollow TEXT EFFECT

利用混合模式,生成光影效果文字

OK,在上述的基礎上,我們可以繼續疊加混合模式,這次我們利用剩餘的一個 ::after 偽類,再新增一個 mix-blend-mode: color-dodge 混合模式,給文字加上最後的點綴,實現美妙的光影效果。

mix-blend-mode: color-dodge: 顏色減淡模式(Color Dodge),檢視每個通道的顏色資訊,通過降低“對比度”使底色的顏色變亮來反映繪圖色,和黑色混合沒變化。。

核心的虛擬碼:

p {
    position: relative;
    -webkit-text-stroke: 3px #7272a5;

    &::before {
		content: ' ';
		background-image: linear-gradient(45deg, #ff269b, #2ab5f5, #ffbf00);
		mix-blend-mode: multiply;
    }

    &::after {
        content: "";
        position: absolute;
        background: radial-gradient(circle, #fff, #000 50%);
        background-size: 25% 25%;
        mix-blend-mode: color-dodge;
        animation: mix 8s linear infinite;
    }
}

@keyframes mix {
    to {
        transform: translate(50%, 50%);
    }
}

看看效果:

這裡就要感嘆 mix-blend-mode: color-dodge 的神奇了,去掉這個混合模式,其實是這樣的:

CodePen -- Hollow TEXT EFFECT

好,就上面這個效果,還可以繼續嗎?答案是可以的。限於篇幅,本文不再繼續在這個效果上深入,感興趣的可以拿著上面的 DEMO 自己再搗鼓搗鼓。

利用混合模式實現文字與底色反色的效果

這裡還是利用 mix-blend-mode: difference 差值模式,實現一種文字與底色反色的 Title 效果。

mix-blend-mode: difference: 差值模式(Difference),作用是檢視每個通道中的顏色資訊,比較底色和繪圖色,用較亮的畫素點的畫素值減去較暗的畫素點的畫素值。與白色混合將使底色反相;與黑色混合則不產生變化。

程式碼非常的簡單,我們實現一個黑白相間的背景,文字的顏色為白色,配合上差值模式,即可實現黑底上的文字為白色,白底上的文字為黑色的效果。

p  {
    background: repeating-radial-gradient(circle at 200% 200%, #000 0, #000 150px, #fff 150px, #fff 300px);

    &::before {
        content: "LOREM IPSUM";
        color: #fff;
        mix-blend-mode: difference;
    }
}

可以用於一些標題效果:

image

CodePen Demo -- Radial-gradient + Mix-blend-mode

利用混合模式實現動態類抖音風格 Glitch 效果

OK,接下來,我們再嘗試下其他混合模式的搭配。在 CSS 故障藝術 一文中,提到了一種故障藝術。

什麼是故障藝術?我們熟知的抖音的 LOGO 正是故障藝術其中一種表現形式。它有一種魔幻的感覺,看起來具有閃爍、震動的效果,很吸引人眼球。

關鍵點

  • 利用 mix-blend-mode: lighten 混合模式實現兩段文字結構重疊部分為白色
  • 利用元素位移完成錯位移動動畫,形成視覺上的衝擊效果

看看效果:

本文篇幅有點長,程式碼就不上了,完整 DEMO 在這裡:

類抖音 LOGO 文字故障效果

當然,我們也不是一定要使用混合模式去使得融合部分為白色,可以僅僅是使用這個配色效果,基於上面效果的另外一個版本,沒有使用混合模式。

關鍵點

  • 利用了偽元素生成了文字的兩個副本
  • 視覺效果由位移、遮罩、混合模式完成
  • 配色借鑑了抖音 LOGO 的風格

完整 DEMO 在這裡:

CSS文字故障效果

僅僅使用配色沒有使用混合模式的好處在於,對於每一個文字的副本,有了更大的移動距離和可以處理的空間。

Glitch Art 風格的 404 效果

稍微替換一下文字文案為 404,再新增上一些濾鏡效果(hue-rotate()blur())嘿嘿,找到了一個可能實際可用的場景:

效果一:

404

效果二:

404

兩個 404 效果的 Demo 如下:

小技巧,在使用混合模式的時,有的時候,效果不希望和背景混合在一起,可以使用 isolation: isolate 進行隔離。

使用濾鏡生成文字融合效果

你所不知道的 CSS 濾鏡技巧與細節 一文中,介紹了利用濾鏡實現的一種融合效果。

利用了模糊濾鏡疊加對比度濾鏡產生的融合效果

單獨將兩個濾鏡拿出來,它們的作用分別是:

  1. filter: blur(): 給影像設定高斯模糊效果。
  2. filter: contrast(): 調整影像的對比度。

但是,當他們“合體”的時候,產生了奇妙的融合現象。簡單的例子:

CodePen Demo -- filter mix between blur and contrast

利用這個特性,可以實現一些文字融合的效果:

利用這個方法,我們還可以設計一些文字融合的效果:

具體實現你可以看這裡:

CodePen Demo -- word animation | word filter

文字與 SVG

最後,我們再來看看文字與 SVG。

在 SVG 與 CSS 的搭配中,有一類非常適合拿來做動畫的屬性,也就是 stroke-* 相關的幾個屬性,利用它們,我們只需要掌握簡單的 SVG 語法,就可以快速製作相關的線條動畫。

我們利用 SVG 中幾個和邊框、線條相關的屬性,來實現文字的線條動畫,下面羅列一下,其實大部分和 CSS 對比一下非常好理解,只是換了個名字:

  • stroke-width:類比 css 中的 border-width,給 svg 圖形設定邊框寬度;
  • stroke:類比 css 中的 border-color,給 svg 圖形設定邊框顏色;
  • stroke-linejoin | stroke-linecap:設定線段連線處的樣式;
  • stroke-dasharray:值是一組陣列,沒數量上限,每個數字交替表示劃線與間隔的寬度;
  • stroke-dashoffset:則是虛線的偏移量

具體的更深入的介紹,可以看看這篇:【Web動畫】SVG 線條動畫入門

線條文字動畫

接下來,我們利用 stroke-* 相關屬性,實現一個簡單的線條文字動畫。

<svg viewBox="0 0 400 200">
	<text x="0" y="70%"> Lorem </text>
</svg>	
svg text {
	animation: stroke 5s infinite alternate;
	letter-spacing: 10px;
	font-size: 150px;
}
@keyframes stroke {
	0% {
		fill: rgba(72, 138, 20, 0);
		stroke: rgba(54, 95, 160, 1);
		stroke-dashoffset: 25%;
		stroke-dasharray: 0 50%;
		stroke-width: 1;
	}
	70% {
		fill: rgba(72, 138, 20, 0);
		stroke: rgba(54, 95, 160, 1);
		stroke-width: 3;
	}
	90%,
	100% {
		fill: rgba(72, 138, 204, 1);
		stroke: rgba(54, 95, 160, 0);
		stroke-dashoffset: -25%;
		stroke-dasharray: 50% 0;
		stroke-width: 0;
	}
}

動畫的核心就是,利用動態變化文字的 stroke-dasharraystroke-dashoffset 形成視覺上的線條變換,動畫的最後再給文字上色。看看效果:

CodePen Demo -- SVG Text Line Effect

最後

本文介紹了一些我認為比較有意思的文字動畫小技巧,當然 CSS 中還有非常多有意思的文字效果,限於篇幅,不一一展開。

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

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

相關文章