現代 CSS 解決方案:全尺寸的帶圓角的漸變邊框
在之前,我們有一篇介紹帶圓角的漸變邊框的純 CSS 實現的文章:
會有這麼一個話題的本質在於,在過往,想使用純 CSS 實現純粹的,內部透明漸變邊框,是一件非常困難的事情,像是這樣:
這個效果的幾個核心難點:
-
邊框帶漸變色
-
邊框支持設置
border-radius
-
內部支持透明
思考一下,使用 CSS,我們可以如何實現這個效果?
過往比較好的方法
之前有一個比較接近上面的訴求的方法。主要利用了 clip-path
和 border-image
。
clip-path[2],大家應該都非常熟悉了。它可以創建一個只有元素的部分區域可以顯示的剪切區域。區域內的部分顯示,區域外的隱藏。剪切區域是被引用內嵌的 URL 定義的路徑或者外部 SVG 的路徑。
簡而言之,這裏我們只需要在 border-image
的基礎上,再利用 clip-path
裁剪出一個帶圓角的矩形容器即可:
<div class="border-image-clip-path"></div>
.border-image-clip-path {
position: relative;
width: 200px;
height: 100px;
border: 10px solid;
border-image: linear-gradient(45deg, gold, deeppink) 1;
clip-path: inset(0 round 10px);
}
解釋一下:clip-path: inset(0 round 10px)
。
-
clip-path: inset() 是矩形裁剪
-
inset() 的用法有多種,在這裏
inset(0 round 10px)
可以理解爲,實現一個父容器大小(完全貼合,垂直水平居中於父容器)且border-radius: 10px
的容器,將這個元素之外的所有東西裁剪掉(即不可見)。
效果如下:
但是,可以看到上圖的 border-radius
的值比較大,整個邊框的寬度比較粗。
如果我們想得到一條 1px
寬度的漸變邊框,我們嘗試將上面的邊框 CSS 樣式修改一下:
border: 10px solid
--> border: 1px solid
得到如下效果:
由於圓角的原因,利用了 clip-path: inset(0 round 10px)
對圖形進行切割後,元素的四個圓角都被切割掉了!
所以,有沒有一種更好的方式,實現帶圓角的漸變邊框呢?
使用 mask 和 background-clip 巧妙實現帶圓角的漸變邊框
這裏,我們介紹一種更爲巧妙的方法。主要會利用 background-clip
和 mask
兩個核心屬性。
首先,我們利用背景 background
實現一個普通的漸變背景:
<div></div>
div {
position: relative;
width: 140px;
height: 80px;
border-radius: 100px;
background: conic-gradient(#ff00fa, #fe3, #0f3, #ff00fa);
}
利用角向漸變 background: conic-gradient(#ff00fa, #fe3, #0f3, #ff00fa)
,我們得到了這麼一個圖形:
思考一下,如果我們有辦法將圖形中間部分鏤空裁剪,我們不就能得到一個帶圓角的漸變邊框了嗎?
通過一個示意圖,你能很快明白到底是什麼意思:
好,那剩下的問題就轉換爲了:
-
如何裁剪掉一個元素內部的區域,並且能夠控制裁剪區域的大小
-
裁剪區域,與圖形的輪廓是一致的
在 CSS 中想使用裁剪功能,首先想到的肯定是 clip-path
,但是上面的例子已經證明了 clip-path
無法實現細邊框的裁剪,因此,我們需要另尋解法。
而 CSS 中,另外一個與裁剪功能相關的屬性就是 mask
。
不瞭解
mask
的,可以戳我的這幾篇文章看看:奇妙的 CSS MASK[3]、高階切圖技巧!基於單張圖片的任意顏色轉換 [4]
在此處,我們利用 mask
,並且,最爲核心的是,需要配合 mask-composite
,實現圖形輪廓的精確裁剪。
深入理解 mask-composite
什麼是 mask-composite
?
mask-composite[5]: 屬性指定了將應用於同一元素的多個蒙版圖像相互合成的方式。
通俗點來說,他的作用就是,當一個元素存在多重 mask 時,我們就可以運用 -webkit-mask-composite 進行效果疊加。
舉個栗子:
<div class="original"></div>
.original {
background: #000;
mask: radial-gradient(circle at 0 0, #000, #000 200px, transparent 200px);
}
我們用一個 radial-gradient
作爲 mask,切割原本的矩形,得到一個新的圖形。
如果再換一個方向:
<div class="original"></div>
.original {
background: #000;
mask: radial-gradient(circle at 100% 0, #000, #000 200px, transparent 200px);
}
如果我想得到這樣一個效果:
該怎麼做呢?
我們嘗試合併上述兩個 mask 的效果:
.mask {
background: #000;
mask: radial-gradient(circle at 100% 0, #000, #000 200px, transparent 200px),
radial-gradient(circle at 0 0, #000, #000 200px, transparent 200px);
}
效果如下:
與我們想象的不太一樣,這是因爲,兩個 mask 的圖形疊加,就是上述圖形的效果,所以上述效果是沒有問題的。
只是,我們想得到的是兩個 mask 圖形的重疊部分:
這時,我們就可以使用 mask-composite
:
.mask {
background: #000;
mask: radial-gradient(circle at 100% 0, #000, #000 200px, transparent 200px),
radial-gradient(circle at 0 0, #000, #000 200px, transparent 200px);
-webkit-mask-composite: source-in;
}
添加了 -webkit-mask-composite: source-in
後,我們就可以得到兩個 mask 圖形的重疊部分,再基於這個重疊部分作用到整個 mask 遮罩:
CodePen Demo -- mask-composite Demo[6]
-webkit-mask-composite
還可以實現非常多不同的功能,包括但不限於:
-webkit-mask-composite: clear; /*清除,不顯示任何遮罩*/
-webkit-mask-composite: copy; /*只顯示上方遮罩,不顯示下方遮罩*/
-webkit-mask-composite: source-over;
-webkit-mask-composite: source-in; /*只顯示重合的地方*/
-webkit-mask-composite: source-out; /*只顯示上方遮罩,重合的地方不顯示*/
-webkit-mask-composite: source-atop;
-webkit-mask-composite: destination-over;
-webkit-mask-composite: destination-in; /*只顯示重合的地方*/
-webkit-mask-composite: destination-out;/*只顯示下方遮罩,重合的地方不顯示*/
-webkit-mask-composite: destination-atop;
-webkit-mask-composite: xor; /*只顯示不重合的地方*/
看看這張圖,就一目瞭然(圖片源自 CSS mask 實現鼠標跟隨鏤空效果 [7])
理解 background-clip
要實現最終效果,還有一個有意思的細節點需要掌握。那就是理解 backgrund-clip
。
一般我們用 backgrund-clip
比較多的場景是 background-clip: text
,用於將背景圖作用與文字之上。
但是,其實 backgrund-clip
還有幾個與 box-content
類似的取值:
{
background-clip: border-box; // 背景延伸到邊框外沿(但是在邊框之下)
background-clip: padding-box; // 邊框下面沒有背景,即背景延伸到內邊距外沿。
background-clip: content-box; // 背景裁剪到內容區 (content-box) 外沿。
}
什麼意思呢?background-clip
設置元素的背景(背景圖片或顏色)是否延伸到邊框下面。看看下面這張圖(圖片源自:CSS Background Clip[8]),就是對 background-clip
很好的一個闡述:
而本文,我們會用到 content-box
,舉個例子:
<div></div>
div {
width: 140px;
height: 80px;
border-radius: 100px;
border: 1px dashed #000;
background: conic-gradient(#ff00fa, #fe3, #0f3, #ff00fa);
background-clip: content-box;
padding: 10px;
}
效果如下:
可以看到,此時,背景的填充不再是從元素的右上角開始,而是在內容區域,算上了 10px
的 padding 之後,開始繪製。
也就是說,基於 background-clip
,是可以改變元素背景的繪製規則!這一點非常重要。
利用 mask 配合 mask-composite 實現圖形輪廓裁剪
只有在掌握了 mask-composite
和 background-clip
的基礎上,你才能理解下面整個裁剪代碼個核心精髓處。
基於上述講解,我們就可以利用上面的綜合技巧,實現我們最終想要的 -- 帶圓角的漸變邊框。
代碼如下:
<div></div>
div {
position: relative;
width: 140px;
height: 80px;
border-radius: 100px;
background: conic-gradient(#ff00fa, #fe3, #0f3, #ff00fa);
padding: 1px;
-webkit-mask:
linear-gradient(#fff 0 100%) content-box,
linear-gradient(#fff 0 100%);
-webkit-mask-composite: xor;
}
這樣,我們就完美的得到了一個 1px
寬度的帶圓角的漸變邊框,並且,內部是鏤空的:
通過控制上述的 padding: 1px
來控制元素的邊框寬度。
完整的代碼,你可以戳這裏查看:CodePen Demo -- 純 CSS 實現帶圓角的漸變邊框![9]
最後
好了,本文到此結束,希望本文對你有所幫助 :)
如果還有什麼疑問或者建議,可以多多交流,原創文章,文筆有限,才疏學淺,文中若有不正之處,萬望告知。
參考資料
[1]
巧妙實現帶圓角的漸變邊框: https://github.com/chokcoco/iCSS/issues/77
[2]
clip-path: https://developer.mozilla.org/zh-CN/docs/Web/CSS/clip-path
[3]
奇妙的 CSS MASK: https://github.com/chokcoco/iCSS/issues/80
[4]
高階切圖技巧!基於單張圖片的任意顏色轉換: https://github.com/chokcoco/iCSS/issues/189
[5]
mask-composite: https://developer.mozilla.org/en-US/docs/Web/CSS/-webkit-mask-composite
[6]
CodePen Demo -- mask-composite Demo: https://codepen.io/Chokcoco/pen/KKQjxMP
[7]
CSS mask 實現鼠標跟隨鏤空效果: https://segmentfault.com/a/1190000040996523
[8]
CSS Background Clip: https://www.programiz.com/css/background-clip
[9]
CodePen Demo -- 純 CSS 實現帶圓角的漸變邊框!: https://codepen.io/Chokcoco/pen/JjqJqZR
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/2g79GVEGtQAqBwaSNprZLQ