整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

第9节:图形绘制18-SVG矢量图导出

第9节:图形绘制18-SVG矢量图导出

一下死量图。什么是死量图?死量图是指图形放大缩小的时候,图形质量没有变化,仍然可以保证很清晰。

麦地基金赛本身的mode文件,mode文件是死量图格式,同时还支持另外一种格式的死量图叫svg格式。死量图最大的好处是可以通过浏览器,普通第三方软件浏览器app去打开。大家看浏览器打开的死量图,软件做出来的死量图几乎是一样的。

当投稿的期刊的时候用svg格式的死量图切开设一般就可以去编辑,用第三方的这样来编辑。如果只给mode格式是无法进行编辑的,这是svg格式的好处。

对于网络图、演化图,除了热力图之外的密度图,一般的网络图、演化图、演化图都可以用svg格式的死量图来去输出svg格式。死量图也可以在word当中去输出编辑,word当中关于二零二一、二零一九都有死量图格式的图形插入的功能。

要整理你的页面重量,但是要保持所有的酷功能吗?继续阅读,看看一个开发人员如何摆脱SVG,并在它的位置使用CSS。

获得高级管理人员手册的重要趋势、技巧和战略,以竞争和赢得数字经济。

在这个假期过后,我们中的许多人都想减掉一点体重,那就是体重。在我的应用中,我广泛地使用SVG元素作为图像、徽标和图标。直到最近,我都直接在HTML中呈现SVG元素。这是最简单的方法。正如您可能通过我的intro语句所猜测的那样,我一直在通过从HTML中删除SVG元素来减少页面权重。它的效果如何?在进行更改之前,主页是14kb (77kb解压缩)。更改后,主页为6kb(未压缩的30kb)。这是每一页的“超过有线”字节的57%。我到底做了什么,我做了哪些权衡来获得一个更小的页面?让我们看看以前如何使用SVG。

这是原始的SVG:

<?xml version="1.0" encoding="UTF-8"?>

<svg fill="#fff" class="issue-icon" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">

<path d="m8 0c-4.418 0-8 3.582-8 8s3.582 8 8 8 8-3.582 8-8-3.582-8-8-8zm0 14c-3.309 0-6-2.692-6-6s2.691-6 6-6c3.307 0 6 2.692 6 6s-2.693 6-6 6z" clip-rule="evenodd" fill-rule="evenodd"/>

<path d="M8.5,3h-1C7.224,3,7,3.224,7,3.5v6C7,9.776,7.224,10,7.5,10h1 C8.776,10,9,9.776,9,9.5v-6C9,3.224,8.776,3,8.5,3z" clip-rule="evenodd" fill-rule="evenodd"/>

<path d="M8.5,11h-1C7.224,11,7,11.224,7,11.5v1C7,12.776,7.224,13,7.5,13h1 C8.776,13,9,12.776,9,12.5v-1C9,11.224,8.776,11,8.5,11z" clip-rule="evenodd" fill-rule="evenodd"/>

</svg>

我将它定义为一个Rails“helper”,它将直接呈现在HTML中。这个元素在页面上重复了很多次,每次我们必须发送完全相同的SVG字符串,该字符串将相同的字节数添加到页面大小。为了解决这个问题,我将SVG代码移动到我的图像目录中,然后我使用链轮来“内联”图像通过一个数据url。

数据URL如何工作?通常,在CSS元素背景下的URL会说“出去,在不同的URL中获取该资产”。相反,一个“数据”URL会编码呈现图像所需的所有数据,而无需创建新的网络请求。这里有一个例子:

background: url("data:image/svg+xml;charset=utf-8,

%3Csvg

version='1.1'

xmlns='http://www.w3.org/2000/svg'

xmlns:xlink='http://www.w3.org/1999/xlink'

width='512'

height='512'

viewBox='0 0 512 512'

%3E%3Cpath d='M224 387.814v124.186l-192-192 192-192v126.912c223.375 5.24 213.794-151.896 156.931-254.912 140.355 151.707 110.55 394.785-156.931 387.814z'

%3E%3C/path%3E

%3C/svg%3E");

这个“url”包含整个图像内容,不需要发出HTTP请求。

在链轮中,当前支持的数据URL通过创建一个Base64字符串来支持,但是在以后的版本中,它将是URL转义,以避免使用Base64的额外开销。您可以阅读更多关于为什么不使用base64 SVG的内联图像。

以前,我说过我用链轮来做这个改变。在我的项目中,这是sassrails添加警告的咒语。svg作为我的CSS的数据url:

.warning-svg {

width: 16px;

height: 16px;

display: inline-block;

background: asset-data-url("warning.svg");

}

资产数据url被解释为一个指令,它接受警告的内容。svg图像和“inlines”它们使得不需要额外的HTTP请求。如果你用的是ERB,它可能是这样的:

.warning-svg {

width: 16px;

height: 16px;

display: inline-block;

background: url(<%=asset_data_uri 'warning.svg' %>);

}

现在,当您访问该页面时,SVG元素仅通过应用程序发送一次。css,然后被重新使用很多次,通过war- svg类。这意味着为最终用户下载HTML所需的时间更少,而且由于这些资产是与未来的高速缓存头一起服务的,所以它们只会被浏览器下载一次。更好的是,该站点正在Cloudflare CDN的后面服务,因此对于稍微大一点的CSS文件,应用服务器上没有额外的负担。

您可以看到我实现此更改的pull请求。

有什么缺点吗?这种方法(对我来说)最大的问题是,我失去了通过CSS控制SVG元素填充(颜色)的能力。以前在HTML中使用SVG,如果我想改变元素的颜色,很简单,我在CSS中做了。这里有一个例子,可以用CSS将填充色改为红色。

一旦我将SVG元素移出页面,我就无法通过纯CSS进行这种类型的修改。对于这种情况,我决定转换元素,使悬浮状态变得明显:

如果颜色变化是绝对需要的,那么我可以生成两个具有不同填充值的SVG元素,并更改鼠标悬空的背景元素。您可以在其他选项上看到一个堆栈溢出线程。

除了在主页上使用“警告”SVG之外,我还在“repo show”页面上使用它,但是它的填充不同。它是灰色的而不是白色的。在这种情况下,去掉颜色变化是不合适的;但是,我可以使用不透明的CSS属性来近似一个颜色的变化,这将影响SVG元素。

如果您不想在CSS中使用数据URL,您也可以通过标记将其呈现为普通图像。您还可以使用使用标记,它允许您通过HTML发送元素,但之后再使用和操作,就好像它是直接在HTML中一样。

在我的例子中,所有呈现的元素都存在于我的绝大多数页面中,所以将它们放在那些会被浏览器和我的CDN缓存的地方是有意义的。

一些关于将SVG元素转换为内联CSS元素的说明:

  • 您需要确保将高度和宽度设置为元素,因为SVG只是“背景”。

  • 您还需要确保SVG正在被格式化并正确地服务。对我来说,我有一个SVG元素,它缺少xml声明:

<?xml version="1.0" encoding="UTF-8"?>

和相同的一个失踪了xmlns=" http://www.w3.org/2000/svg "属性。如果您在浏览器中通过CSS检查器单击图像URL,它应该显示是否存在错误。您还需要显式地在图像中设置填充属性,否则,它们将默认为黑色。

总的来说,这一变化相当简单,57%的小页面也不太破旧。

虽然仍然有可能希望将SVG元素直接放到HTML中,但是考虑页面的权重和成本。

绍一些你可能没用过的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,有个xy坐标,我们现在宽高都是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>

效果如下

是不是已经自适应了?

不过还是有点问题,仔细观察,圆角处有些不自然,感觉被裁剪了一样

造成这种现象的原因有两个:

  1. SVG描边是居中描边,并且不可修改
  2. SVG默认是超出隐藏的,也就是自带overflow:hidden

我们把边框改大一点就可以很明显的观察到描边是居中的

由于是居中的,所以在不做修改的情况下,我们看到的其实只有原边框的一半,利用这个原理我们其实可以实现常说的0.5px边框,有兴趣的可以参考我之前这篇文章:使用svg描边来实现移动端1px

在这里,我再介绍一种新的方式,那就是利用 CSS calc !

没错,在 SVG中也可以使用CSS函数,比如我们这里边框是4px,那么坐标xy就应该是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的尺寸自适应

这里小结一下

  1. SVG的尺寸改为`百分比
  2. 由于是居中描边,所以要修正一下坐标和大小

除此之外,还能直接加上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]

六、总结一下

以上就是本文的全部内容了,主要介绍了如何利用 SVGCSS各种的优势来实现更加灵活的布局,下面总结一下

  1. 设计软件导出的SVG都是固定尺寸的,不能自适应尺寸
  2. SVG很擅长渐变边框,而CSS很擅长自适应尺寸,得想办法取长补短
  3. SVG部分属性支持百分比类型,可以实现尺寸自适应
  4. SVG描边是居中描边,并且不可修改,所以需要调整圆角矩形的坐标的大小
  5. SVG中也支持 CSS部分特性,比如calc计算函数
  6. SVG还支持内嵌style标签,直接插入CSS代码
  7. 可以将SVG转为内联CSS代码,在支持SVG特性的同时极大的保证了HTML的整洁
  8. 借助SVG可以很轻松的实现渐变虚线边框
  9. SVG中还支持CSS动画,可以实现虚线滚动动画

你可能已经发现SVG并不是非常孤立的一门语言,现在还能和 CSSHTML联动起来,充分发挥各自的优势,这样才能事半功倍 。

[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

作者:XboxYan

来源-微信公众号:前端侦探

出处:https://mp.weixin.qq.com/s/VH2U-jqm3cXI0yQFrR3adQ