漸變邊框文字效果?CSS 輕鬆拿捏!

ChokCoco發表於2024-07-20

今天,有個群友問了我這麼一個問題,如果不想切圖,是否有辦法實現帶漸變邊框的字型效果?如下所示:

本文,就將嘗試一下,在 CSS 中,我們可以如何儘可能的實現這種漸變邊框字型效果。

元素疊加

首先,比較容易想到的寫法是透過元素疊加實現。

  1. 元素本身實現文字效果本身
  2. 透過元素的偽元素,配合 background-clip: text 實現漸變文字,並且透過 transform 或者設定大幾號的文字,實現漸變字型
  3. 將(1)(2)進行疊加

我們嘗試一下這種方式:

<div data-text="4"></div>
div {
    position: relative;
    width: 300px;
    height: 150px;
    font-size: 100px;
    text-align: center;
    font-weight: bold;

    &::before,
    &::after {
        content: attr(data-text);
        position: absolute;
        inset: 0;
        color: #000;
    }
    
    &::before {
        transform: scale(1.1);
        background: linear-gradient(cyan, #fc0);
        background-clip: text;
        color: transparent;
    }
}

這裡,我們讓 before 偽元素after 偽元素 兩個偽元素進行具體內容的展示,after 偽元素 只展示具體的文字,字號為 100px,而before 偽元素放大一點點後疊加在另外一個偽元素下面,效果如下:

可以看到,這種方式,邊框並不均勻。

而且,如果字數更多,效果更差:

所以,透過疊加實現,顯然不可取。

透過 SVG feMorphology 濾鏡實現

到這裡,我又想到,在之前,寫過的兩篇文章:

  • CSS 奇技淫巧 | 巧妙實現文字二次加粗再加邊框
  • 有意思!不規則邊框的生成方案

我們藉助了 SVG 濾鏡能夠實現對元素的腐蝕(變薄)或擴張(加粗)。

看看原理,feMorphology 為形態濾鏡,它的輸入源通常是圖形的 alpha 通道,用來它的兩個操作可以使源圖形腐蝕(變薄)或擴張(加粗)。

使用屬性 operator 確定是要腐蝕效果還是擴張效果。使用屬性 radius 表示效果的程度,可以理解為筆觸的大小。

  • operator:erode 腐蝕模式,dilate 為擴張模式,預設為 erode
  • radius:筆觸的大小,接受一個數字,表示該模式下的效果程度,預設為 0

我們將這個濾鏡簡單的應用到文字上看看效果:

<div class="g-text">
    <p>Normal Text</p>
    <p class="dilate">Normal Text</p>
    <p class="erode">Normal Text</p>
</div>

<svg width="0" height="0">
    <filter id="dilate">
        <feMorphology in="SourceAlpha" result="DILATED" operator="dilate" radius="3"></feMorphology>
    </filter>
    <filter id="erode">
        <feMorphology in="SourceAlpha" result="ERODE" operator="erode" radius="1"></feMorphology>
    </filter>
</svg>
p {
    font-size: 64px;
}
.dilate {
    filter: url(#dilate);
}
.erode {
    filter: url(#erode);
}

效果如下:最左邊的是正常文字,中間的是擴張的模式,右邊的是腐蝕模式,看看效果,非常好理解:

如果能理解到這一點,我們可以嘗試:

  1. 利用 background-clip: text 實現漸變文字
  2. 利用 SVG feMorphology 的腐蝕模式,實現被細化的文字
  3. 將兩者疊加起來

程式碼如下:

<div data-text="123/678"></div>
<div data-text="123/678"></div>
<div data-text="123/678"></div>
<svg width="0" height="0">
    <filter id="outline">
        <feMorphology in="SourceAlpha" result="ERODE" operator="erode" radius="2"></feMorphology>
        <feFlood flood-color="#fff" flood-opacity="1" result="flood"></feFlood>
        <feComposite in="flood" in2="ERODE" operator="in" result="OUTLINE"></feComposite>
        <feMerge>
            <feMergeNode in="OUTLINE" />
        </feMerge>
    </filter>
</svg>

div {
    position: relative;
    width: 100vw;
    height: 150px;
    font-size: 120px;
    font-weight: bold;
    text-align: center;
    
    &::before,
    &::after {
        content: attr(data-text);
        position: absolute;
        inset: 0;
    }
    &::before {
        color: transparent;
        background: linear-gradient(0deg, #da00ff, #2a79b7, #7e3eff);
        background-clip: text;
    }
    &::after {
        filter: url(#outline);
    }
}
div:nth-child(2) {
    font-family: 'Cherry Bomb One', cursive;
    font-size: 90px;
}
div:nth-child(3) {
    font-family: 'Darumadrop One', cursive;
    font-size: 150px;
}

基於此,看看效果,這裡我嘗試了 3 種不同的字型:

看著還是挺不錯的,利用 SVG 能夠使源圖形腐蝕(變薄)或擴張(加粗)的能力,我們巧妙的實現了文字的漸變邊框效果。

完整的 DEMO,你可以戳這裡:CodePen Demo -- SVG 實現漸變邊框字型

文字邊框 -webkit-text-stroke

結束了嗎?還沒有。一開始我就有想過使用 -webkit-text-stroke 來實現。

但是轉念一想,認為 -webkit-text-stroke 無法實現漸變邊框,並且它需要使用 -webkit- 字首,可能會存在相容問題,結果在討論的過程中,牛逼的群友給出了使用 -webkit-text-stroke 實現的方式:

<div class="wrapper">
  <span class="text" data-text="1234567890"></span>
  <span class="text" data-text="我能吞下玻璃而不傷身體"></span>
</div>
.wrapper {
  position: relative;
  font-size: 128px;
  
  --stroke-width: 12px;
  --background-gradient: linear-gradient(red 0%, green 100%);
  --text-gradient: linear-gradient(white 0%, cyan 100%);
}

.text {
  position: relative;
}
.text::before,
.text::after {
  content: attr(data-text);
  display: block;
  background-clip: text;
  color: transparent;
}
.text::before {
  position: absolute;
  inset: 0;
  background-image: var(--background-gradient);
  -webkit-text-stroke: var(--stroke-width);
}
.text::after {
  position: relative;
  z-index: 1;
  background-image: var(--text-gradient);
}

-webkit-text-stroke 解法思路本質上也是用的它的背景色,使用了 stroke 的偽元素只是為了讓其字更大一圈,從而背景色可以露出來。

並且,-webkit-text-stroke 的邊框顏色,可以支援直接設定漸變色,如此一來,我們就得到非常完美的效果:

並且,從 CanIUse - text-stroke,到今天,-webkit-text-stroke 的相容性已經非常好了:

我們完全可以放心使用 -webkit-text-stroke 設定文字的各種型別邊框效果。

完整的 DEMO,你可以戳這裡:CodePen Demo -- CSS text stroke with gradient By Rex Zeng

最後

簡單總結一下,綜上所述,其實 -webkit-text-stroke 是最簡單最便捷的實現漸變文字邊框的方式。當然,SVG 方法也有其優勢,如果需要多重邊框效果,甚至是多重漸變文字邊框效果,此時,SVG 會更為強大。

好了,本文到此結束,希望本文對你有所幫助 😃

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

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

相關文章