CSS mask 与 切图艺术

作为一名 CSSer,我并不反对"切图"。

相反,有些地方还是更推荐的,特别是那些奇形怪状的 UI,合理的"切图"可以极大地提高布局效率,当然,这里需要一点点技巧,将"切图"和 CSS 现有能力结合起来,一起学习一下吧

一、"切图"的局限性

传统的"切图"简单暴力,但往往缺少适应性。

适应性一般有两种,一是尺寸自适应 ,二是颜色可以自定义

举个例子,有这样一个优惠券样式

关于这类样式实现技巧,之前在这篇文章中有详细介绍:

CSS 实现优惠券的技巧

不过这里略微不一样的地方是,两个凹陷处都是平滑处理的

单纯实现内凹圆角已经很费劲了,现在还来个平滑圆角?是时候祭出最后大招了--切图。

但是,切图真的能解决吗?假设已经得到了这样一张图片

css 复制代码
css
复制代码
div{
  background: url(a.png) 0/100% 100%;
}

下面是这张图片在不同尺寸下的表现

除非整个布局的尺寸是完全固定的,否则都会有不同程度的拉伸情况,这是视觉最为忌讳的。

另外,整张图是固定的,也无法直接修改背景色,如果有多种状态,还需要保存多份

css 复制代码
css
复制代码
.div1{
  background: url(a.png) 0/100% 100%;
}
.div2{
  background: url(b.png) 0/100% 100%;
}

有没有更为灵活的切图方式呢?

二、图形运算与CSS MASK

经常会和设计稿打交道,对设计软件(Photoshop、Figma等)应该或多或少也有所了解了,这里简单介绍一下图形运算(也称布尔运算),通常有 4 种类型

这是一个非常常见的设计技巧,可以将不同的图形经过运算合成新的图形。

下面是一个经典案例,就是通过圆的布尔运算绘制的

这么好的特性,CSS 中有类似的吗?

这就不得不提到CSS mask 了,CSS MASK 可以指定一张图作为遮罩图片。

css 复制代码
css
复制代码
div{
  mask: url(图片);
  mask: 渐变;
}

遮罩图片可以是图片,也可以是渐变。主要原理是显示遮罩图片不透明的部分,透明的则会被裁剪,示意如下

但是,很多情况下,单一的遮罩并不能满足需求,比如这样一个带缺口的圆,单一的渐变可能无法绘制

因此,我们需要用到和设计中图形布尔运算一样的技巧。

这和 CSS mask中的mask-composite是一一对应的

css 复制代码
css
复制代码
/* Keyword values */
mask-composite: add; /* 叠加(默认) */
mask-composite: subtract; /* 减去,排除掉上层的区域 */
mask-composite: intersect; /* 相交,只显示重合的地方 */
mask-composite: exclude; /* 排除,只显示不重合的地方 */

利用这个特性,可以很轻易的合成带缺口的圆,也就是说,我们可以使用 CSS 的方式自由的去裁剪、合成我们想要的图形。

另外,-webkit-mask-composite与标准下的值有所不同,属性值非常多,如下

css 复制代码
css
复制代码
-webkit-mask-composite: clear; /*清除,不显示任何遮罩*/
-webkit-mask-composite: copy; /*只显示上方遮罩,不显示下方遮罩*/
-webkit-mask-composite: source-over; /*默认值,正常的叠加,等同于 add */
-webkit-mask-composite: source-in; /*只显示重合的地方,等同于 intersect*/
-webkit-mask-composite: source-out; /*只显示上方遮罩,重合的地方不显示,等同于subtract*/
-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; /*只显示不重合的地方,等同于 exclude*/

其实是借用了 Canvas 中的图形合成属性,并且区分了图层顺序,但是对于遮罩层来讲,其实只需要关注遮罩的形状,不要关注图层的颜色,所以上述的一些值效果是完全相同的。

这里可以先不用每个都理解,知道有上面4种类型就行了,其实可以一一去试验,等熟悉了自然就知道每个属性的具体用途了。

下面是每个属性的演示

codepen.io/xboxyan/pen...

了解了这些,接下来看看在切图中的应用。

三、圆滑的内凹圆角

回到前面的问题,同样是切图,不过我们需要换一种方式。

仔细观察,从整体反向考虑,其实就是一个正常的圆角矩形,然后挖去两个平滑的缺口,两个缺口的大小是固定的,位置也是相对不变的,如图所示黑色的部分

所以下面的问题就是,如何来得到这两个缺口

单纯CSS渐变是难以绘制的,所以这里可以直接"切图"。但是设计稿上给的是红色部分,如何去手动做一个缺口部分呢?

这就稍微借助设计工具了,这里以 Figma 为例,我们绘制一个矩形,居右对齐,确保可以覆盖缺口(如下,蓝色部分)

然后,将蓝色矩形图层放在原图形下面

最后,选中这两个图形,执行减去顶层

完成!!

用同样的方式,可以得到左右两个半圆,或者直接翻转一下也行

接下来,我们需要将这两个 svg 转为内联,推荐用张鑫旭老师的这个

SVG在线压缩合并工具

最后,我们使用3层遮罩,两个半圆加上整个矩形,通过遮罩合成(仅显示不重叠部分)就可以得到我们需要的图形了

这样做的好处是两个半圆是通过CSS定位实现的,所以可以确保一定是居中、靠近边缘的,不会因为尺寸的变化而变形。

下面是完整代码

ini 复制代码
css
复制代码
coupon{
  width: 300px;
  height: 150px;
  border-radius: 8px;
  background: linear-gradient(85deg, #FF9078 7.57%, #FA3440 80.06%);
  -webkit-mask: url("data:image/svg+xml,%3Csvg width='20' height='48' viewBox='0 0 20 48' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M0 48V0c0 2.21 1.809 3.958 3.974 4.395C13.116 6.238 20 14.315 20 24S13.116 41.762 3.974 43.605C1.81 44.042 0 45.791 0 48z' fill='%23000'/%3E%3C/svg%3E") 0 50%/20px no-repeat,
    url("data:image/svg+xml,%3Csvg width='20' height='48' viewBox='0 0 20 48' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M20 48V0c0 2.209-1.809 3.959-3.975 4.395C6.885 6.238 0 14.315 0 24s6.885 17.762 16.025 19.605C18.191 44.041 20 45.791 20 48z' fill='%23000'/%3E%3C/svg%3E") 100% 50%/20px no-repeat,
    linear-gradient(red 0 0);
  -webkit-mask-composite: xor;
}

这样就得到了尺寸自适应、可更换颜色的优惠券样式了

你也可以访问在线链接

四、投票 PK 样式

下面来看这样一个例子

注意,这里也是有平滑圆角的,并且在宽度改变时,倾斜角是固定的

同样,也可以用"切图"的方式来实现这样的效果

在这里,我们还是从整体考虑,将图形补全,用图形合成的方式,在 Figma 中绘制出如下的"平滑直三角"

然后在 CSS 中通过 mask 减去黑色部分就行了,下面是完整代码

css 复制代码
css
复制代码
.pk{
  display: flex;
  width: 400px;
}
.item{
  height: 40px;
}
.left{
  width: 50%;
  border-radius: 40px 0 0 40px;
  background: linear-gradient(85deg, #FF9078 7.57%, #FA3440 80.06%);
  -webkit-mask: linear-gradient(red,red), url("data:image/svg+xml,%3Csvg width='16' height='40' viewBox='0 0 16 40' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M16 0h-2.344a1 1 0 0 1 .957 1.287L3.855 37.148A4 4 0 0 1 .023 40H16V0z' fill='%23C6F'/%3E%3C/svg%3E") right/auto 100% no-repeat;
  -webkit-mask-composite: xor;
}
.right{
  flex: 1;
  border-radius:  0 40px 40px 0;
  background: linear-gradient(274deg, #5FB6F5 -3.81%, #4B80EE 62.98%);
  -webkit-mask: linear-gradient(red,red), url("data:image/svg+xml,%3Csvg width='16' height='40' viewBox='0 0 16 40' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M0 40h2.344a1 1 0 0 1-.957-1.287L12.145 2.85A4 4 0 0 1 15.977 0H0v40z' fill='%23C6F'/%3E%3C/svg%3E") left/auto 100% no-repeat;
  -webkit-mask-composite: xor;
}

这样实现的倾角支持渐变,支持自适应宽度,效果如下

你也可以访问在线链接

五、平滑 tab 样式

最后再来看一个例子:平滑 tab 标签,就是 Chrome 标签栏那样的

其实关于这个布局,之前也专门写过文章,介绍了5种不同方式,有兴趣的可以回顾一下

CSS 实现Chrome标签栏的技巧

这次再来介绍一个比较简单、实用的"切图"方式。

通过前面两个例子,可能你已经猜到要怎么做了。没错,就是先补全

然后在设计软件中将黑色部分单独"切"出来

然后在 CSS 中通过 mask 减去这两部分黑色部分就行了,和第一个例子非常像,下面是完整代码

ini 复制代码
css
复制代码
tab{
  line-height: 40px;
  padding: 0 30px;
  background-color:royalblue;
  color: #fff;
  -webkit-mask: url("data:image/svg+xml,%3Csvg width='28' height='40' viewBox='0 0 28 40' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M28 0H0v40h1c8.283 0 15-6.717 15-15V12c0-6.627 5.373-12 12-12z' fill='%23000'/%3E%3C/svg%3E") 0 0 no-repeat,
    url("data:image/svg+xml,%3Csvg width='28' height='40' viewBox='0 0 28 40' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M0 0h28v40h-1c-8.283 0-15-6.717-15-15V12C12 5.373 6.627 0 0 0z' fill='%23000'/%3E%3C/svg%3E") 100% 0 no-repeat,
    linear-gradient(red 0 0);
  -webkit-mask-composite: xor;
}

这样实现的 tab 既做到了自适应宽度,也能随意更改背景,效果如下

你也可以访问在线链接

六、总结一下

以上就是本文的全部内容了,介绍了一种特殊的"切图"手法,将切图与CSS MASK结合起来,既保留了"切图"的简单暴力,又满足了CSS自适应的特点,下面简单总结一下

  1. 传统的"切图"简单暴力,但往往缺少适应性:尺寸自适应和颜色自适应

  2. 图形布尔运算主要有:合并形状、减去顶层、交叉形状、排除重叠

  3. CSS MASK composite 刚好也有相同的特性

  4. 可以从整体反向考虑,将难以实现的部分由"切图"完成,然后通过mask从整体减去这一部分

  5. 由于缺口部分是通过CSS定位实现,因此可以确保整体的自适应性

相关推荐
崔庆才丨静觅2 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60613 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了3 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅3 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅3 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅4 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment4 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅4 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊4 小时前
jwt介绍
前端
爱敲代码的小鱼4 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax