实现跨浏览器的图标SVG Sprites的教程

作者:袖梨 2022-06-25

基于本文的目的,我会以一个像个人名片的东西来开始。它会简短地介绍一下我自己以及显示3个和我工作相关的网络档案。

实现跨浏览器的图标SVG Sprites的教程

从上面的截图你可以看到我使用了三个图标(Twitter,Dribble 和 Github)象征着我的网络档案。这些图标我是从 flaticon 下载到的,这是一个具有各种不同图标和符号的网站,并且每个图标都提供矢量和光栅格式。

PNG 和 SVG


我们会在支持SVG的浏览器中使用SVG的格式,然后在不支持svg的浏览器中使用PNG格式的图标。

通常我使用Sketch来输出我的PNG图标和SVG图标。

实现跨浏览器的图标SVG Sprites的教程

简单的SVG实现

在上面的截图中你会注意到我将分组和图形都在左侧面板进行了适当的命名。(Adobe Illustrator在图层面板中有个相似的视图)。将资源正确地命名是很重要的,这不仅仅让它们保持组织性,更是对后面的图标使用有很大帮助。

输出SVG


现在我会将这些图标输出为SVG格式,我们可以用Sketch的slicing工具来轻松地完成这项工作。在Sketch的输出配置选项中你可以得到更多的信息从而明白它是如何工作的。我会将它们输出为单独的文件并放置在我项目中的images目录中。

通常地,你要在网站中展示一张图片你需要通过一个元素的src属性中来指向这个资源,类似下面这样:



然而,对于SVG来说我们可以有几种不同的方法来在HTML文档中使用它们。举个例子,我们可以使用直观的SVG代码来描述一张图片。代码可能会是这样:



   
    twitter-icon
    Created with Sketch.
   
   
       
           
       

   



这是我上面输出的其中一个图标,是基于XML的格式的呈现。这些代码几乎就像一段HTML一样,这意味着我们可以插入这段代码到页面中。

在HTML中添加inline SVG


让我们以一个基础的HTML页面开始,里面包含了3个赋予了链接的PNG图标,以及它们的容器:


   
       
Twitter
   
   
       
Dribbble
   
   
       
GitHub
   


现在我会开始复制上面SVG图标代码并黏贴到这里面,但我会忽略这段说明文件编码方式和其他信息的代码。因为在HTML文档中已经包含了这部分的信息,我们无需复制进去。



在这个HTML页面中,我已经将SVG放在了PNG图标的正上方。现在我要把PNG图片的代码注释掉防止它再SVG图片后面再出现一次。

清理 SVG

接着我准备清理一下上面的SVG代码。移除掉那些可选的元素属性,因为我要移除的这些属性并不会影响SVG的表现。下面是优化后跟优化前的代码对比,但他们表现效果是一样的:


   
    twitter-icon
    Created with Sketch.
   
   
       
           
       

   




   
       
   



注意我移除的那些元素。 , <desc>, 和 <defs>元素目前是不需要的,但在本文后面我们可能会用到它们。其中代表着分组的<g>元素相当于我在Sketch文档中的分组。默认地Sketch是将所有的东西放在一个页面中的,相当于组元素<g id=”Page-1”…。你可以把这个元素移除掉因为它对我们来说没有什么作用(在它里面的组元素才是重要的)。Sketch提供了一个选项让我们在输出之前处理SVG的清理工作,但你手动来清理一遍也没多大问题。<br /> <br /> 这部分的最后一步就是移除掉SVG标签上的height和width属性。它们会在我的CSS文件中来定义,如下所示:<br /> <br /> <svg viewBox="0 0 50 41" version="1.1" xmlns="http://www.w3.org/2000/svg"><br />     <g id="twitter-icon" fill="#55ACEE"><br />         <path d="M0,36.3461306 C0.803663004,36.4417973 1.62142857,36.4907387 2.45054945,36.4907387 C7.26336996,36.4907387 11.6928571,34.8346712 15.2086081,32.0564595 C10.71337,31.9727973 6.91959707,28.9779505 5.61245421,24.8624369 C6.23956044,24.9834054 6.88315018,25.0482297 7.54505495,25.0482297 C8.48205128,25.0482297 9.38956044,24.9217207 10.2516484,24.684955 C5.55201465,23.7334595 2.01117216,19.5466577 2.01117216,14.5276667 C2.01117216,14.4840811 2.01117216,14.4406802 2.01190476,14.397464 C3.3970696,15.1733243 4.98095238,15.6392838 6.66501832,15.693027 C3.90860806,13.8354685 2.09487179,10.6648018 2.09487179,7.07102252 C2.09487179,5.17264865 2.6014652,3.39321171 3.48571429,1.86328378 C8.55238095,8.13037387 16.1217949,12.2543829 24.6595238,12.6863604 C24.4844322,11.9282297 24.3934066,11.1375946 24.3934066,10.3257207 C24.3934066,4.60511261 28.9930403,-0.0328738739 34.6664835,-0.0328738739 C37.6210623,-0.0328738739 40.2908425,1.2251982 42.1648352,3.23844595 C44.5047619,2.77377928 46.7032967,1.91167117 48.6880952,0.724702703 C47.9210623,3.14351802 46.2923077,5.17357207 44.1712454,6.45565315 C46.2492674,6.20522072 48.2291209,5.6483964 50.0714286,4.82451802 C48.6941392,6.90185135 46.952381,8.72635135 44.9454212,10.1868378 C44.9652015,10.6310045 44.9750916,11.0777568 44.9750916,11.5269099 C44.9750916,25.2155541 34.6424908,41 15.7472527,41 C9.9459707,41 4.54615385,39.2852027 0,36.3461306 L0,36.3461306 Z" id="bird"></path><br />     </g><br /> </svg><br /> <br /> .icon {<br />     max-<br />     max-<br />     transition: .2s;<br />     -webkit-filter: drop-shadow(0 1px 0 #11222d);<br /> }<br /> <br /> 如果你跟着我的步骤你应该能在浏览器看到一个简洁锐利的矢量图。<br /> <br /> 提示:你可以通过浏览器的放大缩小来看看这个图片是否为SVG。这个图片不应该会受到你浏览器放大缩小而产生变化。<br /> <strong><br /> 提供Fallback</strong><br /> <br /> 如果你使用svg来在客户端显示,你会想它的浏览器支持程度如何,实际上svg可以在除了ie8(和ie8以下的)以及 Opera Mini 以外的所有浏览器上工作。但就目前来说,ie8在全球中只占到了4%的份额,Opera Mini 只有3%的份额。所以你没必要去为他们提供兼容,但尽管如此我还是会给给你一个解决方案。<br /> <br /> <a href="http://twitter.com/DavidDarnes" title="twitter profile"><br />    <svg viewBox="0 0 50 41" version="1.1" xmlns="http://www.w3.org/2000/svg"><br />        <g id="twitter-icon" fill="#55ACEE"><br />            <path d="M0,36.3461306 C0.803663004,36.4417973 1.62142857,36.4907387 2.45054945,36.4907387 C7.26336996,36.4907387 11.6928571,34.8346712 15.2086081,32.0564595 C10.71337,31.9727973 6.91959707,28.9779505 5.61245421,24.8624369 C6.23956044,24.9834054 6.88315018,25.0482297 7.54505495,25.0482297 C8.48205128,25.0482297 9.38956044,24.9217207 10.2516484,24.684955 C5.55201465,23.7334595 2.01117216,19.5466577 2.01117216,14.5276667 C2.01117216,14.4840811 2.01117216,14.4406802 2.01190476,14.397464 C3.3970696,15.1733243 4.98095238,15.6392838 6.66501832,15.693027 C3.90860806,13.8354685 2.09487179,10.6648018 2.09487179,7.07102252 C2.09487179,5.17264865 2.6014652,3.39321171 3.48571429,1.86328378 C8.55238095,8.13037387 16.1217949,12.2543829 24.6595238,12.6863604 C24.4844322,11.9282297 24.3934066,11.1375946 24.3934066,10.3257207 C24.3934066,4.60511261 28.9930403,-0.0328738739 34.6664835,-0.0328738739 C37.6210623,-0.0328738739 40.2908425,1.2251982 42.1648352,3.23844595 C44.5047619,2.77377928 46.7032967,1.91167117 48.6880952,0.724702703 C47.9210623,3.14351802 46.2923077,5.17357207 44.1712454,6.45565315 C46.2492674,6.20522072 48.2291209,5.6483964 50.0714286,4.82451802 C48.6941392,6.90185135 46.952381,8.72635135 44.9454212,10.1868378 C44.9652015,10.6310045 44.9750916,11.0777568 44.9750916,11.5269099 C44.9750916,25.2155541 34.6424908,41 15.7472527,41 C9.9459707,41 4.54615385,39.2852027 0,36.3461306 L0,36.3461306 Z" id="bird"></path><br />        </g><br />    </svg><br />    <!-- <a href="https://img.111cn.netimg/twitter-icon.png" class="js-smartPhoto-pc" target="_blank"><img alt="twitter" width="50" height="51" src="https://img.111cn.netimg/twitter-icon.png"> --><br /></a> </a><br /> <br /> 这是我上面3个图标中的其中一个图标,但你会注意到我的png图标也在里面,只是以注释地形式存在着。这个png图片就是我们的fallback。<br /> <br /> <strong>干掉注释</strong><br /> <br /> 首先我会移除掉上面的注释。我需要将<img>移动到<svg>元素里面,放在组元素<g>后面。<br /> <br /> 然后我会将<img>包裹在svg特有的元素foreignObject里面。如果浏览器不能识别svg的矢量信息,它会找到“foreign object”并使用它里面的<img>元素。我们也需要告诉浏览器如果支持矢量图标那就应该把“foreign object”忽略掉。这就是<switch>元素存在的目的了,我用它来将<g>元素和<foreignObject>元素包裹了起来。<br /> <br /> 下面是更新后的代码:<br /> <br /> <a href="http://twitter.com/DavidDarnes" title="twitter profile"><br />    <svg viewBox="0 0 50 41" version="1.1" xmlns="http://www.w3.org/2000/svg"><br />        <switch><br />            <g id="twitter-icon" fill="#55ACEE"><br />                <path d="M0,36.3461306 C0.803663004,36.4417973 1.62142857,36.4907387 2.45054945,36.4907387 C7.26336996,36.4907387 11.6928571,34.8346712 15.2086081,32.0564595 C10.71337,31.9727973 6.91959707,28.9779505 5.61245421,24.8624369 C6.23956044,24.9834054 6.88315018,25.0482297 7.54505495,25.0482297 C8.48205128,25.0482297 9.38956044,24.9217207 10.2516484,24.684955 C5.55201465,23.7334595 2.01117216,19.5466577 2.01117216,14.5276667 C2.01117216,14.4840811 2.01117216,14.4406802 2.01190476,14.397464 C3.3970696,15.1733243 4.98095238,15.6392838 6.66501832,15.693027 C3.90860806,13.8354685 2.09487179,10.6648018 2.09487179,7.07102252 C2.09487179,5.17264865 2.6014652,3.39321171 3.48571429,1.86328378 C8.55238095,8.13037387 16.1217949,12.2543829 24.6595238,12.6863604 C24.4844322,11.9282297 24.3934066,11.1375946 24.3934066,10.3257207 C24.3934066,4.60511261 28.9930403,-0.0328738739 34.6664835,-0.0328738739 C37.6210623,-0.0328738739 40.2908425,1.2251982 42.1648352,3.23844595 C44.5047619,2.77377928 46.7032967,1.91167117 48.6880952,0.724702703 C47.9210623,3.14351802 46.2923077,5.17357207 44.1712454,6.45565315 C46.2492674,6.20522072 48.2291209,5.6483964 50.0714286,4.82451802 C48.6941392,6.90185135 46.952381,8.72635135 44.9454212,10.1868378 C44.9652015,10.6310045 44.9750916,11.0777568 44.9750916,11.5269099 C44.9750916,25.2155541 34.6424908,41 15.7472527,41 C9.9459707,41 4.54615385,39.2852027 0,36.3461306 L0,36.3461306 Z" id="bird"></path><br />            </g><br />            <foreignObject><br />                <a href="https://img.111cn.netimg/twitter-icon.png" class="js-smartPhoto-pc" target="_blank"><img alt="twitter" width="50" height="51" src="https://img.111cn.netimg/twitter-icon.png"><br /></a>            </foreignObject><br />        </switch><br />    </svg><br /> </a><br /> <br /> 如果你跟着我的步伐到这里并写下我上面这段html,你会发现如果你的浏览器不支持svg它就会使用png图片来显示。(但我测试下来,这种方式会导致加载png图片,用注释的方式则不会,所以这并不是一种可取的方案)<br /> <br /> <strong>创建一个 SVG Sprite</strong><br /> <br /> svg sprites几乎跟image sprites一样。就最简单的形式来说,sprites是将几张图合并到一起的一张图片。每一张图都可以通过<a href="http://www.111com.net/cssdiv/css.html" target="_blank">css</a>和html来获取,一般通过sprite在一个展现“窗口”的指定的坐标来取到其中的某张图片(超出窗口部分的被截取隐藏掉)。<br /> <br /> 它最主要的优点就是能减少页面的加载时间,优化开发流程,以及保持页面中图片元素的一致性。其中第二和第三点可以很好地应用在svg sprites中。因为我们可以紧紧在一处地方更新我们的svg而不是让svg的代码块散落在文档的各个地方。<br /> <br /> 我会在页面的<head>元素的闭合标签</head>前面创建一个新的<svg>元素。这个<svg>元素将会包含我前面所有的图标。<br /> <br /> 下一步我要将图标都放到里面去。但我不需要把整个svg代码块都放进去,只要把组元素<g>和它的内容堆叠到头部的<svg>元素里就好了。<br /> <br /> <!doctype html><br /> <html lang="en"><br />   <head><br />       <meta charset="utf-8" /><br />       <title>David Darnes - Web Designer & Front-end Developer
     
     
     
         
             
         

         
             
             
         

         
             
         

     
 

提示:如果你熟悉Grunt的使用,你可以用一个插件来自动的将你所有单独的svg文件合并到一起。

隐藏!

现在我们把所有的图标都放在头部,我们需要把它们隐藏起来。在这个标签中添加一个属性display=”none”就能让所有的图标都不显示在页面的头部了。

定义每一个图标

我们下一步就是去定义每一个图标这样我门才能在页面中重用他们,定义的地方就在我们之前清理svg时删掉的元素里面,通过用它来包裹所有的组元素,就能把所有的图标都放进去,然后在页面任何地方使用了。



   
       
        David Darnes - Web Designer & Front-end Developer
       
       
       
           
               
                   
               

               
                   
                   
               

               
                   
               

           

       
   

使用图标


图标我们已经定义好了,但需要一个方法来引用,use 元素就是用来干这个事情的。元素允许我们把元素里面的任意元素取出放到页面的任何地方。我们是通过它的id的来取到它们的,这也是为什么在Sketch文档中命名我们的图标是件很重要的事情。

注意前面例子中元素的id,然后我是这样通过use元素来映射它们的,



跟着我的教程到这里,你会发现你的图片没有任何变化,但是你现在可以在任意的位置不限次数地(以任何尺寸)来使用它们。
让你的SVG Sprite更加完美

一个使用svg sprites的优点是你页面上的代码变地更加地简洁并且对于你的项目伙伴来说它的可读性也更加强了。但我们还可以进一步地优化。

下面我把在svg sprite中的元素替换为元素,另外我把viewbox属性从svg元素移动到元素上。



   
       
        David Darnes - Web Designer & Front-end Developer
       
       
       
           
               
                   
               

               
                   
                   
               

               
                   
               

           

       
   

使用元素不仅仅更加地语义化,至少在我的例子中,我们还可以避免元素上的viewbox属性的重复出现。另外我们现在还可以把之前移除的title和desc元素放回来,用他们来提高我们图标的可访问性。



   
       
        David Darnes - Web Designer & Front-end Developer
       
       
       
           
                Twitter
                Twitter account
               
           

           
                Dribbble
                Dribbble portfolio
               
               
           

           
                GitHub
                GitHub account
               
           

       
   

通过将组元素变为symbol

相关文章

精彩推荐