Icon System with SVG Sprites | CSS

I’ve been a big proponent of icon fonts. Lots of sites really need a system for icons, and icon fonts offer a damn fine system. However, I think assuming you’re good with IE 9+, using inline SVG and the <use> element to reference an icon is a superior system.

First let’s cover how it works.

A nice way to handle your icons is to have a folder full of .svg files.

That’s one of the cool things about working with SVG – they are the source files.

They can be colored, not colored, multiple shapes, sizes, whatever.

You can let Illustrator (or whatever) save it however, with all the cruft that comes along for the ride:

<?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>

Combine the .svg files

You can manually do this if you want. I’ve done it. You don’t even have to look at the final file. Just call it svg-defs.svg or something.

It should just be an <svg> tag, with a <defs> tag (which just means you are defining stuff to use later), and then a bunch of <g> (group) tags. Each <g> tag will have a unique ID, and will wrap all the paths and whatnot for each icon.

<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>
Turns out <symbol> is probably a better choice than <g>. Read all about it!

Again you can do that by hand, but of course that’s a bit laborious. Fabrice Weinberg has created a Grunt plugin called grunt-svgstore that automates this.

If you’ve never used Grunt, you can do it. Here’s a screencast to get you started.

You can install it with:

npm install grunt-svgstore --save-dev

Make sure the task is available with:

grunt.loadNpmTasks('grunt-svgstore');

And then in the config:

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

In the output file, svg-defs.svg, each icon (whatever paths and stuff from the source .svg file) will be wrapped up in a <g> tag with a unique, prefixed ID, and the file name (minus the .svg). Like:

<g id="shape-codepen">

Inject that SVG at the top of the document

Literally include it, like:

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

<head>
  ...
</head>

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

Or however you want to do that.

It’s gotta be at the top, sadly, as there is a Chrome bug in which this isn’t going to work if defined later. Although… there is more to this story because as I type these words, the theme this very site is using has the icons defined at the bottom of the document and it works. Ughkgh confusing.

Use the icons wherever

Now you can use them wherever! Like:

<svg viewBox="0 0 100 100" class="icon shape-codepen">
  <use xlink:href="#shape-codepen"></use>
</svg>
Note that grunt-svgstore is now using <symbol> so you don’t even need to use the viewBox!

Make sure you use those class names on the svg to size it.

/* 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: you can style them (and their parts) with CSS

One of the reasons we loved icon fonts is the ability to style them with CSS. This technique one-ups that in that we do everything we could there, and more, because:

  1. We can style all the separate parts
  2. SVG has even more things you can control, like special filters and strokes

The svg is (kinda) in the DOM, so JavaScript too. Here’s some styling possibilities and a demo of this all at work:

Another way: IcoMoon

IcoMoon, which is known for producing icon fonts, actually does a fantastic job of producing SVG sprites as well. After selecting all the fonts you want, click the SVG button on the bottom and you’ll get that output, including a demo page with the inline SVG method.

Browser Support

On the browser support front, the danger zones are IE 8 and down, Safari 5 and down, iOS 4.3 and down, and Android 2.3 and down. But if your policy is “the last two major versions” – you’re looking at pretty much 100% support.

Remember that icons can be used as a supporting role only, like always accompanied by a word. If that’s the case, support isn’t too big of a deal. If these are stand-alone, and non-display would make the site unusable, that’s a big deal.

I probably would go for icon fonts, as the support there is much deeper. Just make sure you do it up right.

This is going to get a lot better

Ideally we’d be able to do this:

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

This does work in some browsers, meaning you could skip the include at the top of the document. Doing it this way means an extra HTTP request, but that means you can utilize caching more efficiently (not bloat document caching). In testing, Jonathan Neal discovered you need to have the xmlns attribute on the <svg> for it to work:

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

But even then, no support in any IE. Unless you wanted to swap out the whole <svg><use> with an <object>, which does work. Jonathan Neal again figured this out:

/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);
    }
  });
});

His demo now also has a method which makes an Ajax request for the contents and injects that, which allows the fills to work in IE 9. Not as efficient, but more like a polyfill.

I imagine someday straight up <svg><use> linking right to the .svg will be the way to go. Or even perhaps <img> working with URL fragment identifiers on the SVG.


Browsers treat <use> like the shadow DOM:

Right now, we can target, say, an individual <path> with CSS, like:

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

But that will affect all instances of that path. You’d think you could do:

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

But that doesn’t work. It crosses that shadow DOM boundary. Ideally you’d use the “hat” selector to break that:

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

But that’s not supported yet either and it’s not entirely clear if that’s exactly how that will work or not.

“Versus” icon fonts

Vector-based: tie

Style with CSS: slight edge to SVG sprites (targeting parts, SVG specific styling like strokes)

Weird failures: SVG seems to just work (when supported). Icon fonts seem to fail in weird ways. For instance, you map the characters to normal letters, then the font loading fails and you get random characters abound. Or you map to “Private Use Area” and some browsers decide to re-map them to really weird characters like roses, but it’s hard to replicate. Or you want to host the @font-face files on a CDN, but that’s cross-origin and Firefox hates that, so you need your server to serve the right cross-origin headers, but your Nginx setup isn’t picking that up right, SIGH. SVG wins this one.

Semantics: Not a huge deal, but I think an <svg> makes a bit more sense for an image than a <span>.

Accessibility: Maybe someone can tell me? Can we/should we give the <svg> a title attribute or something? Or a <text> element inside that we visually hide? Update: the <title> element might do. Or perhaps the <desc> element as used in this SVG access spec.

Ease of use: Tools like Fontello and IcoMoon are pretty good for an icon font workflow, but the folder-full-of-SVGs with Grunt squishing them together for you is even easier, I think.


Ian Feather posted an article about why they switched away from icon fonts as well and I agree with every single point.

(0)

相关推荐

  • WEB前端第十九课——雪碧图&滑动门

    WEB前端第十九课——雪碧图&amp;滑动门

  • 高清图标来袭!在vue项目中使用iconfont

    为什么不切图标了 以前的图标我们非常喜欢用ps等工具切成一张张xxx.png图片,如果稍微懂点移动端适配,对dpr(设备像素比)有所了解的,还会切出类似home@1x.ppng,home@2x.png ...

  • 4.标签篇:SVG

    # 4.标签篇:svg - SVG:矢量图,放大不会失真,适合大面积的贴图,通常动画较少或较简单.使用标签和CSS去画     canvas:适合用于小面积的绘图,适合动画 ```html <s ...

  • [css] 第114天 为什么要使用css sprites?

    今日试题: 为什么要使用css sprites? 此开源项目四大宗旨:勤思考,多动手,善总结,能坚持 <论语>,曾子曰:"吾日三省吾身"(我每天多次反省自己). 前端面 ...

  • Web 设计新趋势: 使用 SVG 代替 Web Icon Font | IO

    如果你还在使用 Icon Font 作为网页中显示图标的实现方案,那么你可能有点 Out 了. 由于使用 Icon Font 显示图标存在一些缺陷,开发者们一直在致力于探索使用 SVG 作为替代的方法 ...

  • 10个CSS简写/优化技巧整理

    CSS简写就是指将多行的CSS属性简写成一行,又称为CSS代码优化或CSS缩写.CSS 简写的最大好处就是能够显著减少CSS文件的大小,优化网站整体性能,更加容易阅读. 下面介绍常见的CSS简写规则: ...

  • 长铜绿的沛纳海青铜表,如何成为潮流ICON?

    两年前,香港,富艺斯春季拍卖会上,一枚表壳"锈迹斑斑"的沛纳海腕表,经过一番激烈叫价竞争,最后以27.5万港币高价成交,是它2011年上市时价格的近4倍. 你也许会惊讶,品相并不好 ...

  • 基于system verilog的图像处理验证平台 bmp文件解析

    版权所有:转载请注明 https://blog.csdn.net/jayash/article/details/79947314 基于FPGA的图像处理中,rtl代码的仿真验证一直是重中之重, 之前也 ...

  • SVG Shaper for SwiftUI

    轻松将 SVG 转换为 SWIFTUI 形状 Easily convert SVGs to SwiftUI shapes Mac开发者工具

  • CSS控制DIV层显示和隐藏的实现方法

    本文给大家带来了CSS控制DIV层显示和隐藏的方法,是前端学习必须要掌握的基础知识,非常不错,具有参考借鉴价值,感兴趣的小伙伴一起学习吧 CSS中的display和visibility属性 css中d ...

  • 解析CSS的box model盒模型及其内的子元素布局控制

    盒模型是CSS控制布局的主要方式之一,尤其是内部的元素排列控制,这里我们将来解析CSS的box model盒模型及其内的子元素布局控制,需要的朋友可以参考下 css的两种盒模型介绍   CSS中Box ...

  • 从一个熊猫ICON的“成长”看潮流文化是如何吸引年轻人的

    文| 林不二子 今年的五一假期,除了展现出疫情后大众强烈的出游热情,还发生了一些不易注意到的变化,比如全国多个商圈为假期吸引游客都打出了"潮玩"的概念,这里的"潮玩&qu ...