SVG Icon System

This page demonstrates how to use an svg icon system that works in browsers > IE8. This system starts with a collection of svg icons that are compiled into a single svg sprite. I encourage you to study the Gulp file in my svg-icons repo in order to understand the actual build system.

View Icons

Inline SVG <use> with External Source

The CSS

In this system, icons receive the .icon class. Icon width and height are set to 1em. This allows the icons to inherit font size - alleviating the burden of having to set specific widths and heights for icons based on context.

.icon {
  display: inline-block;
  fill: currentColor;
  height: 1em;
  line-height: 1;
  position: relative;
  top: -1px;
  vertical-align: middle;
  width: 1em;
}

The SVGs

We start with a collection of svg icons. These icons are compiled into a single svg sprite using gulp-svg-sprite. While we will predominantly use the svg sprite, we'll also want access to individual svgs - they'll come in handy when we tackle svgs in generated content.

Basic Usage

Using an external svg sprite gives us caching and the ability to use inline svg. For additional information and caveats, see Chris Coyier's great explanation. A polyfill is necessary for IE 9-11. If you hate the idea of a polyfill, it's okay. This system will still work for you. Simply include the svg sprite on every page and change the use xlink:href reference to ONLY be the hashtag and filename.

 = <svg class="icon"><use xlink:href="icons/sprite.svg#heart"/></svg>
 = <svg class="icon"><use xlink:href="icons/sprite.svg#fire"/></svg>

Adding Color

Now that you understand the basics, let's add some color. In this example, we are simply adding a contextual color class to the icon class. You could just as easily use a inline style.

 = <svg class="icon text-danger"><use xlink:href="icons/sprite.svg#heart"/></svg>
 = <svg class="icon text-success"><use xlink:href="icons/sprite.svg#fire"/></svg>
 = <svg class="icon text-primary"><use xlink:href="icons/sprite.svg#cog"/></svg>
 = <svg class="icon text-warning"><use xlink:href="icons/sprite.svg#star"/></svg>
 = <svg class="icon text-muted"><use xlink:href="icons/sprite.svg#cloud"/></svg>
 = <svg class="icon text-info"><use xlink:href="icons/sprite.svg#tag"/></svg>

In this example, you'll see how the icons inherit color from their parent.

<p class="text-info">
  <svg class="icon"><use xlink:href="icons/sprite.svg#heart"/></svg>
  <svg class="icon"><use xlink:href="icons/sprite.svg#fire"/></svg>
  <svg class="icon"><use xlink:href="icons/sprite.svg#cog"/></svg>
  <svg class="icon"><use xlink:href="icons/sprite.svg#star"/></svg>
  <svg class="icon"><use xlink:href="icons/sprite.svg#cloud"/></svg>
  <svg class="icon"><use xlink:href="icons/sprite.svg#tag"/></svg>
</p>

Inside of Anchor Tags

In this example, you'll see how icons are used in an achor tag. Notice how the icons inherit CSS transitions from the anchor tag.

Link One | Link Two | Link Three

<a href="#"><svg class="icon"><use xlink:href="icons/sprite.svg#bell"/></svg> Link One</a> | <a href="#"><svg class="icon"><use xlink:href="icons/sprite.svg#search"/></svg> Link Two</a> | <a href="#"><svg class="icon"><use xlink:href="icons/sprite.svg#paperclip"/></svg> Link Three</a>

Inside of Buttons

In this example, you'll see how icons are used in buttons. Each icon inherits color, size, and transition from the button.






<button class="btn btn-sm btn-primary"><svg class="icon"><use xlink:href="icons/sprite.svg#heart"/></svg> Button</button>
<button class="btn btn-sm btn-outline-primary"><svg class="icon"><use xlink:href="icons/sprite.svg#heart"/></svg> Button</button>
<button class="btn btn-sm btn-secondary"><svg class="icon"><use xlink:href="icons/sprite.svg#heart"/></svg> Button</button>
<button class="btn btn-sm btn-outline-secondary"><svg class="icon"><use xlink:href="icons/sprite.svg#heart"/></svg> Button</button>

Multi-Color Icons

Unlike our single-color icons, our multi-color icons have defined fills that give them color. As you can see, when hovering over the buttons below the multi-color icon does not change. That's because they don't inherit the button color styles due to the svg's fill definitions.

<svg class="icon"><use xlink:href="icons/sprite.svg#pinwheel"/></svg>
<button class="btn btn-lg btn-default"><svg class="icon"><use xlink:href="icons/sprite.svg#pinwheel"/></svg> Button</button>
<button class="btn btn-lg btn-outline-secondary"><svg class="icon"><use xlink:href="icons/sprite.svg#pinwheel"/></svg> Button</button>
<button class="btn btn-lg btn-outline-primary"><svg class="icon"><use xlink:href="icons/sprite.svg#pinwheel"/></svg> Button</button>

SVG with Generated Content

In this example, I'm going to demonstrate how to use svg icons as generated content. Let's say that we have a list group and we want the .active list item to have a checkmark icon. We won't be using the svg sprite. Instead, we will use the individual checkmark.svg icon.

Generated Demo One

The Demo

.list-group-item.active receives a single-color checkmark icon using the :after pseudo selector.

The CSS

The CSS is pretty straighforward. We simply set checkmark.svg as the background image. BAM! We have a nice checkmark icon on the active list item.

Uh oh, there is still one problem. The icon is black. What if we wanted it to be another color? Because the icon is a background image, there is no way to alter the color with vanilla CSS. Don't fret. I'll address this in Generated Demo Two.

#generated-demo-1 .list-group-item.active:after {
  background-image: url("../icons/checkmark.svg");
  background-repeat: no-repeat;
  background-position: center center;
  background-size: cover;
  content: "";
  height: 1em;
  position: absolute;
  right: 15px;
  top: 50%;
  transform: translateY(-50%);
  width: 1em;
}

Generated Demo Two

The Demo

.list-group-item.active receives a single-color checkmark icon using the :after pseudo selector. This time we will change the color of the checkmark to white.

The CSS/LESS

Hell yes! The icon is now white! Okay. Now things are going to get a bit more complex. This is where the power of a CSS preprocessor comes in handy. We are going to use a LESS "parametric mixin" to modify the svg background fill.

Check out the first line of the CSS/LESS code below. We use our .svg-bg-add-fill() LESS mixin and pass it two parameters: the path to the icon and a hex color (or color variable). The mixin will generate a data-uri background image with a fill using the color provided to the mixin. Remember, our single-color svgs DON'T HAVE fills. This mixin will ADD a fill so that the icon's color can be altered.

#generated-demo-2 .list-group-item.active:after {
  .svg-bg-add-fill("../icons/checkmark.svg", "#ffffff"); // THIS IS THE ONLY DIFFERENCE BETWEEN THE TWO DEMOS!
  background-repeat: no-repeat;
  background-position: center center;
  background-size: cover;
  content: "";
  height: 1em;
  position: absolute;
  right: 15px;
  top: 50%;
  transform: translateY(-50%);
  width: 1em;
}

The Mixin - Add SVG Background Fill

.svg-bg-add-fill(@src, @fill-new) {
  @data-uri: data-uri('image/svg+xml;charset=UTF-8', "@{src}");
  @replace-default: escape('<path ');
  @replace-new: escape('<path fill="@{fill-new}" ');
  @replace-src: replace("@{data-uri}", @replace-default, @replace-new, "g");
  background-image: e(@replace-src);
}

The CSS Output

#generated-demo-2 .list-group-item.active:after {
  background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2232%22%20height%3D%2232%22%20viewBox%3D%220%200%2032%2032%22%3E%3Cpath%20fill%3D%22%23ffffff%22%20d%3D%22M13.272%2027.2c-.696%200-1.355-.325-1.778-.885l-5.718-7.55c-.744-.98-.55-2.38.432-3.124.984-.745%202.38-.55%203.125.433l3.762%204.966%209.46-15.187c.65-1.045%202.026-1.365%203.073-.714%201.045.65%201.365%202.026.712%203.07L15.167%2026.148c-.39.626-1.06%201.018-1.794%201.05-.034.002-.067.002-.1.002z%22%2F%3E%3C%2Fsvg%3E");
  background-repeat: no-repeat;
  background-position: center center;
  background-size: cover;
  content: "";
  height: 1em;
  position: absolute;
  right: 15px;
  top: 50%;
  transform: translateY(-50%);
  width: 1em;
}

Generated Demo Three

The Demo

.list-group-item.active receives a multi-color pinwheel icon using the :after pseudo selector. This time we will change the multi-color pinwheel to white.

The CSS/LESS

Hell yes! The multi-color icon is now white!

Check out the first line of the CSS/LESS code below. We use our .svg-bg-fill() LESS mixin and pass it two parameters: the path to the icon and a hex color (or color variable). The mixin will generate a data-uri background image with a fill using the color provided to the mixin. Remember, our multi-color svgs HAVE fills. This mixin will REPLACE fill colors with the color passed to the mixin.

#generated-demo-3 .list-group-item.active:after {
  .svg-bg-fill("../icons/pinwheel.svg", "#ffffff"); 
  background-repeat: no-repeat;
  background-position: center center;
  background-size: cover;
  content: "";
  height: 1em;
  position: absolute;
  right: 15px;
  top: 50%;
  transform: translateY(-50%);
  width: 1em;
}

The Mixin - SVG Background Fill

.svg-bg-fill(@src, @fill-new) {
  @data-uri: data-uri('image/svg+xml;charset=UTF-8', "@{src}");
  @replace-src: replace("@{data-uri}", 'fill\%3D\%22\%23[\w]{3,6}\%22', escape('fill="@{fill-new}"'), "g");
  background-image:e(@replace-src);
}

The CSS Output

#generated-demo-3 .list-group-item.active:after {
  background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%22-241%20333%20128%20128%22%20enable-background%3D%22new%20-241%20333%20128%20128%22%3E%3Ctitle%3EAperture%3C%2Ftitle%3E%3Cpath%20fill%3D%22%23ffffff%22%20d%3D%22M-192%20419l-35.4-61.4c-8.5%2010.9-13.6%2024.5-13.6%2039.4%200%207.7%201.4%2015.1%203.9%2022h45.1z%22%2F%3E%3Cpath%20fill%3D%22%23ffffff%22%20d%3D%22M-165.5%20421h-70.9c8.2%2020.2%2026.3%2035.2%2048.3%2039l22.6-39z%22%2F%3E%3Cpath%20fill%3D%22%23ffffff%22%20d%3D%22M-150.4%20399l-35.4%2061.4c2.9.4%205.9.6%208.9.6%2019.7%200%2037.4-8.9%2049.1-23l-22.6-39z%22%2F%3E%3Cpath%20fill%3D%22%23ffffff%22%20d%3D%22M-162%20375l35.4%2061.4c8.5-10.9%2013.6-24.5%2013.6-39.4%200-7.7-1.4-15.1-3.9-22H-162z%22%2F%3E%3Cpath%20fill%3D%22%23ffffff%22%20d%3D%22M-188.5%20373h70.9c-8.2-20.2-26.3-35.2-48.3-39-.1%200-22.6%2039-22.6%2039z%22%2F%3E%3Cpath%20fill%3D%22%23ffffff%22%20d%3D%22M-203.6%20395l35.4-61.4c-2.9-.4-5.9-.6-8.9-.6-19.7%200-37.4%208.9-49.1%2023l22.6%2039z%22%2F%3E%3C%2Fsvg%3E");
  background-repeat: no-repeat;
  background-position: center center;
  background-size: cover;
  content: "";
  height: 1em;
  position: absolute;
  right: 15px;
  top: 50%;
  transform: translateY(-50%);
  width: 1em;
}