这篇文章发布于 2020年10月30日,星期五,01:57,归类于 CSS相关, SVG相关。 阅读 20194 次, 今日 10 次 13 条评论
by zhangxinxu from https://www.zhangxinxu.com/wordpress/?p=9539
本文欢迎分享与聚合,全文转载就不必了,尊重版权,圈子就这么大,若急用可以联系授权。
目前流行的SVG小图标技术是SVG Sprites技术,此技术我6年前就率先在国内进行了介绍:“未来必热:SVG Sprites技术介绍”,这里再介绍另外一种同样需要用到SVG元素的Sprites技术,我称之为“clipPath Sprites技术”。
一、关于clip-path与小图标实现
CSS clip-path
属性除了剪裁圆、多边形之外,还支持url()
函数语法,可以把SVG元素中的路径作为剪裁路径。
语法示意如下:
.shape { clip-path: url(#someId); }
someId
就是SVG中<clipPath>
元素的ID值。
例如:
<svg>
<clipPath id="someId">...</clipPath>
</svg>
下面通过一个具体案例演示下这种语法的效果。
假设有如下SVG代码:
<svg width="50" height="50" version="1.1" xmlns="http://www.w3.org/2000/svg"> <ellipse cx="25" cy="25" rx="20" ry="10"></ellipse> <rect x="15" y="5" width="20" height="40" rx="5" ry="5"></rect> </svg>
会有如下图所示的姨妈巾效果:
此时,可以把SVG中的图形元素全部放在<clipPath>
元素中,这样,就可以把任意的元素剪裁为姨妈巾的形状了。
<svg width="0" height="0"> <clipPath id="someId"> <ellipse cx="25" cy="25" rx="20" ry="10"></ellipse> <rect x="15" y="5" width="20" height="40" rx="5" ry="5"></rect> </clipPath> </svg>
但是,实际测试发现,上面的代码只有在50px*50px的元素中效果才是正常的,也就是剪裁元素的尺寸默认需要和SVG元素图形尺寸一致才行,这就有些坑爹了,好在SVG提供了一些方法可以适用于任意的HTML元素尺寸。
方法1:transform缩放SVG
例如剪裁的HTML元素的尺寸是20px*20px,原SVG尺寸是50px,因此,需要缩放40%,此时就有如下所示的SVG代码:
<svg width="0" height="0"> <clipPath id="someId"> <ellipse transform="scale(0.4, 0.4)" cx="25" cy="25" rx="20" ry="10"></ellipse> <rect transform="scale(0.4, 0.4)" x="15" y="5" width="20" height="40" rx="5" ry="5"></rect> </clipPath> </svg>
此时,就可以把20px*20px大小元素剪裁成对应规格的图形效果了:
.icon { display: inline-block; width: 20px; height: 20px; background-color: deepskyblue; clip-path: url(#someId); }
此时就有如下图所示的效果:
方法2:设置clipPathUnits=”objectBoundingBox”
设置剪裁位置是基于对象的尺寸,此时,需要SVG图形中的坐标都以数值1为基准进行计算,因此,通常路径或者参数值基本上都是小于1的数值,例如:
<svg width="0" height="0"> <clipPath id="someId" clipPathUnits="objectBoundingBox"> <ellipse cx=".5" cy=".5" rx=".4" ry=".2"></ellipse> <rect x=".3" y=".1" width=".4" height=".8" rx=".1" ry=".1"></rect> </clipPath> </svg>
此时,剪裁的图形效果会按照元素的的尺寸计算,无论图标的尺寸是20px*20px,还是100px*100px,都会按照这个尺寸进行剪裁。
实现的效果如下截图所示:
眼见为实,您可以狠狠地点击这里:2种方法实现的clip-path小图标剪裁效果demo
无论是transform
缩放,还是objectBoundingBox
重计算,都可以实现任意尺寸的SVG剪裁效果。
下图是Firefox浏览器下的效果截图:
//zxx: 如果你看到这段文字,说明你现在访问是体验糟糕的垃圾盗版网站,你可以访问原文获得很好的体验:https://www.zhangxinxu.com/wordpress/?p=9539(作者张鑫旭)
关于IE/Edge浏览器
CSS中有3个很高级属性IE浏览器也是支持的,分别是clip-path
属性,filter
属性和mask
属性。
但是,请注意,这些支持其实并不是CSS规范中的那种支持,而是SVG元素衍生过来的语法,因为IE浏览器支持SVG,而SVG中有一些特性可以在CSS中使用,因此,IE浏览器也支持了部分高级CSS语法,就好像SVG中的fill
和stroke
属性也可以在IE中使用一样。
同样的,clip-path
属性,filter
属性和mask
属性都是仅支持url()
语法,均指向SVG元素。
因此,虽然clip-path:url(#someId)
在IE/Edge浏览器下语法是合法的,但是仅仅作用在SVG元素上才有效果,也就是下面的HTML代码IE浏览器是没有效果的:
<i class="icon"></i>
但是下面的代码就有剪裁效果:
<svg width="20" height="20"> <rect fill="deepskyblue" class="icon"></rect> </svg>
因此,如果需要兼容IE浏览器,只要把普通HTML元素改为使用SVG元素就可以了。
二、更进一步,clipPath Sprites小图标技术
在传统的SVG Sprites中使用的是SVG <use>
元素的href
属性值指向<symbol>
元素的id属性,嘿!岂不是和这里的实现逻辑本质上是一样的,这里是CSS clip-path属性中的url()
函数值指向<clipPath>
元素的id属性。
因此,理论上,传统SVG Sprites合并那一套东西也是可以用在clipPath Sprites合并中的。
受此idea的启发,我就把我之前制作的SVG压缩合并工具升级了下,增加了clipPath Sprites合并功能(选择的是transform
缩放,因为更容易实现[捂脸]),发现这个技术完全可行。
您可以狠狠地点击这里:升级后的SVG在线压缩合并工具
从这个我做的SVG Sprites还原工具中下载几个比较顺眼的图标,然后拖进去——
在页面的最下方就可以看到合并后的clipPath Sprites代码了,如下截图示意:
点击复制或下载按钮,把输入框中的SVG代码复制到页面中,此时,就可以使用CSS clip-path
属性实现各式各样的小图标效果了。
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="0" height="0" style="position:absolute;"> <clipPath id="eye"><path transform="scale(0.034724, 0.0390625)" d="..."/></clipPath> <clipPath id="paper-plane"><path transform="scale(0.0390625, 0.0390625)" d="..."/></clipPath> <clipPath id="comment"><path transform="scale(0.0390625, 0.0390625)" d="..."/></clipPath> </svg>
例如有如下所示的HTML和CSS代码:
<ul id="ul"> <li><i class="icon" style="--clipPath:url(#paper-plane)"></i>分享</li> <li><i class="icon" style="--clipPath:url(#eye)"></i>预览</li> <li><i class="icon" style="--clipPath:url(#comment)"></i>评论</li> </ul>
.icon { display: inline-block; width: 20px; height: 20px; background-color: currentColor; -webkit-clip-path: var(--clipPath); clip-path: var(--clipPath); vertical-align: middle; margin-right: 1ch; }
此时就有如下图所示的小图标效果:
眼见为实,有演示的,您可以狠狠地点击这里:SVG clipPath合并图标效果demo
由于是通过剪裁实现的,因此实现的图标效果支持任意变色,如下GIF录屏示意(点击播放317K):
也可以是渐变效果(改成背景渐变即可),例如:
.icon { background: linear-gradient(deepskyblue, deeppink); ... }
渐变效果如下截图:
当然,也可以把照片剪裁成图标模板,或者是任意的元素,按钮、文字等都可以剪裁成小图标的样子,非常灵活。
对比传统SVG Sprites技术
传统SVG Sprites | clipPath Sprites | |
---|---|---|
矢量 | ✔ | ✔ |
颜色可变 | ✔ | ✔ |
支持渐变 | ✘ | ✔ |
标签 | svg>use | 任意HTML标签(IE除外) |
兼容性 | IE9+ | IE9+(IE需使用SVG元素) |
尺寸控制 | 灵活 | transform方法受限 | clipPathUnits方法灵活 |
工具 | 丰富 ✔ | 起步中…… |
整体来看,clipPath Sprites技术的优势更强,尤其在移动端开发中,只要后期有转换工具可以把所有的SVG图标路径转成clipPathUnits为objectBoundingBox模式的数值,那么clipPath Sprites技术几乎就没有任何缺陷,取代传统的SVG Sprites小图标技术应该不成问题。
三、肝不动的结语
本月爆更11篇技术文章,10年来新高,为什么高产四母猪呢?因为《CSS新世界》这本书交稿了,有时候更新博客了,于是积攒的文章一次性爆发了,不过也导致这个月天天很晚睡,实在有些肝不动了。
回到文章这里,clipPath Sprites技术是自己写CSS clip-path
章节突然的灵感,我查了下国内外的资料,有使用clip-path
实现小图标效果的案例,但是并没有发现谁把小图标全部打包在一起的案例,因此,本文的clipPath Sprites技术可以算是一个首创的技术吧。
不过,也是最近刚折腾出来的,还没有在生成环境使用,因此,是否有什么坑还不得而知,不过按照我长期以来使用clip-path
的经验来看,应该没什么问题,clip-path
一直是一个运行非常稳健的CSS属性,在移动端兼容性也非常好。
我近期会在合适的项目中尝试这种图标技术,之后有变化会进一步更新。
OK,结语就说这么多。
如果你觉得本文内容确实有点料,欢迎分享,也欢迎以评论方式进行交流,补充我不知道的信息,或者指出文章有表述不准确的地方。
本文为原创文章,欢迎分享,勿全文转载,如果实在喜欢,可收藏,永不过期,且会及时更新知识点及修正错误,阅读体验也更好。
本文地址:https://www.zhangxinxu.com/wordpress/?p=9539
(本篇完)
- CSS3/SVG clip-path路径剪裁遮罩属性简介 (0.539)
- 基于clip-path的任意元素的碎片拼接动效 (0.510)
- 纯CSS实现任意格式图标变色的研究 (0.490)
- 今天学习SVG滤镜feGaussianBlur和feDropShadow (0.405)
- 未来必热:SVG Sprites技术介绍 (0.328)
- SVG图标颜色文字般继承与填充 (0.328)
- 3种纯CSS实现中间镂空的12色彩虹渐变圆环方法 (0.308)
- SVG-Morpheus实现SVG图标图形间的补形动画 (0.299)
- 你用的那些CSS转场动画可以换一换了 (0.267)
- 学习了,CSS中内联SVG图片有比Base64更好的形式 (0.237)
- -webkit-box-reflect属性简介及元素镜像倒影实现 (RANDOM - 0.150)
牛啊,大大减少了http的请求次数。请问用mask 配合mask-position mask-size可以做到类似的事情吗,clip-path绝对路径转相对路径一定会有缺少边角的情况,有啥更好的办法吗?
ClipPath Sprites合并后的ID都是随机的数字,这样没法调用啊
估计你没试用过,如果以文件名上传是会有ID的,随机ID是会出现在复制SVG代码粘贴的情况下。
不好意思,还真是,我之前一直都是找到svg图标复制代码粘贴的,还没试过上传,用了压缩工具好久了,感谢开发这样的工具,方便很多
妙啊.
这个方案不错.
https://yoksel.github.io/relative-clip-path/
大佬 找到这种工具了,正好解决了目前遇到的一些问题,感谢
请问这样svg需要满足什么样的条件呢,我随便用的svg好像没法用
看了博主的不少关于SVG文章,想深入学习下,想问下有啥SVG书籍推荐嘛~~?
SVG这块没关注过。
实现背景剪裁型的图标可能有应用场景,如果只是普通的小图标,为什么不用字体图标来实现呢?多色图标用clippath似乎也无法实现吧?
图标颜色用background-color控制,而且可以用渐变颜色,这个用svg实现没那么灵活。
一个是字体,用color控制颜色,一个是剪切,可以剪任何元素。
总之字体图标尺寸控制更方便,clippath颜色更多变。
沙发前排?!