不一样的SVG!SVG在CSS背景平铺中的应用

2024年 5月 16日 109.0k 0

再次介绍一些你可能没用过的SVG小技巧。

再次介绍一些你可能没用过的SVG小技巧。

有时候会遇到一些完全相同的图形,如果能用上 CSS背景平铺,那就再合适不过了。举个例子,有这样一个按钮。

不一样的SVG!SVG在CSS背景平铺中的应用-1

相比普通的按钮,多个左右两个小装饰,如果是你,会怎样实现呢?

假设这个小图标是a.svg,想了一下,应该有以下几种方式。

1.伪元素

刚好用上::before和::after,设置相同的背景就行了,示意如下:

button::before,
button::after{
  content:'';
  background: url(a.svg)
}

2. 多重背景

利用 CSS背景可以叠加的特性,设置两个背景就可以了,分别定位,示意如下:

button{
  background: url(a.svg) 10px center no-repeat,url(a.svg) right 10px top center no-repeat
}

这两种方式都是不错的方式,但是感觉还是有些浪费,毕竟把两个相同的图案重复写了两遍。

为啥不能直接用背景平铺呢?因为无法直接设置平铺的间隔,就像这样。

不一样的SVG!SVG在CSS背景平铺中的应用-2

这时,如果能充分发挥SVG的特性,就可以仅仅使用平铺的方式来实现我们想要的效果了,一起看看吧~

一、SVG的自适应和viewBox

就以上面的小图标为例,从 Figma中可以复制这段svg,如下:


    

嗯,看着非常乱,没关系,我们不必关注里面的细节。

我们直接放在 html 中来展示这段svg,效果是这样的。

不一样的SVG!SVG在CSS背景平铺中的应用-3

因为这段 svg有自带的尺寸,最后展示的就是16 * 16的大小。

如果我们手动改变这个svg的尺寸呢?为了方便观察,我们给svg添加一个边框,如下:

svg{
	width: 200px;
  height: 100px;
  outline: 1px dashed;
}

你猜会是什么样的?

下面有 3 个选项。

不一样的SVG!SVG在CSS背景平铺中的应用-4

思考一分钟...

思考完成,答案是A,你猜对了吗?

不一样的SVG!SVG在CSS背景平铺中的应用-5

为什么会这样呢?有点类似于object-fit:contain的效果。其实这是viewBox造成的,viewBox会按照尺寸等比放大从而铺满整个svg。

有关 viewBox的更多介绍,可以参考张鑫旭老师的这篇文章:理解SVG viewport,viewBox,preserveAspectRatio缩放。

如果去除viewBox,svg内部该是什么样就是什么样,也就是仍然是16*16的大小。



  ...

结果如下:

不一样的SVG!SVG在CSS背景平铺中的应用-6

也就是说,在去除viewBox之后,无论svg尺寸是多少,里面的图标都不会变化。

看似好像没什么用?

其实用处可大了,可以让背景以我们想要的方式平铺,那就来看接下来的应用。

二、自适应尺寸与背景平铺

现在来简单实现文章开头所示的按钮效果。html很简单,就一个标签。

召唤卡牌

然后简单装饰一下,绘制圆角和背景。

button{
  border: 0;
  outline: 0;
  padding: 8px 36px;
  font-size: 12px;
  line-height: 16px;
  border-radius: 30px;
  color: #FFEFDB;
  background: #FF2A2A;
}

效果如下:

不一样的SVG!SVG在CSS背景平铺中的应用-7

接下来,我们要用上前面的那段svg,先去除viewBox属性,为了能够通过背景尺寸控制svg大小,我们可以将svg的尺寸改成100%。

示意如下:


  ...

然后将这段svg转换成css内联格式,推荐用张鑫旭老师的在线转换工具。

SVG在线压缩合并工具。

可以得到这样一段。

--icon: url("data:image/svg+xml,%3Csvg     fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M15.021 8.028L15 8.027c-.262-.26-.876-.747-2.008-.701.13-.314.027-1.204-.676-1.227.179.574-.803.974-1.361 1.155-.484.156-1.025.344-1.16.622l-.437-.003.002-.43-.276-.001-.004.428-.25-.002c-.028-.022-.058-.047-.091-.07a.643.643 0 0 0-.316-.29.663.663 0 0 0-.21-.22 3.071 3.071 0 0 0-.109-.157l.002-.21.43.004.003-.277-.43-.004.002-.436c.283-.127.478-.667.644-1.152.19-.555.606-1.53 1.18-1.341-.013-.704-.902-.822-1.216-.695.063-1.135-.417-1.754-.67-2.02V.977L8.036.99 8.028.977l-.001.02c-.26.263-.747.877-.701 2.009-.314-.13-1.204-.027-1.228.676.574-.179.974.803 1.155 1.362.157.484.345 1.025.622 1.159l-.003.437-.43-.002v.277l.427.003-.002.25c-.022.028-.046.058-.069.091a.643.643 0 0 0-.29.317.664.664 0 0 0-.222.21 3.07 3.07 0 0 0-.156.108l-.21-.002.004-.43-.276-.002-.004.43-.436-.002c-.127-.283-.667-.478-1.152-.644-.555-.19-1.53-.606-1.341-1.18-.704.013-.822.902-.695 1.216-1.135-.063-1.754.417-2.02.67H.977l.012.012-.012.009.02.001c.263.26.877.747 2.009.702-.13.314-.027 1.203.676 1.227-.179-.574.803-.974 1.362-1.155.484-.157 1.024-.345 1.159-.622l.437.003-.002.43h.277l.003-.427.25.002c.028.022.058.046.091.069a.643.643 0 0 0 .317.29c.058.101.135.172.21.222.04.06.077.114.108.156l-.002.21-.43-.004-.002.276.43.004-.002.437c-.283.127-.478.666-.644 1.15-.19.556-.606 1.532-1.18 1.342.013.705.902.822 1.216.696-.063 1.134.417 1.753.67 2.02v.022l.012-.011c.004.003.006.007.009.012l.001-.021c.26-.263.747-.877.702-2.009.314.13 1.203.027 1.227-.676-.574.179-.974-.803-1.155-1.362-.157-.483-.345-1.024-.622-1.159l.003-.437.43.002v-.277l-.427-.003.002-.25c.022-.028.046-.058.069-.091a.643.643 0 0 0 .29-.317.664.664 0 0 0 .222-.21c.06-.04.114-.077.156-.108l.21.002-.004.43.276.002.004-.43.437.002c.127.283.666.478 1.15.644.556.19 1.532.606 1.342 1.18.705-.013.823-.902.696-1.216 1.134.063 1.753-.417 2.02-.67h.022a1.093 1.093 0 0 1-.011-.012c.003-.004.007-.006.012-.009h-.002z' fill='%23FFEFDB'/%3E%3C/svg%3E")

接着,将这段svg背景放到按钮中。

button{
  background: var(--icon) #FF2A2A;
}

效果如下:

不一样的SVG!SVG在CSS背景平铺中的应用-8

很明显,此时这个svg图标背景默认尺寸是充满整个容器的,也就是100% * 100%。如果希望右边也出现平铺一个图标,可以减小背景尺寸,比如。

button{
  background: var(--icon) #FF2A2A;
  background-size: calc(100% - 48px)
}

效果如下:

不一样的SVG!SVG在CSS背景平铺中的应用-9

然后改变水平位置。

button{
  background: var(--icon) #FF2A2A;
  background-size: calc(100% - 48px);
  background-position: 16px;
}

效果如下:

不一样的SVG!SVG在CSS背景平铺中的应用-10

左右已经出现图标了,现在只需要垂直居中就可以了,这个也很好实现,设置尺寸为图标本身大小,然后改变背景位置就行了。

button{
  background: var(--icon) #FF2A2A;
  background-size: calc(100% - 48px) 16px;
  background-position: 16px center;
}

效果如下:

不一样的SVG!SVG在CSS背景平铺中的应用-11

垂直方向也平铺了,所以还需要改变一下平铺方式,仅限水平方向。

button{
  background: var(--icon) #FF2A2A;
  background-size: calc(100% - 48px) 16px;
  background-position: 16px center;
  background-repeat: repeat-x;
}

这样就仅仅使用平铺完成了想要的效果!

不一样的SVG!SVG在CSS背景平铺中的应用-12

是不是有些不可思议?下面是一个示意图,紫色圆圈代表图标,紫色边框代表svg尺寸,也就是背景尺寸,设置为100% - 36px后,水平方向的平铺就可以显示两个圆圈了,然后适当移动背景位置,就可以看到左右两边的图标了。

不一样的SVG!SVG在CSS背景平铺中的应用-13

当然这种实现也是完全是自适应的,无论什么尺寸都可以完美适配。

不一样的SVG!SVG在CSS背景平铺中的应用-14

完整代码可以查看以下链接:

  • CSS & SVG repeat button (juejin.cn)[1]
  • CSS & SVG repeat button (codepen.io)[2]

三、有时候可替代径向渐变

里面有提到用径向渐变的方式来绘制内凹圆角,但是渐变一直都是一个非常难学的技巧,语法非常多,一般同学表示接受不了。

这里就采用 SVG来代替径向渐变的方式来实现这样的优惠券效果。

不一样的SVG!SVG在CSS背景平铺中的应用-15

首先,我们用设计软件随便画个圆,这里以Figma为例,然后复制出SVG。

不一样的SVG!SVG在CSS背景平铺中的应用-16

其实就是这样一段代码。



非常简单吧。

然后去除viewBox,并且设置宽高为100%,这是为了让SVG画布尺寸撑满整个容器。



接着转换成CSS内联格式。

--icon: url("data:image/svg+xml,%3Csvg     fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Ccircle cx='20' cy='20' r='20' fill='%23FF336F'/%3E%3C/svg%3E")

然后用在 CSS 背景中。

div{
  background: var(--icon);
}

目前效果是这样的。

不一样的SVG!SVG在CSS背景平铺中的应用-17

我们需要将这个圆分割到4个角落上,可以直接用背景平移的方式。

div{
  background: var(--icon);
  background-position: -20px -20px;
}

这样就可以了,演示如下:

不一样的SVG!SVG在CSS背景平铺中的应用-18

不过这样还没完,我们需要实现的反向圆角,所以这里需要用遮罩的方式,减去 4 个角落。

回到这里,我们只需要一个完整的背景,减去刚才的圆角就可以了,具体实现如下:

.coupon{
  background: linear-gradient(red,orange);
  -webkit-mask:linear-gradient(red,red), var(--icon);
  -webkit-mask-position: -20px -20px;
  -webkit-mask-composite: xor;
}

效果如下,其实和前面几乎一致。

不一样的SVG!SVG在CSS背景平铺中的应用-19

是不是没有用到径向渐变?

完整代码可以查看以下链接:

  • CSS & SVG coupon (juejin.cn)[3]
  • CSS & SVG coupon (codepen.io)[4]

四、SVG还可以更灵活

有时候径向渐变还是有很多局限的,复杂的图形绘制不了或者成本很高。而 SVG就没有这样的限制了,如果能有一定的自适应特性,相信可以更方便的解决问题。

比如这样一个带圆角的自适应聚焦框,可能在大屏可视化比较常见,如下(CSS表示无能为力😭)。

不一样的SVG!SVG在CSS背景平铺中的应用-20

除了使用border-image实现以外,还可以采用背景平铺来实现。

要实现背景平铺,首先要考虑,哪个是平铺最小单元?

不一样的SVG!SVG在CSS背景平铺中的应用-21

思考一分钟...

思考完成,答案还是A,你猜对了吗?

为什么是A呢?其实要从全局视野来观察,从全局来看,其实是由4个半圆弧组合而成,示意如下:

不一样的SVG!SVG在CSS背景平铺中的应用-22

那么,如何用 CSS背景平铺来实现呢?

思路是一致的,首先从设计稿把这段svg复制下来。

不一样的SVG!SVG在CSS背景平铺中的应用-23

得到这样一个片段。



然后去除viewBox,并且设置宽高为100%。


  ...

接着转换成CSS内联格式。

--icon: url("data:image/svg+xml,%3Csvg     fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M30 2a2 2 0 1 0-4 0v8c0 8.837-7.163 16-16 16H2a2 2 0 1 0 0 4 2 2 0 1 0 0 4h8c8.837 0 16 7.163 16 16v8a2 2 0 1 0 4 0 2 2 0 1 0 4 0v-8c0-8.837 7.163-16 16-16h8a2 2 0 1 0 0-4 2 2 0 1 0 0-4h-8c-8.837 0-16-7.163-16-16V2a2 2 0 1 0-4 0zm20 28c-11.046 0-20 8.954-20 20 0-11.046-8.954-20-20-20 11.046 0 20-8.954 20-20 0 11.046 8.954 20 20 20z' fill='%23FF336F'/%3E%3C/svg%3E")

最后设置为CSS背景。

div{
  background: var(--icon);
}

效果如下:

不一样的SVG!SVG在CSS背景平铺中的应用-24

此时无论容器尺寸是多少,这个背景位于左上角。

最后只需要改变一下背景的位置,设置负的偏移量,就可以平铺到 4 个角落了。

div{
  background: var(--icon) #eee;
  background-position: -30px -30px;/*图案的一半*/
}

动态示意如下:

不一样的SVG!SVG在CSS背景平铺中的应用-25

是不是非常简单的实现?

完整代码可以查看以下链接:

  • CSS & SVG coner (juejin.cn)[5]
  • CSS & SVG coner (codepen.io)[6]

五、总结一下

以上就是本文的全部内容了,一个成本非常小的 SVG小技巧,仅仅需要小小的改动,就能让SVG自适应背景平铺,如下:



  ...

你学到了吗?下面总结一下实现要点:

  • SVG默认会根据viewBox填充整个画布,有点类似于object-fit:contain的效果。
  • 去除viewBox后,无论svg尺寸是多少,里面的内容大小都不会变化。
  • 利用这个特性,可以通过设置背景尺寸的方式,让背景以我们想要的方式平铺。
  • 有时候可替代径向渐变,毕竟 SVG 比渐变还是容易很多。
  • 复杂的图形渐变绘制不了或者成本很高,SVG还能更灵活。

[1]CSS & SVG repeat button (juejin.cn): https://code.juejin.cn/pen/7357275939322052658。

[2]CSS & SVG repeat button (codepen.io): https://codepen.io/xboxyan/pen/mdgjeeM。

[3]CSS & SVG coupon (juejin.cn): https://code.juejin.cn/pen/7357302135584718899。

[4]CSS & SVG coupon (codepen.io): https://codepen.io/xboxyan/pen/MWRBKbj。

[5]CSS & SVG coner (juejin.cn): https://code.juejin.cn/pen/7357294680330993702。

[6]CSS & SVG coner (codepen.io): https://codepen.io/xboxyan/pen/GRLBpLX。

相关文章

JavaScript2024新功能:Object.groupBy、正则表达式v标志
PHP trim 函数对多字节字符的使用和限制
新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
为React 19做准备:WordPress 6.6用户指南
如何删除WordPress中的所有评论

发布评论