用SVG 製做 Sprites的圖標系統

https://css-tricks.com/svg-sp...javascript

我一直是圖標字體的大力支持者。不少網站真的須要一個圖標系統,圖標字體提供了一個該死的精細系統。可是,我認爲假設你對 IE 9+ 很好,使用內聯 SVG 而且 <use> 引用圖標的元素是一個優秀的系統。php

首先讓咱們介紹它的工做原理。css

處理圖標的一個好方法是讓文件夾中包含大量.svg文件。html

folder-of-svgs.png

這是使用SVG的一個很酷的事情 - 它們是源文件。
它們能夠是彩色的,而不是彩色的,多種形狀,尺寸等等。java

svg-whatever.png

你可讓 Illustrator(或其餘任何軟件)保存它,享受其帶來的全部瑕疵:git

<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.4, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
     width="100px" height="100px" viewBox="0 0 100 100" enable-background="new 0 0 100 100" xml:space="preserve">
<g>
    <path d="M50.049,0.3c14.18,0.332,25.969,5.307,35.366,14.923S99.675,36.9,100,51.409c-0.195,11.445-3.415,21.494-9.658,30.146 - yadda yadda yadda"/>
</g>
</svg>

合併.svg文件

若是須要,能夠手動執行此操做。我作到了 您甚至沒必要查看最終文件。只是稱之爲 svg-defs.svg或其餘。github

它應該只是一個 <svg> 標籤,帶有<defs>標籤(這意味着你要定義之後要使用的東西),而後是一堆<g>(組)標籤。每一個<g>標記都有一個惟一的ID,包含每一個圖標的全部路徑和諸如此類的東西。web

<svg>
  <defs>

    <g id="shape-icon-1">
      <!-- all the paths and shapes and whatnot for this icon -->
    <g>

    <g id="shape-icon-2">
      <!-- all the paths and shapes and whatnot for this icon -->
    <g>

    <!-- etc -->

  </defs>
</svg>
事實證實 <symbol>多是一個更好的選擇 <g>。參考 關於它的內容

能夠手工完成,但固然這有點費力。Fabrice Weinberg建立了一個名爲grunt-svgstore的Grunt插件,可自動執行此操做。shell

若是從未使用過Grunt,那麼您能夠這樣作。這是一個能夠幫助入門的截屏視頻。npm

你能夠安裝它:

npm install grunt-svgstore --save-dev

確保該任務可用於:

grunt.loadNpmTasks('grunt-svgstore');

而後在配置中:

svgstore: {
  options: {
    prefix : 'shape-', // This will prefix each <g> ID
  },
  default : {
      files: {
        'dest/svg-defs.svg': ['svgs/*.svg'],
      }
    }
  }
},

在輸出文件中svg-defs.svg,每一個圖標(來自源.svg文件的任何路徑和內容)將被包裝在<g>帶有惟一的前綴ID和文件名(減去.svg)的標記中。喜歡:

<g id="shape-codepen">

將SVG注入文檔頂部
字面上包括它,如:

<!DOCTYPE html>
<html lang="en">

<head>
  ...
</head>

<body>
  <?php include_once("processed/svg-defs.svg"); ?>

或者你想要那樣作。

遺憾的是,它必須位於頂部,由於有一個Chrome錯誤,若是稍後定義,這將沒法正常工做。雖然......這個故事還有更多內容,由於當我輸入這些單詞時,這個網站使用的主題是在文檔底部定義的圖標,而且它有效。Ughkgh很困惑。

隨時隨地使用圖標

如今你能夠在任何地方使用它們!喜歡:

<svg viewBox="0 0 100 100" class="icon shape-codepen">
  <use xlink:href="#shape-codepen"></use>
</svg>
請注意, grunt-svgstore如今正在使用, <symbol>所以您甚至不須要使用viewBox!
確保在svg上使用這些類名來調整它的大小。
/* Do whatever makes sense here.
   Just know that the svg will be an 
   enormous 100% wide if you don't 
   reign in the width. */
.icon {
  display: inline-block;
  width: 25px;
  height: 25px;
}

Yay:你能夠用CSS設置它們(和它們的部分)的樣式

咱們喜歡圖標字體的緣由之一是可以使用CSS設置樣式。這項技術可讓咱們盡咱們所能,並且更多,由於:

  1. 咱們能夠設計全部單獨的部分
  2. SVG有更多你能夠控制的東西,好比特殊的過濾器和筆畫

svg(有點像是)在DOM中,因此也能夠用JavaScript。這裏有一些造型可能性的各類演示:

codepen.io

<svg viewBox="0 0 100 100" class="icon shape-codepen">
  <use xlink:href="#shape-codepen"></use>
</svg>

<svg viewBox="0 0 100 100" class="icon shape-codepen-2">
  <use xlink:href="#shape-codepen"></use>
</svg>

<br>

<svg viewBox="0 0 100 100" class="icon shape-youtube">
  <linearGradient id="gradient"  gradientUnits="userSpaceOnUse" x1="0%" y1="0%" x2="0%" y2="100%">
<stop stop-color="#FF0000" offset="0"/><stop stop-color="#571C1C" offset="1"/>
</linearGradient>
  <use xlink:href="#shape-youtube"></use>
</svg>

<br>

<svg viewBox="0 0 100 100" class="icon shape-twitter">
  <use xlink:href="#shape-twitter"></use>
</svg>

<svg viewBox="0 0 100 100" class="icon shape-twitter-2">
  <use xlink:href="#shape-twitter"></use>
</svg>

<svg viewBox="0 0 100 100" class="icon shape-twitter-3">
  <use xlink:href="#shape-twitter"></use>
</svg>
Result
EDIT ON
.hide {
  display: none;
}

.icon {
  width: 75px;
  height: 75px;
}

body {
  padding: 20px;
}

/* Targeting inside only */
.outer-ring {
  fill: #999;
}
.inner-logo {
  fill: #666;
}
.shape-codepen-2 {
  -webkit-filter: drop-shadow(5px 5px 2px #ccc); 
  filter: drop-shadow(5px 5px 2px black);
}

.shape-youtube {
  fill: url(#gradient);
}

.shape-twitter-2 {
  fill: #55ACEE
}
.shape-twitter-3 {
  fill: red;
}

請參閱CodeCen上的Chris Coyier(@chriscoyier)的Pen EBHlD。

另外一種方式:IcoMoon

IcoMoon以生成圖標字體而聞名,實際上也能夠很好地生成SVG精靈。選擇所需的全部字體後,單擊底部的SVG按鈕,您將得到該輸出,包括帶有內聯SVG方法的演示頁面。

icomoon-out.jpg

瀏覽器支持

在瀏覽器支持方面,危險區域是IE 8和向下,Safari 5和向下,iOS 4.3和向下,以及Android 2.3和向下。但若是你的政策是「最後兩個主要版本」 - 你會看到幾乎100%的支持。

請記住,圖標只能用做支持角色,就像老是伴隨着一個單詞同樣。若是是這樣的話,那麼支持並不算太大。若是它們是獨立的,而且不顯示會使網站沒法使用,那麼這是一個大問題。

我可能會選擇圖標字體,由於那裏的支持更深。只要確保你作得對。

會變得更好的

理想狀況下,咱們可以作到這一點:

<svg viewBox="0 0 100 100" class="icon shape-codepen">
  <use xlink:href="/images/svg-defs.svg#shape-codepen"></use>
</svg>

這確實在某些瀏覽器下是能夠的,這意味着你能夠不用將svg包括在文檔的頂部。但意味着額外的 HTTP 請求,但這也意味着能夠更有效地利用緩存(而不是膨脹文檔緩存)。在測試中,Jonathan Neal 發現你須要擁有 xmlns 屬性<svg>才能使它工做:

<svg xmlns="http://www.w3.org/2000/svg">

但即便這樣,任何IE都沒有支持。除非你想把整個換成<svg><use>一個<object>,這確實有效。喬納森尼爾再次想到這一點:

/MSIE|Trident/.test(navigator.userAgent) && document.addEventListener('DOMContentLoaded', function () {
  [].forEach.call(document.querySelectorAll('svg'), function (svg) {
    var use = svg.querySelector('use'); 

    if (use) {
      var object = document.createElement('object');
      object.data = use.getAttribute('xlink:href');
      object.className = svg.getAttribute('class');
      svg.parentNode.replaceChild(object, svg);
    }
  });
});

他的演示如今還有一個方法,它對內容進行Ajax請求並注入,這容許填充在IE 9中工做。效率不高,但更像是polyfill。

我想有一天會直接<svg><use>.svg鏈接起來。甚至可能<img>在SVG上使用URL片斷標識符。

瀏覽器<use>像陰影DOM同樣對待:

如今,咱們能夠針對<path>具備CSS 的我的進行定位,例如:

.targetting-a-path {
  fill: red;
}

但這會影響該路徑的全部實例。你認爲你能夠這樣作:

svg.shape-version-2 .targetting-a-path {
  fill: red;
}

但這不起做用。它穿過陰影DOM邊界。理想狀況下,您可使用「帽子」選擇器來打破:

svg.shape-version-2 ^ .targetting-a-path {
  fill: red;
}

可是,這也沒有獲得支持,而且不徹底清楚這是否確實如何起做用。

與圖標字體比對

基於矢量:領帶

CSS風格: SVG精靈略有優點(定位部分,SVG特定造型,如筆畫)

奇怪的失敗: SVG彷佛正常工做(支持時)。圖標字體彷佛以奇怪的方式失敗。例如,您將字符映射到普通字母,而後字體加載失敗,您會獲得隨機字符。或者你映射到「私人使用區」,一些瀏覽器決定將它們從新映射到真正奇怪的角色,如玫瑰,但它很難複製。或者你想在CDN上託管@font-face文件,但這是跨域的,Firefox討厭這個,因此你須要你的服務器提供正確的跨源頭文件,但你的Nginx設置不是正確的,唉。SVG贏得了這一局。

語義:並非什麼大不了的事,但我以爲<svg>對於一個圖像來講比<span>更有意義。

可訪問性:也許有人能夠告訴我?咱們應該/能夠給出<svg>一個title屬性嗎?或者<text>咱們在視覺上隱藏的元素?
更新:該<title>元素能夠有。或者也許是<desc>此SVG訪問規範中使用的元素。

易用性:像 Fontello 和 IcoMoon 這樣的工具很是適合圖標字體工做流程,但我認爲,與 Grunt 一塊兒將它們拼湊在一塊兒的文件夾 - 完整的SVG更加容易。

引用外部svg文件

svg 經過use能夠在頁面中引用屢次, 但前提是svg裏內嵌的,若是是外部的, 能夠藉助下面的腳原本實現:

https://github.com/jonathantn...

相關文章
相關標籤/搜索