8

介绍一种全新的clipPath Sprites小图标技术

 3 years ago
source link: https://www.zhangxinxu.com/wordpress/2020/10/clip-path-sprites-icon/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

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元素图形效果示意

此时,可以把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);
}

此时就有如下图所示的效果:

transform缩放下的图标效果

方法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浏览器下的效果截图:

clip-path实现小图标效果示意

关于IE/Edge浏览器

CSS中有3个很高级属性IE浏览器也是支持的,分别是clip-path属性,filter属性和mask属性。

但是,请注意,这些支持其实并不是CSS规范中的那种支持,而是SVG元素衍生过来的语法,因为IE浏览器支持SVG,而SVG中有一些特性可以在CSS中使用,因此,IE浏览器也支持了部分高级CSS语法,就好像SVG中的fillstroke属性也可以在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代码了,如下截图示意:

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):

颜色变化GIF录屏示意

也可以是渐变效果(改成背景渐变即可),例如:

.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,结语就说这么多。

如果你觉得本文内容确实有点料,欢迎分享,也欢迎以评论方式进行交流,补充我不知道的信息,或者指出文章有表述不准确的地方。

2764.svg

(本篇完)1f44d.svg 是不是学到了很多?可以分享到微信
1f44a.svg 有话要说?点击这里


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK