前言
我們在 css 裏可以直接使用 border
屬性指定元素的邊框,但這樣的方法具有侷限性,就是隻能添加單色的邊框,如果需要給元素添加漸變的邊框,又該如何實現呢?
利用 border-image
我們可以使用 border-image 和 linear-gradient() 實現漸變的邊框。
<template>
<div :class="$style.btn">
<slot>button</slot>
</div>
</template>
.btn {
display: inline-flex;
align-items: center;
justify-content: center;
cursor: pointer;
user-select: none;
border: 4px solid transparent;
border-image: linear-gradient(#e66465, #9198e5);
padding: 8px 16px;
font-size: 32px;
}
效果如下圖所示:
這樣就完成了基本的漸變邊框,但這種方法並不能支持圓角屬性,除非我們直接使用帶圓角的圖片。
利用 background
CSS SECRETS 中第二章第八節提到,可以利用疊加的背景圖片去模擬邊框效果,利用這一思想,我們在漸變的背景之上疊加一個原有的背景,就能達到我們想要的效果,而且因爲利用的是 background
,所以圓角屬性也能得到支持,一舉兩得。
.btn {
border-radius: 8px; /* 圓角屬性測試 */
background-image: linear-gradient(#eee, #eee), /* 底色,即原有的背景 */
linear-gradient(#e66465, #9198e5); /* 模擬漸變邊框 */
background-clip: padding-box, border-box;
background-origin: border-box;
}
說明:
- 因爲我們需要將底色覆蓋在漸變背景之上,層級最高,所以底色背景是
background-image
的第一項,漸變背景爲第二項。- 由於是模擬邊框效果,所以底色的繪製區域爲
padding-box
,漸變背景的繪製區域爲border-box
。- 上面所說的覆蓋背景,其實指的是覆蓋背景區域,而元素的背景區域是由
background-origin
屬性來決定的,默認值是padding-box
,故默認情況下,漸變背景是填不滿整個元素的,需要改爲border-box
。
效果如下:
這樣我們就實現了漸變邊框的效果,且支持圓角屬性。
動態的漸變邊框
既然漸變邊框是背景模擬出來的,那我們也可以將線性漸變改爲圓錐漸變(conic-gradient),這樣就有了彩虹色的邊框,當然這需要瀏覽器的支持。
.btn {
background-image: linear-gradient(#eee, #eee),
conic-gradient(#ff0000, #ffff00, #00ff00, #00ffff, #0000ff, #ff00ff, #ff0000);
}
效果如下:
如果我們想讓邊框旋轉起來,我們可以先捨棄上面的解決方案,而是用兩個元素,一個元素充當漸變背景,一個元素覆蓋到背景上面,然後兩者做反向的旋轉動畫即可,但我們偏不這麼做,就是要用一個元素做到旋轉效果,該如何做呢?
其實我們可以利用 CSS 自定義屬性及 @keyframe
去實現,首先定義6個基本顏色構成一個數組,然後在動畫的每一幀,進行顏色數組的左移操作,就能實現旋轉效果。
scss 代碼如下:
$colors: (#ff0000), (#ffff00), (#00ff00), (#00ffff), (#0000ff), (#ff00ff);
$colorSize: length($colors);
@function getIndex($len, $index) {
@if $index > $len {
@return $index - $len;
}
@return $index;
}
.btn {
@for $i from 1 through $colorSize {
#{--color + $i}: nth($colors, $i);
}
background-image: linear-gradient(#eee, #eee),
conic-gradient(var(--color1), var(--color2), var(--color3), var(--color4), var(--color5), var(--color6), var(--color1));
animation: rotate 5s linear infinite;
}
@keyframes rotate {
@for $i from 1 through $colorSize {
#{$i * 100% / $colorSize} {
@for $j from 1 through $colorSize {
#{--color + $j}: nth($colors, getIndex($colorSize, $i + $j));
}
}
}
}
效果如下:
可以看到動畫是一幀一幀的而不是平滑的,這是因爲自定義屬性本身是不能動畫化的,不過現在有了css houdini,這樣我們就能手動註冊自定義屬性,使得自定義屬性可以動畫化。
增加 js:
const colors = [
'#ff0000',
'#ffff00',
'#00ff00',
'#00ffff',
'#0000ff',
'#ff00ff',
];
colors.forEach((color, index) => {
CSS.registerProperty({
name: `--color${index + 1}`,
syntax: '<color>',
initialValue: color,
inherits: true,
});
});
增加 scss:
.btn {
background-size: 200% 200%;
}
效果如下:
這樣就由一幀一幀的動畫變成了平滑的動畫,把 background-size
設置成 200% 200%
,可以使動畫看起來更舒服。
注:
conic-gradient
和css houdini
都需要瀏覽器支持,本文代碼在 chrome 71 可完美運行,代碼可至 github 查看。
技術總結
我們可以利用 background-clip
和 background-origin
去完成漸變邊框的需求,利用 CSS.registerProperty
使得自定義屬性也能夠和其他屬性一樣運行在動畫中。
其實我們還可以使用 clip-path
對漸變背景的顯示區域進行裁剪,從而也模擬出漸變邊框的效果,但這種方案對圓角屬性的支持也不算太好,故本文暫不討論該方案。
本文如有紕漏之處,還請各位大神指出,有其他問題也可以在評論中提出,謝謝大家。