Real World Use of CSS with SVG

SVG is a lightweight vector image format that’s used to display a variety of graphics on the Web and other environments with support for interactivity and animation. In this article, we’ll explore the various ways to use CSS with SVG, and ways to include SVGs in a web page and manipulate them.

The Scalable Vector Graphic (SVG) format has been an open standard since 1999, but browser usage became practical in 2011 following the release of Internet Explorer 9. Today, SVG is well supported across all browsers, although more advanced features can vary.

SVG Benefits

Bitmap images such as PNGs, JPGs and GIFs define the color of individual pixels. An 100×100 PNG image requires 10,000 pixels. Each pixel requires four bytes for red, green, blue and transparency so the resulting file is 40,000 bytes (plus a little more for meta data). Compression is applied to reduce the file size; PNG and GIF use ZIP-like lossless compression while JPG is lossy and removes less noticeable details.

--ADVERTISEMENT--

Bitmaps are ideal for photographs and more complex images, but definition is lost as the images are enlarged.

SVGs are vector images defined in XML. Points, lines, curves, paths, ellipses, rectangles, text, etc. are drawn on an SVG canvas. For example:

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 600">
  <circle cx="400" cy="300" r="250" stroke-width="20" stroke="#f00" fill="#ff0" />
</svg>

The viewBox defines a co-ordinate space. In this example, an 800×600 area starting at position 0,0 has a yellow circle with a red border drawn in the center:

SVG circle

The benefits of vectors over bitmaps:

  • the SVG above uses less than 150 bytes, which is considerably smaller than an equivalent PNG or JPG
  • SVG backgrounds are transparent by default
  • the image can scale to any size without losing quality
  • SVG code/elements can be easily generated and manipulated on the server or browser
  • in terms of accessibility and SEO, text and drawing elements are machine and human-readable.

SVG is ideal for logos, charts, icons, and simpler diagrams. Only photographs are generally impractical, although SVGs have been used for lazy-loading placeholders.

SVG Tools

It’s useful to understand the basics of SVG drawing, but you’ll soon want to create more complex shapes with an editor that can generate the code. Options include:

Each has different strengths, and you’ll get differing results for seemingly identical images. In general, more complex images require more complex software.

The resulting code can usually be simplified and minimized further using SVGO (plugins are available for most build tools) or Jake Archibold’s SVGOMG interactive tool.

SVGs as Static Images

When used within an HTML <img> tag or CSS background-url, SVGs act identically to bitmaps:

<!-- HTML image -->
<img src="myimage.svg" alt="a vector graphic" />
/* CSS background */
.myelement {
  background-image: url('mybackground.svg');
}

The browser will disable any scripts, links, and other interactive features embedded into the SVG file. You can manipulate an SVG using CSS in an identical way to other images using transform, filters, etc. The results of using CSS with SVG are often superior to bitmaps, because SVGs can be infinitely scaled.

CSS Inlined SVG Backgrounds

An SVG can be inlined directly in CSS code as a background image. This can be ideal for smaller, reusable icons and avoids additional HTTP requests. For example:

.mysvgbackground {
  background: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 600"><circle cx="400" cy="300" r="50" stroke-width="5" stroke="#f00" fill="#ff0" /></svg>') center center no-repeat;
}

Standard UTF-8 encoding (rather than base64) can be used, so it’s easy to edit the SVG image if necessary.

CSS with SVG: Responsive SVG Images

When creating a responsive website, it’s normally practical to omit <img> width and height attributes and allow an image to size to its maximum width via CSS:

img {
  display: block;
  max-width: 100%;
}

However, an SVG used as an image has no implicit dimensions. You might discover the max-width is calculated as zero and the image disappears entirely. To fix the problem, ensure a default width and height is defined in the <svg> tag:

<svg xmlns="http://www.w3.org/2000/svg" width="400" height="300">

Note: the dimensions should not be added to inlined SVGs, as we’ll discover in the next section …

HTML-Inlined SVG Images

SVGs can be placed directly into the HTML. When this is done, they become part of the DOM and can be manipulated with CSS and JavaScript:

<p>SVG is inlined directly into the HTML:</p>

<svg id="invader" xmlns="http://www.w3.org/2000/svg" viewBox="35.4 35.4 195.8 141.8">
  <path d="M70.9 35.4v17.8h17.7V35.4H70.9zm17.7 17.8v17.7H70.9v17.7H53.2V53.2H35.4V124h17.8v17.7h17.7v17.7h17.7v-17.7h88.6v17.7h17.7v-17.7h17.7V124h17.7V53.2h-17.7v35.4h-17.7V70.9h-17.7V53.2h-17.8v17.7H106.3V53.2H88.6zm88.6 0h17.7V35.4h-17.7v17.8zm17.7 106.2v17.8h17.7v-17.8h-17.7zm-124 0H53.2v17.8h17.7v-17.8zm17.7-70.8h17.7v17.7H88.6V88.6zm70.8 0h17.8v17.7h-17.8V88.6z"/>
  <path d="M319 35.4v17.8h17.6V35.4H319zm17.6 17.8v17.7H319v17.7h-17.7v17.7h-17.7V159.4h17.7V124h17.7v35.4h17.7v-17.7H425.2v17.7h17.7V124h17.7v35.4h17.7V106.3h-17.7V88.6H443V70.9h-17.7V53.2h-17.7v17.7h-53.2V53.2h-17.7zm88.6 0h17.7V35.4h-17.7v17.8zm0 106.2h-35.5v17.8h35.5v-17.8zm-88.6 0v17.8h35.5v-17.8h-35.5zm0-70.8h17.7v17.7h-17.7V88.6zm70.9 0h17.7v17.7h-17.7V88.6z"/>
</svg>

<p>The SVG is now part of the DOM.</p>

No width or height attributes are defined for the SVG, so it can size to the containing element or be directly sized using CSS:

#invader {
  display: block;
  width: 200px;
}

#invader path {
  stroke-width: 0;
  fill: #080;
}

See the Pen HTML-Inlined SVG by SitePoint (@SitePoint) on CodePen.

SVG elements such as paths, circles, rectangles etc. can be targeted by CSS selectors and have the styling modified using standard SVG attributes as CSS properties. For example:

/* CSS styling for all SVG circles */
circle {
  stroke-width: 20;
  stroke: #f00;
  fill: #ff0;
}

This overrides any attributes defined within the SVG because the CSS has a higher specificity. SVG CSS styling offers several benefits:

  • attribute-based styling can be removed from the SVG entirely to reduce the page weight
  • CSS styling can be reused across any number of SVGs on any number of pages
  • the whole SVG or individual elements of the image can have CSS effects applied using :hover, transition, animation etc.

SVG Sprites

A single SVG file can contain any number of separate images. For example, this folders.svg file contains folder icons generated by IcoMoon. Each is contained within a separate <symbol> container with an ID which can be targeted:

<svg xmlns="http://www.w3.org/2000/svg">
  <defs>
    <symbol id="icon-folder" viewBox="0 0 32 32">
      <title>folder</title>
      <path d="M14 4l4 4h14v22h-32v-26z"></path>
    </symbol>
    <symbol id="icon-folder-open" viewBox="0 0 32 32">
      <title>open</title>
      <path d="M26 30l6-16h-26l-6 16zM4 12l-4 18v-26h9l4 4h13v4z"></path>
    </symbol>
    <symbol id="icon-folder-plus" viewBox="0 0 32 32">
      <title>plus</title>
      <path d="M18 8l-4-4h-14v26h32v-22h-14zM22 22h-4v4h-4v-4h-4v-4h4v-4h4v4h4v4z"></path>
    </symbol>
    <symbol id="icon-folder-minus" viewBox="0 0 32 32">
      <title>minus</title>
      <path d="M18 8l-4-4h-14v26h32v-22h-14zM22 22h-12v-4h12v4z"></path>
    </symbol>
    <symbol id="icon-folder-download" viewBox="0 0 32 32">
      <title>download</title>
      <path d="M18 8l-4-4h-14v26h32v-22h-14zM16 27l-7-7h5v-8h4v8h5l-7 7z"></path>
    </symbol>
    <symbol id="icon-folder-upload" viewBox="0 0 32 32">
      <title>upload</title>
      <path d="M18 8l-4-4h-14v26h32v-22h-14zM16 15l7 7h-5v8h-4v-8h-5l7-7z"></path>
    </symbol>
  </defs>
</svg>

The SVG file can be referenced as an external, cached resource in an HTML page. For example, to show the folder icon at #icon-folder:

<svg class="folder" viewBox="0 0 100 100">
  <use xlink:href="folders.svg#icon-folder"></use>
</svg>

and style it with CSS:

svg.folder { fill: #f7d674; }

The method has a couple of drawbacks:

  1. It fails in IE9+.
  2. CSS styling only applies to the <svg> element containing the <use>. The fill here makes every element of the icon the same color.

To solve these issues, the SVG sprite can be embedded within page HTML, then hidden using display: none or similar techniques. An individual icon can be placed by referencing the ID:

<svg><use xlink:href="#icon-folder"></use></svg>

See the Pen SVG sprites by SitePoint (@SitePoint) on CodePen.

This works in all modern browsers from IE9+ and it becomes possible to style individual elements within each icon using CSS.

Unfortunately, the SVG set is no longer cached and must be reproduced on every page where an icon is required. The solution (to this solution!) is to load the SVG using Ajax — which is then cached — and inject it into the page. The IcoMoon download provides a JavaScript library, or you could use SVG for Everybody.

SVG Effects on HTML Content

SVG has long supported:

  • masks: altering the visibility of parts of an element
  • clipping: removing segments of an element so a standard regular box becomes any other shape
  • filters: graphical effects such as blurring, brightness, shadows, etc.

These effects have been ported to the CSS mask, clip-path, and filter properties. However, it’s still possible to target an SVG selector:

/* CSS */
.myelement {
  clip-path: url(#clip);
}

This references an effect within an HTML-embedded SVG:

<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" style="position: absolute; width: 0; height: 0; overflow: hidden;">
  <defs>
    <clipPath id="clip">
      <text x="0" y="200" font-family="Arial" font-size="10em" font-weight="800">Text Clip</text>
    </clipPath>
  </defs>
</svg>

to produce effects such as clipped text with an image or gradient background:

See the Pen SVG clipping by SitePoint (@SitePoint) on CodePen.

Portable SVGs

Finally, standalone SVGs can contain CSS, JavaScript and base64-encoded fonts or bitmap images! Anything outside the realms of XML should be contained within <![CDATA[]]> sections.

Consider the following invader.svg file. It defines CSS styling with hover effects and a JavaScript animation which modifies the viewBox state:

<svg id="invader" xmlns="http://www.w3.org/2000/svg" viewBox="35.4 35.4 195.8 141.8">
  <!-- invader images: https://github.com/rohieb/space-invaders !-->
  <style>/* <![CDATA[ */
    path {
      stroke-width: 0;
      fill: #080;
    }

    path:hover {
      fill: #c00;
    }
  /* ]]> */</style>
  <path d="M70.9 35.4v17.8h17.7V35.4H70.9zm17.7 17.8v17.7H70.9v17.7H53.2V53.2H35.4V124h17.8v17.7h17.7v17.7h17.7v-17.7h88.6v17.7h17.7v-17.7h17.7V124h17.7V53.2h-17.7v35.4h-17.7V70.9h-17.7V53.2h-17.8v17.7H106.3V53.2H88.6zm88.6 0h17.7V35.4h-17.7v17.8zm17.7 106.2v17.8h17.7v-17.8h-17.7zm-124 0H53.2v17.8h17.7v-17.8zm17.7-70.8h17.7v17.7H88.6V88.6zm70.8 0h17.8v17.7h-17.8V88.6z"/>
  <path d="M319 35.4v17.8h17.6V35.4H319zm17.6 17.8v17.7H319v17.7h-17.7v17.7h-17.7V159.4h17.7V124h17.7v35.4h17.7v-17.7H425.2v17.7h17.7V124h17.7v35.4h17.7V106.3h-17.7V88.6H443V70.9h-17.7V53.2h-17.7v17.7h-53.2V53.2h-17.7zm88.6 0h17.7V35.4h-17.7v17.8zm0 106.2h-35.5v17.8h35.5v-17.8zm-88.6 0v17.8h35.5v-17.8h-35.5zm0-70.8h17.7v17.7h-17.7V88.6zm70.9 0h17.7v17.7h-17.7V88.6z"/>
  <script>/* <![CDATA[ */
    const
      viewX = [35.4, 283.6],
      animationDelay = 500,
      invader = document.getElementById('invader');

    let frame = 0;

    setInterval(() => {
      frame = ++frame % 2;
      invader.viewBox.baseVal.x = viewX[frame];
    }, animationDelay);

  /* ]]> */</script>
</svg>

When referenced in an HTML <img> or CSS background, the SVG becomes a static image of the initial state (in essence, the first animation frame):

Invaders

However, open the image in its own browser tab and all the effects will return.

This could be useful for distributing images, demonstrations or small documents which require a level of embedded interactivity.

Sophisticated SVGs

SVGs offer a wide range of technical possibilities both within and outside web pages. When combining CSS with SVG, it becomes possible to style and animate the whole image or individual elements in interesting ways.

This article describes ways to manipulate SVG images, but they are regularly used for smaller visual enhancements such as:

  • form focus highlights and validation
  • turning a hamburger menu into a an X close icon
  • creating lava-lamp-like morphing.

Despite the age of SVG technology, web developers are still discovering ways to transform boring block-based pages with subtle effects through using CSS with SVG. Please let us know if you create any interesting examples.