【CSS】2018- 不一样的SVG!SVG在 CSS 中的应用
共 10666字,需浏览 22分钟
·
2024-04-16 10:20
介绍一些你可能没用过的
SVG
小技巧。
在平时开发中,很多时候都会用到SVG
。大部分情况我们都不必关注SVG
里面到底是什么,直接当成图片资源引入就行,比如常见的图标资源
我们可以通过多种方式使用这个特殊的图片
<img src="a.svg">
.icon{
background: url("a.svg")
}
甚至直接放到HTML
中
<div>
<svg>
...
</svg>
</div>
这些都没什么问题,但有时候,我们需要的是可以自适应尺寸的,比如像这样的渐变边框,尺寸会随着文本内容的变化而变化,而不是固定尺寸,如下
或者是这样的虚线渐变边框
这样的该如何用 SVG
动态实现呢,一起看看吧
一、SVG导出的局限性
SVG
通常不是手写的(能手写任意路径的都是大神),几乎都是设计师借助软件绘制生成的,比如设计都很喜欢的Figma
(对前端非常友好,可以尝试一下)
比如前面提到的渐变边框,在Figma
中就是这样
对于设计师来说,渐变边框很容易,只需要选择边框类型就行了
对于 CSS
来说,这还算一个比较麻烦的事,通常我们需要额外嵌套一层渐变背景,通过遮盖或者mask
裁切的方式实现,有兴趣的可以尝试一下,这里暂不展开。
那么,这个设计可以直接通过导出SVG
实现吗?
先试试,Figma
中可以直接将这个边框复制成SVG
格式
下面是这段复制出来的SVG
代码(大概还是能看得懂一些的...)
<svg width="41" height="25" viewBox="0 0 41 25" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="1" y="1" width="39" height="23" rx="4" stroke="url(#paint0_linear_1_2)" stroke-linecap="round"/>
<defs>
<linearGradient id="paint0_linear_1_2" x1="0" y1="0" x2="1" y2="0">
<stop stop-color="#FFD75A"/>
<stop offset="1" stop-color="#ED424B"/>
</linearGradient>
</defs>
</svg>
我们尝试让这段SVG
尺寸跟随button
的大小,就行这样
<style>
svg{
position: absolute;
inset: 0;
}
</style>
<button>
CSS
<svg>...</svg>
</button>
在内容不定的情况下,就变成了这样
很显然不行,因为生成的SVG
宽高是固定的,没法跟随文本内容自适应尺寸
既然 SVG
很擅长渐变边框,而 CSS
很擅长自适应,那么,有没有取长补短的办法呢?
当然也是有的!不过需要“改造”一下,接着往下看
二、SVG 自适应尺寸
首先我们把上面的那段SVG
拿过来
<svg width="41" height="25" viewBox="0 0 41 25" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="1" y="1" width="39" height="23" rx="4" stroke="url(#paint0_linear_1_2)" stroke-linecap="round"/>
<defs>
<linearGradient id="paint0_linear_1_2" x1="0" y1="0" x2="1" y2="0">
<stop stop-color="#FFD75A"/>
<stop offset="1" stop-color="#ED424B"/>
</linearGradient>
</defs>
</svg>
有没有发现这里很多数值都固定的?如果想实现自适应,我们就需要将这些值改成百分比形式,注意看这个rect
,有个x
、y
坐标,我们现在宽高都是100%
了,所以这里的坐标也要改成0
,不然就撑出去了
<svg width="100%" height="100%" viewBox="0 0 100% 100%" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="0" y="0" width="100%" height="100%" rx="4" stroke="url(#paint0_linear_1_2)" stroke-linecap="round"/>
<defs>
<linearGradient id="paint0_linear_1_2" x1="0" y1="0" x2="1" y2="0">
<stop stop-color="#FFD75A"/>
<stop offset="1" stop-color="#ED424B"/>
</linearGradient>
</defs>
</svg>
为了验证这个 SVG
的自适应,我们将这个SVG
放在一个div
中
<div style="width: 100px;height: 80px;">
<svg>...</svg>
</div>
<div style="width: 200px;height: 180px;">
<svg>...</svg>
</div>
效果如下
是不是已经自适应了?
不过还是有点问题,仔细观察,圆角处有些不自然,感觉被裁剪了一样
造成这种现象的原因有两个:
SVG
描边是居中描边,并且不可修改SVG
默认是超出隐藏的,也就是自带overflow:hidden
我们把边框改大一点就可以很明显的观察到描边是居中的
由于是居中的,所以在不做修改的情况下,我们看到的其实只有原边框的一半,利用这个原理我们其实可以实现常说的0.5px
边框,有兴趣的可以参考我之前这篇文章:使用svg描边来实现移动端1px
在这里,我再介绍一种新的方式,那就是利用 CSS calc
!
没错,在 SVG
中也可以使用CSS
函数,比如我们这里边框是4px
,那么坐标x
、y
就应该是2
,然后宽高应该是calc(100% - 4px)
,所以可以很自然的改成这样
<div style="width: 100px;height: 80px;">
<svg width="100%" height="100%">
<rect x="2" y="2" width="100%" height="100%" style="width: calc(100% - 4px);height: calc(100% - 4px);" rx="4" stroke="url(#paint0_linear_1_2)" stroke-width="4" stroke-linecap="round"/>
<defs>
<linearGradient id="paint0_linear_1_2" x1="0" y1="0" x2="1" y2="0">
<stop stop-color="#FFD75A"/>
<stop offset="1" stop-color="#ED424B"/>
</linearGradient>
</defs>
</svg>
</div>
非常完美了,不会有任何裁剪!(大家也可以复制上面这段代码放在 HTML 中验证)
这样就“轻易”实现了SVG
的尺寸自适应
这里小结一下
将
SVG
的尺寸改为`百分比由于是居中描边,所以要修正一下坐标和大小
除此之外,还能直接加上style
样式,就像这样
<svg width="100%" height="100%" viewBox="0 0 100% 100%" fill="none" xmlns="http://www.w3.org/2000/svg">
<style>
rect{
width: calc(100% - 4px);
height: calc(100% - 4px);
}
</style>
<rect x="2" y="2" width="100%" height="100%" rx="4" stroke="url(#paint0_linear_1_2)" stroke-width="4" stroke-linecap="round"/>
<defs>
<linearGradient id="paint0_linear_1_2" x1="0" y1="0" x2="1" y2="0">
<stop stop-color="#FFD75A"/>
<stop offset="1" stop-color="#ED424B"/>
</linearGradient>
</defs>
</svg>
虽然看着多,但后面作用更大,可以添加更多的 CSS
样式
三、SVG 在 HTML 中的应用
其实前面的这段 SVG
可以直接放到 HTML
中用了,比如
<button>
<svg width="100%" height="100%" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="2" y="2" width="100%" height="100%" style="width: calc(100% - 4px);height: calc(100% - 4px);" rx="16" stroke-width="2" stroke="url(#paint0_linear_3269_5233)"/>
<defs>
<linearGradient id="paint0_linear_3269_5233" x1="0" y1="0" x2="100%" y2="100%" gradientUnits="userSpaceOnUse">
<stop stop-color="#FFD75A"/>
<stop offset="1" stop-color="#ED424B"/>
</linearGradient>
</defs>
</svg>
CSS
</button>
我们需要将这个 SVG
撑满整个button
,所以可以直接绝对定位
button{
position: relative;
}
button>svg{
position: absolute;
inset: 0;
}
这样就得到了一个自适应尺寸的、带有渐变边框的按钮,效果如下
你也可以访问在线链接:buton with SVG (juejin.cn)[1]
四、SVG 在 CSS 中的应用
不知道你有没有这样的感觉,把一大段 SVG
放在 HTML
不是特别优雅,总觉得太臃肿了。
如果你有这种感觉,不妨将这段 SVG
转换成内联CSS
代码。
在这里可以借助张鑫旭老师的这个工具:SVG在线压缩合并工具[2]
我们将这段SVG
粘贴过去,可以得到这样的一段内联SVG
data:image/svg+xml,%3Csvg fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Crect x='1' y='1' width='100%25' height='100%25' style='width:calc(100%25 - 2px);height:calc(100%25 - 2px)' rx='16' stroke-width='2' stroke='url(%23paint0_linear_3269_5233)'/%3E%3Cdefs%3E%3ClinearGradient id='paint0_linear_3269_5233' y2='100%25' gradientUnits='userSpaceOnUse'%3E%3Cstop stop-color='%23FFD75A'/%3E%3Cstop offset='1' stop-color='%23ED424B'/%3E%3C/linearGradient%3E%3C/defs%3E%3C/svg%3E
有了这段内联SVG
,我们可以直接用在background
背景上
button{
background: url("data:image/svg+xml,%3Csvg fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Crect x='1' y='1' width='100%25' height='100%25' style='width:calc(100%25 - 2px);height:calc(100%25 - 2px)' rx='16' stroke-width='2' stroke='url(%23paint0_linear_3269_5233)'/%3E%3Cdefs%3E%3ClinearGradient id='paint0_linear_3269_5233' y2='100%25' gradientUnits='userSpaceOnUse'%3E%3Cstop stop-color='%23FFD75A'/%3E%3Cstop offset='1' stop-color='%23ED424B'/%3E%3C/linearGradient%3E%3C/defs%3E%3C/svg%3E")
}
而HTML
只需要干净的button
元素就够了
<button>CSS</button>
<button>CSS & SVG</button>
神奇的是,即便是转为内联了,SVG
仍然保持着自适应特性,这样也能实现同样的效果,是不是好多了?
你也可以访问在线链接:button with SVG background (juejin.cn)[3]
五、SVG 的独特魅力
如果说上面的效果 CSS
还能勉强模拟一下,那如果是这样的虚线呢?
对于 SVG
就非常容易了,只需要设置stroke-dasharray
属性就行,并且可以随意更改虚线的间隔
<svg width="100%" height="100%" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="2" y="2" width="100%" height="100%" style="width: calc(100% - 4px);height: calc(100% - 4px);" rx="16" stroke-width="2" stroke="url(#paint0_linear_3269_5233)" stroke-dasharray="8 4"/>
<defs>
<linearGradient id="paint0_linear_3269_5233" x1="0" y1="0" x2="100%" y2="100%" gradientUnits="userSpaceOnUse">
<stop stop-color="#FFD75A"/>
<stop offset="1" stop-color="#ED424B"/>
</linearGradient>
</defs>
</svg>
还有这种虚线边缘是圆角的情况,CSS
就更加无能为力了
SVG
只需要设置stroke-linecap
就行
<svg width="100%" height="100%" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="2" y="2" width="100%" height="100%" style="width: calc(100% - 4px);height: calc(100% - 4px);" stroke-width="2" rx="16" stroke-linecap="round" stroke="url(#paint0_linear_3269_5233)" stroke-dasharray="8 6"/>
<defs>
<linearGradient id="paint0_linear_3269_5233" x1="0" y1="0" x2="100%" y2="100%" gradientUnits="userSpaceOnUse">
<stop stop-color="#FFD75A"/>
<stop offset="1" stop-color="#ED424B"/>
</linearGradient>
</defs>
</svg>
更进一步,SVG
还能实现虚线滚动动画,CSS
应该是实现不了了
看似复杂,其实只需要改变stroke-dashoffset
属性就行了,我们可以直接在SVG
中插入CSS
动画
<svg width="100%" height="100%" fill="none" xmlns="http://www.w3.org/2000/svg">
<style>
.rect{
width: calc(100% - 4px);
height: calc(100% - 4px);
animation: move .3s infinite linear;
}
@keyframes move {
0% { stroke-dashoffset: 0; }
100% { stroke-dashoffset: 14; }
}
</style>
<rect class="rect" x="2" y="2" width="100%" height="100%" stroke-width="2" rx="16" stroke-linecap="round" stroke="url(#paint0_linear_3269_5233)" stroke-dasharray="8 6"/>
<defs>
<linearGradient id="paint0_linear_3269_5233" x1="0" y1="0" x2="100%" y2="100%" gradientUnits="userSpaceOnUse">
<stop stop-color="#FFD75A"/>
<stop offset="1" stop-color="#ED424B"/>
</linearGradient>
</defs>
</svg>
所有情况都可以将 SVG
转为内联CSS
直接用在背景上,极大的保证了HTML
的简洁性
你也可以访问在线链接:dot border with animation (juejin.cn)[4]
六、总结一下
以上就是本文的全部内容了,主要介绍了如何利用 SVG
和CSS
各种的优势来实现更加灵活的布局,下面总结一下
设计软件导出的
SVG
都是固定尺寸的,不能自适应尺寸SVG
很擅长渐变边框,而CSS
很擅长自适应尺寸,得想办法取长补短SVG
部分属性支持百分比类型,可以实现尺寸自适应SVG
描边是居中描边,并且不可修改,所以需要调整圆角矩形的坐标的大小SVG
中也支持CSS
部分特性,比如calc
计算函数SVG
还支持内嵌style
标签,直接插入CSS
代码可以将
SVG
转为内联CSS
代码,在支持SVG
特性的同时极大的保证了HTML
的整洁借助
SVG
可以很轻松的实现渐变虚线边框SVG
中还支持CSS
动画,可以实现虚线滚动动画
你可能已经发现SVG
并不是非常孤立的一门语言,现在还能和 CSS
、HTML
联动起来,充分发挥各自的优势,这样才能事半功倍 。最后,如果觉得还不错,对你有帮助的话,欢迎点赞、收藏、转发 ❤❤❤
[1]buton with SVG (juejin.cn): https://code.juejin.cn/pen/7341373491785236532
[2]SVG在线压缩合并工具: https://www.zhangxinxu.com/sp/svgo/
[3]button with SVG background (juejin.cn): https://code.juejin.cn/pen/7341378448348643379
[4]dot border with animation (juejin.cn): https://code.juejin.cn/pen/7341382517888876582