← 圆角三部曲:一个角的二十年 / 渐变描边:让渐变沿着圆角流动 待审核 5 / 5
番外 · gradient border

渐变描边:让渐变沿着圆角流动

三部曲讲的是角本身;这一页讲——而它最难的地方,恰恰还是圆角。原生 border 只接受纯色,想给边框上渐变,第一直觉是 border-image:它确实能把渐变铺到边框上,却完全无视 border-radius,四角立刻变回直角。于是整套「渐变描边」技巧,本质都是在回答同一个问题:怎样让一道渐变,严丝合缝地贴着圆角走?

1 · 问题:渐变与圆角为何相互冲突

border-color 只能是纯色,渐变无从谈起。退而求其次用 border-image: linear-gradient(...),渐变是上去了,但 border-image 把边框区域当成一张九宫格图片来贴,不参与圆角裁剪——所以无论 border-radius 设多大,描边的四角都是直角。右边的 background-clip 双层法则用 border-box 层承载渐变、padding-box 层盖住内芯,渐变只在边框环露出,且天然跟随圆角。拖滑块对比。

border-image 不是不能用,而是它与 border-radius 互斥。规范里 border-image 一旦生效就替换掉常规边框的绘制,圆角裁剪只作用于「常规边框 + 背景」这条路径,管不到贴上去的图。所以只要你既要渐变、又要圆角,就得换思路——把渐变放进背景遮罩,让它走那条会被圆角裁剪的绘制路径。

2 · 两种贴着圆角的静态做法

两种主流写法都能让渐变严格跟随 border-radius背景双层法:把 border 设成透明,背景叠两层——padding-box 那层是纯色内芯、border-box 那层是渐变,渐变只在透明边框处露出。遮罩法:用一个 ::before 铺满渐变,再用两层 maskexclude,只留下边框环。遮罩法更通用(任意渐变、任意形状都对),双层法更简短。切换方案与渐变类型,看右侧 CSS。

遮罩法的核心是 mask-composite: exclude两层 mask:一层裁到 content-box(内芯区域)、一层覆盖整盒;exclude 取「整盒 减去 内芯」= 一圈边框环,渲染就被这个环裁出来。Safari 仍需配 -webkit-mask-composite: xor-webkit-mask 前缀(本页已写)。双层法则不需要任何前缀,但只适合「内芯纯色」的场景——内芯要透出底下内容时,用遮罩法。

3 · 让描边转起来:@property + conic-gradient

若浏览器不支持 @property,conic 会停在起始角不旋转——见本页末的降级方案。

把双层法里的渐变换成 conicgradient(fromvar(angle),)conic-gradient(from var(--angle), \dots ),再让 --angle0deg 转到 360deg,描边就沿圆角流动。关键在 @property:裸自定义属性是字符串,动画引擎不知道怎么补间;用 @property--angle 注册成 <angle> 类型后,它才能像普通角度值一样被 @keyframes 平滑插值。拖滑块改转速,或暂停。

为什么不能直接动画一个普通 --angle?未注册的自定义属性,其值在 CSS 看来只是一段不透明文本,@keyframes 无法在两段文本之间「取中间值」,于是动画会在 0deg360deg 之间瞬间跳变(甚至完全不动)。@propertysyntax: "<angle>" 给了它类型,浏览器据此知道如何插值——这正是 @property 让「动画任意属性」成为可能的根本。prefers-reduced-motion 下本页已自动停转。

4 · 降级:旋转一张超大渐变

@property 较新,不支持时 conic 停在起始角。@property 出现之前,旋转渐变靠的是另一招,且处处可用:外层 overflow: hidden + border-radius 裁出圆角,内部塞一张远大于盒子的渐变层(这里 260%),用 transform: rotate 整张转;再叠一层内芯盖住中间,只留下一圈边框。转的是元素而非渐变的角度,因此不需要可动画的自定义属性。

**降级方案的代价:多两层 DOM、且渐变层必须做得足够大。**盒子是长方形时,旋转中的方形渐变层要能在任意角度都盖满四角,边长得取到对角线以上(本页用 260% 留足余量)。它胜在兼容性——不依赖 @property / conic-gradient 的可动画性,只用最古老的 transform: rotateoverflow: hidden 圆角裁剪,这本身正是border-radius那页讲过的能力。

5 · 回到主线

切图、到border-radius、再到corner-shape,三部曲让「角」一步步从图片资产变成声明式样式。这页则是「边」的同一个故事:渐变描边的全部工程,都是为了让一道颜色沿着那条圆角轮廓流动——角与边,最终都收束到同一条圆角曲线上。