请使用firefox,chrome等最新浏览器浏览本站。

svg sprite以及自定义主题探索

css3 阿豹 270次浏览 1个评论 扫描二维码
最近业务开发中遇到了一些svg相关的问题, 比如svg <use>的内容如何实现主题自定义? svg sprite如何与项目结合使用?现在对遇到的问题以及解决方案做一下总结。
先来说一下svg相关的特性:

svg简介

svg即可缩放矢量图形 (Scalable Vector Graphics)的简称,是一种用来描述二维矢量图形的XML标记语言。 SVG图形不依赖于分辨率, 因此图形不会因为放大而显示出明显的锯齿边缘。

svg sprite

svg<symbol>在svg中主要适用于定义可复用的符号,而这些定义在symbol元素的形状将不会被展示出来,而是通过use元素引用来显示。<use>可以在任何地方复用svg文件中定定义的形状,包括<g>、<symbol>、<defs>。在使用<use>时,它必须要有一个id,这样<use>通过xlink:href的值找到该形状的引用。注意: 一定要在前面加一个#,这样才能引用ID成功。
通常在使用SVG的时候, 我们是直接写到svg标签当中:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 44 44">
  <path fill="inherit" fill-rule="evenodd" d="M34.538 8L38 11.518 17.808 32 8 22.033l3.462-3.518 6.346 6.45z"></path>
</svg>
这样svg直接在页面中显示。
svg sprite是<symbol>和<use>结合:
// define
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="position:absolute;width:0;height:0">
  <symbol id="check" viewBox="0 0 44 44">
    <path fill="inherit" fill-rule="evenodd" d="M34.538 8L38 11.518 17.808 32 8 22.033l3.462-3.518 6.346 6.45z"></path>
  </symbol>
</svg>

// use
<svg><use xlink:href="#check"/></svg>

svg sprite优势

  1. 少量的http请求
  2. 图标能被缓存方便复用
  3. 每个svg图标可以更改大小颜色
  4. 整合、使用以及管理起来非常简单

svg结构化分组标签

svg中有四个主要的元素用于在文档中定义、引用svg代码。这些元素使得重用svg元素变得容易,同时保持代码的简洁性和可读性。
<g>
<g>元素用于给逻辑上相联系的图形元素分组。当你想要应用某个样式,并希望这个样式能被组中的所有元素继承,分组元素<g>非常好用,特别是当你想要给某组元素应用动画,同时还需要保持它们彼此的空间关系的时候。
<defs>
<defs>元素用来定义你之后要重用的元素。当你想要创建某一类在文档中要多次使用的“模板”时,使用<defs>定义元素。在<defs>中定义的元素不会在画布中渲染出来,除非你在文档的某个位置调用了它们。
<symbol>
<symbol>元素结合了<defs>和<g>元素的优点,将定义模板的元素组合在一起,以便之后在文档中的其他位置引用。和<defs>不同,<symbol>通常不用于定义图案,但是经常用于定义图标,在整个文档中都可以被引用。<symbol>元素相比其它两个元素有一个非常重要的优点:它接受一个viewBox属性,可以让它在任何视窗中自适应大小缩放渲染。
<use>
<use>元素用于引用文档中其它位置定义的元素。你可以重用已有的元素,类似于图形编辑器中的复制粘贴功能。它可以重用单个元素,也可以重用一组用<g>、<defs>或<symbol>定义的元素。要使用一个元素,你需要通过一个标识对该元素进行引用——一个ID,即use中的xlink:href属性。你可以给use元素应用样式,这些样式也会级联应用到use元素的内容中去。

shadow dom

在svg<use>元素中,引用元素的内容被复制到一个文档片段中保存,这个文档片段是由<use>保留着。<use>在这里就是一个shadow Host。所以,<use>的内容都表示在一个shadow文档片段中。也就是说,它们就在那里,但是并不可见,并不能在主文档中被CSS选择器和JavaScript选中。

<use>描述属性

svg元素还可以使用描述属性添加样式。描述属性是在元素上设置CSS属性的简写方式。描述属性权重比较低,可以被其它所有的样式定义覆盖:外部的样式表,内部的样式块以及内联样式。描述属性唯一超过的就是继承样式。就是说,描述属性只可以覆盖文档中的继承样式,但是会被其它所有的样式声明覆盖

svg <use>内容自定义主题

由于不能直接通过css选择器对use的shadow dom中的图形标签进行选择,  因此在为图标定义颜色时需要从另一个角度去解决。

使用inherit实现单色主题自定义

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="__ANTD_MOBILE_SVG_SPRITE_NODE__" style="position:absolute;width:0;height:0">
  <defs>
    <symbol id="check" viewBox="0 0 44 44">
      <path fill="inherit" fill-rule="evenodd" d="M34.538 8L38 11.518 17.808 32 8 22.033l3.462-3.518 6.346 6.45z"></path>
    </symbol>
  </defs>
</svg>
<svg class="inherit">
  <use xlink:href="#check"></use>  
</svg>

<style>
  svg.inherit {
    fill: red;
  }
</style>
当改变svg.inherit的fill属性时, svg颜色就会切换

使用css currentColor变量实现单色主题自定义

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="__ANTD_MOBILE_SVG_SPRITE_NODE__" style="position:absolute;width:0;height:0">
  <defs>
    <symbol id="check-circle-o" viewBox="0 0 48 48">
      <g fill-rule="evenodd">
        <path fill="currentColor" d="M24 48c13.255 0 24-10.745 24-24S37.255 0 24 0 0 10.745 0 24s10.745 24 24 24zm0-3c11.598 0 21-9.402 21-21S35.598 3 24 3 3 12.402 3 24s9.402 21 21 21z"></path>
        <path fill="currentColor" d="M12.2 23.2L10 25.3l10 9.9L37.2 15 35 13 19.8 30.8z"></path>
      </g>
    </symbol>
  </defs>
</svg>
<svg class="currentColor">
  <use xlink:href="#check-circle-o"></use>  
</svg>

<style>
svg.currentColor {
  color: red;
}
</style>
当改变svg.currentColor的color属性时, svg颜色就会切换

使用inherit和css currenColor实现双色主题自定义

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="__ANTD_MOBILE_SVG_SPRITE_NODE__" style="position:absolute;width:0;height:0">
  <defs>
    <symbol id="check-circle-o" viewBox="0 0 48 48">
      <g fill-rule="evenodd">
        <path fill="inherit" d="M24 48c13.255 0 24-10.745 24-24S37.255 0 24 0 0 10.745 0 24s10.745 24 24 24zm0-3c11.598 0 21-9.402 21-21S35.598 3 24 3 3 12.402 3 24s9.402 21 21 21z"></path>
        <path fill="currentColor" d="M12.2 23.2L10 25.3l10 9.9L37.2 15 35 13 19.8 30.8z"></path>
      </g>
    </symbol>
  </defs>
</svg>
<svg class="currentColor">
  <use xlink:href="#check-circle-o"></use>  
</svg>

<style>
svg.currentColor {
  fill: red;
  color: green;
}
</style>

当改变svg.currentColor的fill或color属性时, svg颜色就会切换

使用css变量

使用css变量,你可以给<use>的内容添加样式,而不需要强制浏览器覆盖任何描述属性的值。
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="__ANTD_MOBILE_SVG_SPRITE_NODE__" style="position:absolute;width:0;height:0">
  <defs>
    <symbol id="check-circle-o" viewBox="0 0 48 48">
      <g fill-rule="evenodd">
        <path fill="red" style="fill: var(--primary-color)" d="M24 48c13.255 0 24-10.745 24-24S37.255 0 24 0 0 10.745 0 24s10.745 24 24 24zm0-3c11.598 0 21-9.402 21-21S35.598 3 24 3 3 12.402 3 24s9.402 21 21 21z"></path>
        <path fill="green" style="fill: var(--secondary-color)" d="M12.2 23.2L10 25.3l10 9.9L37.2 15 35 13 19.8 30.8z"></path>
      </g>
    </symbol>
  </defs>
</svg>
<svg class="variable">
  <use xlink:href="#check-circle-o"></use>  
</svg>

<style>
svg.variable{
  --primary-color: #0099CC;
  --secondary-color: #FFDF34;
}
</style>
改变–primary-color和–secondary-color,就能看到主题发生了改变。内联style标签会覆盖描述属性,支持CSS变量的浏览器会使用这些变量作为图形的填充颜色。不支持CSS变量的浏览器将使用fill属性值。

结合webpack实现svg sprite

使用svg-sprite-loader实现svg sprite
和atool-build结合使用,在webpack.confg.js添加如下配置:
const path = require('path');

module.exports = (webpackConfig) => {
  const svgDirs = [
    path.resolve(__dirname, 'src/assets/svg'), // 业务svg目录
  ];
  
  // 避免svg被多个loader处理
  webpackConfig.module.loaders.forEach(loader => {
    if (loader.test && typeof loader.test.test === 'function' && loader.test.test('.svg')) {
      const loaderNew = loader;
      loaderNew.exclude = svgDirs;
    }
  });
  webpackConfig.module.loaders.unshift({
    test: /\.(svg)$/i,
    loader: 'svg-sprite',
    include: svgDirs,
  });
  return webpackConfig;
};


喜欢 (1)or分享 (0)
发表我的评论
取消评论
表情 贴图 加粗 删除线 居中 斜体 签到
(1)个小伙伴在吐槽
  1. 从百度点进来的,学习学习,呵呵!
    爱就爱啦2018-07-03 10:17 回复