家好,我是前端西瓜哥。
最近啊,西瓜哥我用 vite 去给一个项目构建(vite build)一个应用。打包结果是一个 html 和一些加了哈希的资源。
然后打包出来的文件一看,发现居然有好几个 1 Kb 以下的 SVG 文件。
我搜了下源码,这些 SVG 是这样被使用的:
<img src="./image/somIcon.svg">
不对呀,理论上小于 4 Kb 的静态资源,是会转成 base64 编码字符串,嵌入到其他资源中。
较小的资源体积小于 assetsInlineLimit 选项值 则会被内联为 base64 data URL。
build.assetsInlineLimit 默认值为 4096 (4kb)。
我发现使用库模式(打包成 index.es.js,使用该模式需要设置 build.lib 配置)时,是不会出现 SVG 文件的。
如果你指定了 build.lib,那么 build.assetsInlineLimit 将被忽略,无论文件大小或是否为 Git LFS 占位符,资源都会被内联。
所以一开始我以为我的配置设置的有问题,因为库模式没问题了。
我折腾了大半天,检查配置,查文档,assetsInlineLimit 给你加到 999999,安装其他版本的包,给引入的文件末尾加上 ?inline。各种尝试,都没用。
后来我用最新版的 vite 构建了一个新的 Vue 项目。
发现它这个官方给的 demo 打包出来的文件 SVG 都没做内联。
好家伙,我寻思 vite 本身就不支持 SVG 转 base64 编码内嵌。
走,去翻翻 vite 的 issue,然后找到了一个 3 年前的 issue,编号 1204。
这个 issue 标记为 enhancement,即它是一个增强功能,并不是 bug。
此外可以看到有两个 PR 是要解决这个 issue 的。
一个 PR 被关闭了,一个 PR 是打开着。我们去看看。
先看看被关闭的那个,PR 编号是 1716,是 vite 成员提的 PR。
他说他不赞成 SVG 转成 Base64 嵌入到 HTML,SVG 是个文本类的特殊图片格式,不是二进制,没必要再转一层 Base64,导致体积变大。
因为 Base64 需要用 4 个字符表达原来文本的 3 个字节,会增大 33~36% 的体积。
即希望结果是:
<img src='data:image/svg+xml;utf8,<svg ... > ... </svg>'>
而不是:
<img src="data:image/svg+xml;base64,PHN2ZyB4bWxu...c3ZnPg==">
虽然不打算转 Base64,但还是可以转 utf8 格式的 Data URL 的,一样可以实现内嵌的效果,而且体积更小,于是提了这个 PR。
这个 PR 是有问题的,有些情况没处理,比如转义,去掉 svg fragments 等。
然而过了一个月,这个 PR 还是没进展,说明 优先级并不高。
此时一位路过的野生程序员说他来搭把手。
于是这个 PR 关闭了,这位老哥创建了一个新的 PR。
加油啊,路过的程序员老哥。你是我们全村人的希望啊。
看看 PR。
两年前的 PR,至今仍是 Open 状态。
哦豁,凉了。
发生甚么事了?我瞅瞅。
看下 PR 的内容。引入了一个 mini-svg-data-uri 第三方包,来做 SVG 转 DataUrl,改了一些判断条件,因为和普通资源直接走转 base64 不同,SVG 是要直接用原来的文本内容的。改了了几个测试用例。
看着不少 review 和讨论,看着应该还行,有几个 vite 成员 approved 了。
最后时需要有人手动测试是否处理好了 SVG Segment 的情况。此时提 PR 的老哥不见了。
SVG Segment 是 SVG 的一个比较特殊的用法,大概是这样(来自 MDN)。
对于一个 SVG,我们可以用 view 标签指定某种情况下特定的 viewBox 视口范围。
<svg viewBox="0 0 300 100" width="300" height="100"
xmlns="http://www.w3.org/2000/svg">
<view id="one" viewBox="0 0 100 100" />
<circle cx="50" cy="50" r="40" fill="red" />
<view id="two" viewBox="100 0 100 100" />
<circle cx="150" cy="50" r="40" fill="green" />
<view id="three" viewBox="200 0 100 100" />
<circle cx="250" cy="50" r="40" fill="blue" />
</svg>
然后在使用的时候通过 icon.svg#<id> 指定 id,来修改 SVG 最终展示的 viewBox。
<!-- 正常视口 -->
<img src="example.svg" alt="three circles" width="300" height="100" />
<!-- 视口切换到绿色圆的位置 -->
<img src="example.svg#three" alt="blue circle" width="100" height="100" />
效果:
回到 PR。
好久,后面有人帮着测试了,发现有问题。然后就,没有然后了,此外还有因为长期没合入出现的合并冲突。
啊这。
我 fork 了 vite 项目,把这位老哥的修改应用到最新版本上,然后 build 了一下,并拿去构建我的一个 demo 项目,结果 SVG 成功变成了 Base64。
然后我运行测试相关的命令,各种不对。
因为有些原来转换为正常 url 的,现在会转成 base64,就匹配不上了。我还发现 css url 的逻辑还有点问题,拿到了一个错误的 none 值。
诶,感觉要提 PR 的话,要修正原来的测试用例,并补充一些新的测试用例,还要处理 css 的情况。行吧,以后再看看。
回到我一开始的需求,行,你不给我转 Base64 是吧?我通过 ?raw 直接拿到 SVG 文本内容,给你动态转成 Base64。
import iconSvg from './image/someIcon.svg?raw'; // 这个会拿到 "<svg ...>...</svg>"
const toSVGDataUrl = (str: string) => {
const base64 = btoa(str);
return `data:image/svg+xml;base64,${base64}`;
};
<img :src="toSVGDataUrl(iconSvg)" />
还行(又不是不能用)。
这次经历,我认识到 一个大型的开源项目的维护者,对单元测试是非常看重的,因为它影响着千千万万的开发者,必须保证在绝大多数情况下能正确运行。
突然想起之前 VSCode 我更新了最新版本,结果运行一段时间就会报错需要重启。
然后就是 vite 维护者 非常注重性能,毕竟是一个很重要的构建工具。SVG 是可以 Base64 的,实现逻辑也很简单,和其他图形走一样的逻辑。
但 SVG 可以直接用原本的文本数据,更小,有优化空间。因为体积可以优化,所以维护者就宁缺毋滥,宁可丢掉这个功能。
要是我,我可能就先图省事,直接支持 Base64 了,然后有机会再优化(通常不了了之)。
然后是优先级,优先级不高,维护者就是不会主动去实现。
此时就需要社区的力量了,如果你很需要某个功能,就要积极提 PR,积极讨论并主动推进,否则可能像这个 PR 一样,半途而废。
我是前端西瓜哥,关注我,学习更多前端知识。
从2018“草莓音乐节”的宣传视频得到的灵感,海报的主题是错位拼贴分割重组,对我这种设计渣渣而言,看中的是其平面化,也就是说,用SVG+CSS3动画完全可以玩转。因为只涉及一些基础元素的位移、缩放构成的转场效果,相对来说比较简单,但创意很开脑洞。因为宣传视频比较长,所以把它分割成了几个部分,依次来完成。
首先放上一张静态图,来分析动效。一共涉及三种动效,位移,旋转,渐隐渐现。当把元素分析完成后,现在就要在AI中进行相应的分层,便于SVG代码的解读。在AI中,对应各个部分,放置到不同的图层中,每个图层做好命名,依次为底图base、向上移动moveUp、向下移动moveDown、中间大圆baceCenter、中间小圆centerCircle、周围圆点dot。因为涉及Y轴方向的位移动画,所以在底图的绘制时,需要移动的部分要超出画板。
相信很多自学的小伙伴都想学习web前端,可以关注小编后私信【学习】可以免费领取学习地址/案例教程/2018最新的一套学习教程,让学习有方向。
CSS3部分相对来说比较简单,旋转动画transform:rotate(),位移动画transform:translateY(),因为小圆点只是装饰作用,所以只设计了两种类型的透明度的改变,任意分成了两组。
@keyframes centerCircle{ 0%{transform:rotate(0deg); transform-origin:center center} 100%{transform:rotate(-360deg); transform-origin:center center} } #centerCircle{animation:centerCircle linear 4s infinite ; } /*中心旋转圆设置*/ @keyframes moveUp{ 0% {transform: translateY(0)} 100% {transform: translateY(-70px)} } #moveUp {animation:moveUp linear 4s infinite alternate; } /*向上移动*/ @keyframes moveDown{ 0% {transform: translateY(0)} 100% {transform: translateY(70px)} } #moveDown {animation:moveDown linear 4s infinite alternate; } /*向下移动*/ @keyframes dot1{ 0%{opacity:0} 100%{opacity:1} } #dot1{animation:dot1 ease 2s infinite alternate}/*渐隐渐现小圆点样式1*/ @keyframes dot2{ 0%{opacity:0.7} 70%{opacity:0} 100%{opacity:0.3} } #dot2{animation:dot2 ease 2s infinite alternate}/*渐隐渐现小圆点样式2*/
先跑起来看看效果,大块的色块,浓郁的色彩,似乎还不错。
go on。接下来如图:
三个圆从中心依次出现放大,这是一个基础的缩放动效transform:scale()。这里就要用到控制SVG描边属性缩放文章中提到的描边属性不受缩放控制的神句了,三个圆的描边属性后面都要加上vector-effect:non-scaling-stroke,由于出现的顺序不同,又要叠加其他动画,为了避免自己搞不清各部分动画的时间次序(毕竟不是AE,时间轴不直观),所以绘制了一个简单的时间轴。
动画属性定义中,只要开始的时间依次设置好久可以了,另外关于缩放的倍数,由于从无到有,初始值一定是scale(0),结束的值和定义的圆的半径有关,可以多调整几个值,得到最满意的效果。
@keyframes purpleCircle{ 0% {transform:scale(0); transform-origin:center center} 100% {transform:scale(1.5);transform-origin:center center} } #purpleCircle{animation:purpleCircle linear 1.5s 1s both} /*最大圆 1S后开始扩大*/ @keyframes whiteCircle{ 0% {transform:scale(0); transform-origin:center center} 100% {transform:scale(2);transform-origin:center center} } #whiteCircle{animation:whiteCircle linear 1.5s 1.5s both} /*中间圆 1.5S后开始扩大*/ @keyframes blueCircle{ 0% {transform:scale(0); transform-origin:center center} 100% {transform:scale(1);transform-origin:center center} } #blueCircle{animation:blueCircle linear 1.5s 2s both} /*最小圆 2S后开始扩大*/
合成后效果如下:
go on……
如上图所示,当白色圆扩展到整个画布后,中间出现两个三角,三角的变形动画如下:
为了方便定义属性,我以三角形断开时的形状为基准,因为第一步是Y轴向的缩放,X轴不变,所以仅定义transform:scaleY(),而在第二步变形中,X轴向与Y轴向缩放时不同步的,因此要分开写成transform:scaleX()scaleY()。为了确保第一步统一的变形效果,要先把两个三角都放在一个组中,给这个组进行变形动画。
<g id="triangle"> <polygon id="triLeft" points=""/> <!--左侧三角--> <polygon id="triRight" points=""/> <!--右侧三角--> </g>
动画属性中需要注意的是transform-origin变形基点的定义。当两个三角断开后,基点对应如下:
@keyframes triangle{ 0% {transform:scaleY(0);transform-origin:} 100%{transform:scaleY(1);transform-origin:} /*变形的基点为交点坐标*/ } #triangle{animation:triangle linear 0.5s 2.5s both} /*两个三角形Y轴向扩大*/ @keyframes triLeft{ 0% {transform:scaleY(1)scaleX(1);transform-origin:} /*变形的基点为左侧边中点坐标*/ 100%{transform:scaleY(0.15)scaleX(0.05);transform-origin:} } #triLeft{animation:triLeft linear 0.5s 3s both} /*左侧三角形向左水平缩小*/ @keyframes triRight{ 0% {transform:scaleY(1)scaleX(1);transform-origin:} /*变形的基点为右侧边中点坐标*/ 100%{transform:scaleY(0.6)scaleX(0.5);transform-origin:} } #triRight{animation:triRight linear 0.5s 3s both} /*右侧三角形向右水平缩小*/
看下效果,似乎不错,截止到这一步,第一阶段的动画才算完成,之所以称作第一阶段,是因为这时原底图可以退出舞台,全新的下一幕开始了。
这里右侧圆形实现这种效果有点复杂,在SVG剪切蒙版属性clip-path文章中详细说明了实现过程。 各部分图形的顺序至关重要。
来看下效果
好了,第二部分也正式结束,第三部分相对简单一些,基本只有透明度的属性变化。和第一部分底图的圆点的动效基本相似,无非图形更复杂一些,就不再赘述,直接放上最终效果吧。
唯一需要说的是左上角类似渐变网格的圆点,使用了运动的渐变蒙版来实现。
首先需要定义一个蒙版的位移动效@keyframes maskXY{ 0%{transform:translate(0, 0);} 100%{transform:translate(-70px, -70px); } /*向左上角位移*/ } #maskXY{animation:maskXY linear 3s 5s both}
渐变类型的定义和图形是AI导出时生成的,一般不用修改,只是各种定义比较多,别把自己绕进去就行。
击右上方红色按钮关注“web秀”,让你真正秀起来
通常我们说的 Web 动画,其实包含了以下三大类:
1、CSS3 动画
2、javascript 动画(canvas)
3、html 动画(SVG)
3 种动画各有优劣,实际应用中根据情况作出取舍,本文讨论的是我认为 SVG 中在实际项目中非常有应用价值 SVG 线条动画。
在 2003 年一月,SVG 1.1 被确立为 W3C 标准。 参与定义 SVG 的组织有:太阳微系统、Adobe、苹果公司、IBM 以及柯达。 与其他图像格式相比,使用 SVG 的优势在于:
1、SVG 可被非常多的工具读取和修改(比如记事本)
2、SVG 与 JPEG 和 GIF 图像比起来,尺寸更小,且可压缩性更强。
3、SVG 是可伸缩的
4、SVG 图像可在任何的分辨率下被高质量地打印
5、SVG 可在图像质量不下降的情况下被放大
6、SVG 图像中的文本是可选的,同时也是可搜索的(很适合制作地图)
7、SVG 可以与 Java 技术一起运行
8、SVG 是开放的标准
9、SVG 文件是纯粹的 XML
10、SVG 的主要竞争者是 Flash。
与 Flash 相比,SVG 最大的优势是与其他标准(比如 XSL 和 DOM)相兼容。而 Flash 则是未开源的私有技术。
可缩放矢量图形,即SVG,是W3C XML的分枝语言之一,用于标记可缩放的矢量图形。(摘自MDN)
上面代码中,先谈谈 svg 标签:
有了 svg 标签,我们就可以愉快的在内部添加 SVG 图形了
SVG 线条动画基础入门知识
MDN Web 有基本形状的文档,建议去看看。包含矩形、圆形、椭圆、线条、多边形、折线等等。
好了,有了基本的了解,我们继续今天的话题,SVG 线条动画。
先看看效果图,然后想想如果是你,该怎么实现这个效果了?
SVG 线条动画基础入门知识
ok,像以前一样,我们先来解析一下(按步骤实现):
1、svg画个按钮(基础形状-矩形)
2、矩形只保留下方底边
3、实现鼠标:hover事件 + 动画效果
svg画个按钮
<div class="button"> <svg viewBox="0 0 320 60" version="1.1" xmlns="http://www.w3.org/2000/svg" > <rect class="shape" height="60" width="320"></rect> </svg> <div class="hover-text">Web 秀</div> </div>
添加样式
.button { position: absolute; width: 320px; height: 60px; top: 50%; left: 50%; transform: translate(-50%, -50%); } .hover-text { position: absolute; line-height: 60px; width: 320px; top: 0; color: #1199ff; font-size: 28px; text-align: center; cursor: pointer; } .shape { fill: transparent; stroke-width: 4px; stroke: #1199ff; }
SVG 线条动画基础入门知识
button垂直水平居中、shape透明填充,边框宽度4px,边框颜色#1199ff。
也许你会对fill、stroke-width等属性有点懵,下面看看他们的描述:
重点讲讲能够实现线条动画的关键属性 stroke-dasharray 。属性 stroke-dasharray 可控制用来描边的点划线的图案范式。
SVG 矩形只留底边
这里我们给按钮添加stroke-dasharray:
.shape { ... stroke-dasharray: 160 520; stroke-dashoffset: -460; }
SVG 线条动画基础入门知识
SVG hover动画
.button:hover .hover-text { transition: 0.5s; color: pink; } .button:hover .shape { -webkit-animation: draw 0.5s linear forwards; animation: draw 0.5s linear forwards; } @keyframes draw { 0% { stroke-dasharray: 160 520; stroke-dashoffset: -460; stroke-width: 4px; } 100% { stroke-dasharray: 760; stroke-dashoffset: 0; stroke-width: 2px; stroke: pink; } }
hover时,改变文字颜色,利用stroke-dasharray和stroke-dashoffset实现动画效果。
后续文章将会详述非规则图形,如何使用 PS + AI 生成 path 路径,实现 SVG 动画,敬请期待。
喜欢小编的点击关注,了解更多知识!
源码地址和源文件下载请点击下方“了解更多”
*请认真填写需求信息,我们会在24小时内与您取得联系。