1. 程式人生 > >使用SVG symbols建立圖標系統

使用SVG symbols建立圖標系統

blog 網站 工作 text target lin stroke 建圖 基於

在實現Web項目的圖標系統時,SVG是一個不錯的選擇。雖然使用SVG創建圖標系統有多種方式。在這篇文章中,我們只看其中一種:SVG symbols。這項技術基於兩個元素的使用:<symbol><use>

<symbol>元素用來對元素進行分組;它不會被直接顯示,大概相當於定義一個模板,然後使用<use>元素引用並進行渲染。

我們使用Illustrator創建並導出SVG圖標:

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px" height="24px" viewBox="0 0 24 24">
    <path fill="#E86C60" d="M17,0c-1.9,0-3.7,0.8-5,2.1C10.7,0.8,8.9,0,7,0C3.1,0,0,3.1,0,7c0,6.4,10.9,15.4,11.4,15.8 c0.2,0.2,0.4,0.2,0.6,0.2s0.4-0.1,0.6-0.2C13.1,22.4,24,13.4,24,7C24,3.1,20.9,0,17,0z"></path>
</svg>

然後將內容包裹在<symbol>元素中:

<svg>
    <symbol viewBox="0 0 24 24" id="heart">
        <path fill="#E86C60" d="M17,0c-1.9,0-3.7,0.8-5,2.1C10.7,0.8,8.9,0,7,0C3.1,0,0,3.1,0,7c0,6.4,10.9,15.4,11.4,15.8 c0.2,0.2,0.4,0.2,0.6,0.2s0.4-0.1,0.6-0.2C13.1,22.4,24,13.4,24,7C24,3.1,20.9,0,17,0z"></path>
    </symbol>
</svg>

現在如果我們把這段代碼插入到我們的頁面中,我們會看到圖標並不顯示,因為要顯示圖標,我們還需要使用<use>元素:

<body>
    <svg style="display: none;">
        <symbol viewBox="0 0 24 24" id="heart">
            <path fill="#E86C60" d="M17,0c-1.9,0-3.7,0.8-5,2.1C10.7,0.8,8.9,0,7,0C3.1,0,0,3.1,0,7c0,6.4,10.9,15.4,11.4,15.8 c0.2,0.2,0.4,0.2,0.6,0.2s0.4-0.1,0.6-0.2C13.1,22.4,24,13.4,24,7C24,3.1,20.9,0,17,0z"></path>
        </symbol>
    </svg>

    <svg>
        <use xlink:href="#heart"/> <!-- this is our visible icon -->
    </svg>
</body>

結果如下:

技術分享

換句話說,就是你定義了一組圖形對象(使用<symbol>元素)之後,可以使用<use>元素來對它進行無限次實例化展示。你使用xlink:href屬性來指定你想要展示哪一組圖標,這裏,我們要展示的是id#heart<symbol>元素。

你可能註意到了我們給包裹<symbol>元素的SVG標簽加了一個style="display: none;"的樣式:這是因為即使<symbol>本身沒有顯示,但是包裹它的<svg>元素依舊會渲染並占用一些頁面空間,這就是為什麽我們需要隱藏svg元素。

現在我們知道了<symbol><use>元素分別是什麽,以及它們是如何工作的,我們可以來建立我們的SVG sprite了。

首先,你需要準備好所有圖標,每個圖標放一個單獨的.svg文件。然後再創建一個新的(空白的).svg文件(我把它命名為myicons.svg)。

在這個新的svg文件中,插入一個<svg>標簽,然後,對於每一個你要放進去的圖標,分別用一個<symbol>元素來包裹。

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
    <symbol viewBox="0 0 24 24" id="heart">
        <path fill="#E86C60" d="M17,0c-1.9,0-3.7,0.8-5,2.1C10.7,0.8,8.9,0,7,0C3.1,0,0,3.1,0,7c0,6.4,10.9,15.4,11.4,15.8 c0.2,0.2,0.4,0.2,0.6,0.2s0.4-0.1,0.6-0.2C13.1,22.4,24,13.4,24,7C24,3.1,20.9,0,17,0z"></path>
    </symbol>

    <symbol viewBox="0 0 32 32" id="arrow">
        <path fill="#0f0f0f" d="M16,0C7.2,0,0,7.2,0,16s7.2,16,16,16s16-7.2,16-16S24.8,0,16,0z M22.8,13.6l-6,8C16.6,21.9,16.3,22,16,22 s-0.6-0.1-0.8-0.4l-6-8c-0.2-0.3-0.3-0.7-0.1-1S9.6,12,10,12h12c0.4,0,0.7,0.2,0.9,0.6S23,13.3,22.8,13.6z"></path>
    </symbol>
</svg>

每個<symbol>元素都設置一個id,這個id用來在後面使用<use>的時候引用。

我們還給每個<symbol>元素指定了一個viewBox屬性。這個viewBox屬性定義了圖標的寬高比;它包含4個值,前面2個值通常為0(但它其實是依賴於圖標是如何繪制的),另外兩個值分別是SVG的寬和高(如果你對於viewBox屬性不熟悉,可以看看這篇關於SVG縮放的文章)。

這樣你的圖標不需要保持相同的寬高比,因為你可以給每個圖標分別定義不同的viewBox屬性。

最後一步,我們可以給每個圖標添加一個<title>標簽,提升它的可訪問性。

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
    <symbol viewBox="0 0 24 24" id="heart">
        <title>Heart</title>
        <path fill="#E86C60" d="M17,0c-1.9,0-3.7,0.8-5,2.1C10.7,0.8,8.9,0,7,0C3.1,0,0,3.1,0,7c0,6.4,10.9,15.4,11.4,15.8 c0.2,0.2,0.4,0.2,0.6,0.2s0.4-0.1,0.6-0.2C13.1,22.4,24,13.4,24,7C24,3.1,20.9,0,17,0z"></path>
    </symbol>

    <symbol viewBox="0 0 32 32" id="arrow">
        <title>Arrow</title>
        <path fill="#0f0f0f" d="M16,0C7.2,0,0,7.2,0,16s7.2,16,16,16s16-7.2,16-16S24.8,0,16,0z M22.8,13.6l-6,8C16.6,21.9,16.3,22,16,22 s-0.6-0.1-0.8-0.4l-6-8c-0.2-0.3-0.3-0.7-0.1-1S9.6,12,10,12h12c0.4,0,0.7,0.2,0.9,0.6S23,13.3,22.8,13.6z"></path>
    </symbol>
</svg>

我們的SVG sprite現在可以投入使用了。你可以保存文件為myicons.svg,放在資源文件夾中(我通常把這個文件夾明明為img)。

接下來展示我們的圖標,你需要做的就是在文檔中你想要放置圖標的位置插入下面這一小段:

<svg>
    <use xlink:href="img/myicons.svg#heart"/>
</svg>

就這樣,so easy!

瀏覽器兼容性如何呢?在IE中通過<use>引用外部SVG文件的方法是不可行的,IE9以上也不行(不過,這個問題在Edge中已經解決了)。

那要如何解決呢?我們來看看兩種可能的解決方案。

我們可以在文檔的頂部引入SVG sprite,然後使用<use>標簽引用圖標:

<svg style="display: none;"> <!-- this is our svg sprite -->
    <symbol viewBox="0 0 24 24" id="heart">
        <path fill="#E86C60" d="M17,0c-1.9,0-3.7,0.8-5,2.1C10.7,0.8,8.9,0,7,0C3.1,0,0,3.1,0,7c0,6.4,10.9,15.4,11.4,15.8 c0.2,0.2,0.4,0.2,0.6,0.2s0.4-0.1,0.6-0.2C13.1,22.4,24,13.4,24,7C24,3.1,20.9,0,17,0z"></path>
    </symbol>

    <symbol viewBox="0 0 32 32" id="arrow">
        <!-- ... -->
    </symbol>
</svg>

<svg>
    <use xlink:href="#heart"/> <!-- this is our visible icon -->
</svg>

註意xlink:href屬性和id標識符是唯一對應的(它不能引用外部資源中的id)。

這種方法非常好用,但缺點是SVG sprite不能緩存。

我們可以使用一個polyfill;舉個例子,svgxuse。這個polyfill可以根據<use>元素的引用,獲取外部SVG資源中的id,而瀏覽器本身並不能這樣做。基本遠離就是,這個polyfill遍歷文檔中的<use>元素,然後如果它引用的是瀏覽器無法加載的外部SVG文件,它就在外部SVG中抓取並預置到文檔中的<body>中。good!

你可以在Github repo中下載這個polyfill,在文檔中引入,就ok了。

註意:SVG只在IE9以上支持;所以如果你需要支持IE8及以下的瀏覽器,你需要另外再寫一套降級(例如,使用png圖片方案)。

接下來,怎麽給SVG添加樣式呢?給SVG <use>元素添加樣式需要一點技巧。這是因為SVG 圖標引用這種方式有自己單獨的DOM結構(也就是shadow DOM),CSS選擇器並不能獲取到,所以假設我們有如下的圖標:

<svg class="icon">
    <use xlink:href="img/myicons.svg#heart"/>
</svg>

然後這樣添加樣式:

.icon path {
    fill: #000000;
}

是沒有辦法工作的。

如何解決這個問題呢?比如說你想要改變圖標的填充顏色。首先,確保fill屬性不是svg文件中內聯定義的。所以,如果圖標 sprite如下:

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
    <symbol viewBox="0 0 24 24" id="heart">
        <title>Heart</title>
        <path fill="#E86C60" d="M17,0c-1.9,0-3.7,0.8-5,2.1C10.7,0.8,8.9,0,7,0C3.1,0,0,3.1,0,7c0,6.4,10.9,15.4,11.4,15.8 c0.2,0.2,0.4,0.2,0.6,0.2s0.4-0.1,0.6-0.2C13.1,22.4,24,13.4,24,7C24,3.1,20.9,0,17,0z"></path>
    </symbol>

    <symbol viewBox="0 0 32 32" id="arrow">
        <title>Arrow</title>
        <path fill="#0f0f0f" d="M16,0C7.2,0,0,7.2,0,16s7.2,16,16,16s16-7.2,16-16S24.8,0,16,0z M22.8,13.6l-6,8C16.6,21.9,16.3,22,16,22 s-0.6-0.1-0.8-0.4l-6-8c-0.2-0.3-0.3-0.7-0.1-1S9.6,12,10,12h12c0.4,0,0.7,0.2,0.9,0.6S23,13.3,22.8,13.6z"></path>
    </symbol>
</svg>

把內聯fill屬性刪除,如下:

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
    <symbol viewBox="0 0 24 24" id="heart">
        <title>Heart</title>
        <path d="M17,0c-1.9,0-3.7,0.8-5,2.1C10.7,0.8,8.9,0,7,0C3.1,0,0,3.1,0,7c0,6.4,10.9,15.4,11.4,15.8 c0.2,0.2,0.4,0.2,0.6,0.2s0.4-0.1,0.6-0.2C13.1,22.4,24,13.4,24,7C24,3.1,20.9,0,17,0z"></path>
    </symbol>

    <symbol viewBox="0 0 32 32" id="arrow">
        <title>Arrow</title>
        <path d="M16,0C7.2,0,0,7.2,0,16s7.2,16,16,16s16-7.2,16-16S24.8,0,16,0z M22.8,13.6l-6,8C16.6,21.9,16.3,22,16,22 s-0.6-0.1-0.8-0.4l-6-8c-0.2-0.3-0.3-0.7-0.1-1S9.6,12,10,12h12c0.4,0,0.7,0.2,0.9,0.6S23,13.3,22.8,13.6z"></path>
    </symbol>
</svg>

然後在你的css代碼中,加入:

.icon {
    fill: #00000; /* this will be your icons default color */
}

因為你沒有在SVG中給path元素指定fill,所以它們會繼承父級元素,即SVG的fill屬性,這樣你可以直接使用CSS選擇器修改這個屬性。

現在,如果我們只想改變一個圖標的fill,怎麽辦呢?我們給這個圖標再單獨指定一個class即可:

<svg class="icon my-class-name">
    <use xlink:href="img/myicons.svg#heart"></use>
<svg>

然後使用CSS改變它的fill值:

.my-class-name {
    fill: red;
}

使用Nucleo創建SVG symbol sprite

手動創建一個SVG symbol sprite是非常麻煩的,特別是如果你有相對多的圖標。Nucleo自動化SVG symbol sprites構建工具可以幫助你省下很多瑣碎活。

從Nucleo的網站上,選擇你想要下載圖標,然後點擊下載按鈕。在彈出的設置窗口中,勾上‘Export as <symbol>選項,然後填寫你的資源文件夾的路徑(這裏會為<use>元素設置一個xlink:href值);填寫一個文件名(這是你的SVG sprite文件的名字)。然後點擊保存。完成啦!你的sprite就可以用了。

技術分享

你下載的文件夾中會包含幾樣東西:

  • 你的SVG sprite;
  • 一個style.css文件(在css文件夾中):它包含基本的SVG樣式(例如,你在app中設置的fill/stroke屬性);你需要復制這塊內容到你的樣式文件中(或者作為一個額外的css文件引入);
  • 一個svgxuse.min.js文件(在js文件夾中),這是針對IE9+的polyfill;你需要在你的文檔中引入這個文件,如果你希望圖標在IE9+的瀏覽器中可以正確顯示的話;
  • 最後,一個demo.html文件。

基本上,這個demo文件列出了所有你下載的圖標,你可以直接在你的文檔中引入它們:點擊你想要引入的圖標,它就會選中你需要復制的代碼片段,然後在你的文檔中粘貼即可。

技術分享

圖標也會按照你在Nucleo app中設置的樣式顯示。

怎麽給單個圖標添加樣式呢?你可以給圖標指定一個class

<svg class="nc-icon grid-32 glyph my-class-name">
    <use xlink:href="img/myicons.svg#double-left"/>
</svg>

然後在CSS中修改:

.my-class-name {
    color: purple;
}

OK。但是,Nucleo圖標是雙色的....如果我想改變的是其中的第二種顏色的?這也好辦,加上:

.my-class-name use {
    color: orange;
}

OK啦。

我們的symbols有一些額外的技巧。

  • 我們的內聯圖標有可定制的stroke。如果你想要改變某個圖標的stroke-width屬性呢?假設你下載的圖標stroke-width2px,那麽stroke-2類會自動添加到SVG元素上。如果你想要把stroke切換為3px,只需要把stroke-2類改為stroke-3類就可以啦。
  • 那如何讓圖標和文本對齊呢?在demo文件中,在頂部,可以選擇‘align to text’;然後復制SVG片段並粘貼到你的文檔中(感謝Cloud Four提供的‘align to text‘樣式)。 註意,在這裏,SVG會繼承文本的顏色;但是,你同樣可以使用一個自定義類,給它添加自定義樣式,和前面一樣。
  • 如果你更傾向於在文檔中引入SVG sprite(而不是作為一個外部的SVG文件引用),不要勾選‘Reference external SVG‘選項(在demo文件的頂部);這會自動將xlink;href屬性設置為和<symbol>的唯一標識符id相等的名字。

使用SVG symbols真的是管理圖標的非常智能的方法;這是為什麽我們在Nucleo中加入了‘symbol export‘功能。

使用Nucleo管理圖標也是非常方便的,即使你手頭有多個項目:你需要做的只是創建一個項目,添加你需要的圖標,然後點擊幾下,下載即可。

[email protected] Romano的《How to create an icon system using SVG symbols》所譯,整個譯文帶有我們自己的理解與思想,如果譯得不好或有不對之處還請同行朋友指點。如需轉載此譯文,需註明英文出處:https://nucleoapp.com/how-to-create-an-icon-system-using-svg-symbols/。

著作權歸作者所有。
商業轉載請聯系作者獲得授權,非商業轉載請註明出處。
原文: http://www.w3cplus.com/svg/how-to-create-an-icon-system-using-svg-symbols.html ? w3cplus.com

使用SVG symbols建立圖標系統