Tips For Avoiding Common SVG Pitfalls

Hi! I’m Sara!

Pitfall #1

Presentation Attributes will override inherited styles specified on a parent element.

Problematic when: re-using components with <use> (e.g. SVG sprites)

SVG Presentation Attributes

<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="300px" height="300px" viewBox="0 0 300 300">

  <polygon

    fill = "#FF931E"

    stroke = "#ED1C24"

    stroke-width = "5"

    points = "279.1,160.8 195.2,193.3 174.4,280.8   117.6,211.1 27.9,218.3 76.7,142.7 42.1,59.6 129.1,82.7 197.4,24.1 202.3,114 "/>

</svg>

Presentation Attributes and The Cascade

  • Presentation attributes are overridden by any style declarations (inline, <style> or external).

 

  • Presentation attributes override default UA styles and inherited styles.

Styles lower in the diagram override those above them

Presentation Attributes and The Cascade

<style>
    circle {fill: orange;} 
</style>

<svg version="1.1" viewBox="0 0 400 400">
    <g fill="yellow">
        <circle cx="100" cy="100" r="100" fill="blue" />
        <!-- ... -->
    </g>
</svg> 

Presentation Attributes and The Cascade

<style>
    use {fill: orange;} 
</style>

<svg version="1.1" viewBox="0 0 400 400">
   <symbol id="myCirc" viewBox="0 0 32 32">
        <circle cx="100" cy="100" r="100" fill="blue"/>
    </symbol>

    <use xlink:href="#myCirc"...></use>
</svg> 

This is common in reusable SVG icons in icon sprites.

<svg version="1.1" xmlns="http://www.w3.org/2000/svg" style="display: none;">

   <symbol id="icon-twitter" viewBox="0 0 35 35">
      <!-- Twitter icon markup -->
   </symbol>
    
   <symbol id="icon-github" viewBox="0 0 35 35">
      <!-- Github icon markup -->
   </symbol>
   
   <!-- more icons here... -->
</svg>

real-world use case: sprites

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

real-world use case: sprites

<svg class="icon-twitter">
  <use xlink:href="icons.svg#icon-twitter"></use>
</svg>

Does not currently work in any version of IE.

real-world use case: sprites

Pitfall #1: The Solution

circle {
    fill: inherit;
    stroke: inherit;
}

Force the browser into inheriting the styles by taking advantage of the cascade

P.S. Make sure you set this rule _before_ any new style declarations in the CSS.

svg * {
   all: inherit;
}

Extreme Measure

Note that this will:

1. reset all the SVG attributes that can be set in CSS except transforms for now  (which is good considering the use case, cz u would want to change styles but not transformations + the latter are chained into a matrix!)

2. reset _all_ of those properties — so if u don't specify an alternate value, it will default to browser defaults.

3. This is great for overriding and "bare-boning" SVG elements to allow you to control them completely from the CSS (use case: an SVG whose innards you can't control)

Extra Tip: Styling Contents Of <use>

Further Styling Control w/ CSS Variables

<svg class="bird">
  <use xlink:href="#bulbul"></use>
</svg>
use {
    color: gray;
    fill: currentColor; /* this will be the base fill color inherited by all elements inside <use> */
    
    /* define variables here */
    --secondaryColor: yellow;
    --tertiaryColor: black;
}

Continued

HTML

CSS

Further Styling Control w/ CSS Variables

<symbol id="bulbul" viewBox="0 0 300 200">
    <path id="body" d="…" />
    <path id="tail" fill="var(--tertiaryColor)" d="…" />
    <path id="head" fill="var(--tertiaryColor)" d="…" />
   <path id="vent" fill="var(--secondaryColor)" d="…" />
</symbol>

SVG

Further Styling Control w/ CSS Variables

Pitfall #2

Links (<a>) inside an SVG embedded as an <object> will open inside the boundaries of that <object>, not in the main page. 

(—predictably so, considering that <object> is similar in functionality to <iframe>.)

The 6 SVG embedding techniques

<img src="logo.svg" alt="Company Logo" />
.el {background: url(mySVG.svg);}
<object type="image/svg+xml" data="mySVG.svg">
<!--fallback-->
</object>
<embed type="image/svg+xml" src="mySVG.svg" />
<iframe src="mySVG.svg">
<!--fallback-->
</iframe>
<svg><!--SVG content--></svg>

#7

<picture>
    <source type="image/svg+xml" srcset="path/to/image.svg">

    <img src="path/to/fallback.png" alt="...">
</picture>

Better fallback and art direction options.

Pitfall #2: Example Scenario

Pitfall #2: The Solution

<a role="link" tabindex="0" 

xlink:href="..." 

xlink:title="..." 

xlink:target="_parent" 

...> Visit Page </a>

        

Specify the target of the link using the xlink:target attribute

Remember to...

  1. Set the namespace on the root <svg> when you have links inside the SVG (including internal links).   xmlns:xlink="http://www.w3.org/1999/xlink"
  2. Set the namespace if you are creating and appending the attributes to elements using JavaScript.                                        var xlinkns = “http://www.w3.org/1999/xlink”;
     anchor.setAttributeNS(xlinkns, ‘href’, ‘…’ );

Pitfall #3

Setting `fill: none` on path area will disable pointer events on that area.

 

Example use case: Paths With Fills

pointer-events: visiblePainted;

The given element can be the target element for pointer events when the ‘visibility’ property is set to visible and when the pointer is over a "painted" area. The pointer is over a painted area if it is over the interior (i.e., fill) of the element and the ‘fill’ property has an actual value other than none or it is over the perimeter (i.e., stroke) of the element and the ‘stroke’property is set to a value other than none.

The Reason

Pitfall #3:

The SOlution

Set the fill to "transparent" instead of "none"

<path ... fill="transparent" ...></path>

OR

Change the value of the `pointer-events` property on the element.

 

For a list of values, refer to the specification.

Pitfall #4

Certain CSS and JS characters — e.g "<" — will cause an XML error when used inside an SVG file.

Styling SVG: CSS Embedding Options

<path style="fill: maroon; stroke:..." ></path>

Inline styles using a style attribute:

Styles embedded using a <style> tag inside the <svg>:

External styles:

<style> 
   rect { stroke-width: 1em; }
</style>
<?xml-stylesheet type="text/css" href="style.css"?>

SCRIPTING SVG

Script block:

External script reference:

<script>

    //JS here

</script>
<script xlink:href="file_name.js"></script>

Conflicting characters will not be an issue if the JS is external.

Pitfall #4:

The Solution

Wrap your CSS and/or JS in a CDATA block:

<style>
//<![CDATA[
    CSS here 
//]]>
</style>
<script>
//<![CDATA[
    JS here 
//]]>
</script>

OR

Manually convert your conflicting characters to their data formats.

&lt;        &gt;      &amp;

Placing internal CSS style sheets within CDATA blocks is sometimes necessary since CSS style sheets can include characters, such as ">", which conflict with XML parsers. Even if a given style sheet does not use characters that conflict with XML parsing, it is highly recommended that internal style sheets be placed inside CDATA blocks.

Pitfall #5

Cropping the SVG using the viewBox attribute can yield unwanted visible overflow.

The SVG viewBox Attribute

  • It goes in the <svg> declaration.. (among other elements).
  • It establishes a user coordinate system on the SVG.
  • It is made up of four components: "vx vy width height".
  • These components specify the origin and dimensions of the user coordinate system.
  • By changing the origin of the viewBox, we can crop or extend the SVG canvas.

Cropping The SVG using the viewBox Attribute:

The PRoblem

LIVE DEMO'ING

Pitfall #5:

The Solution

Change the aspect ratio of the <svg> (the viewport) to match that of the new viewBox.

OR

Clip the overflow out using clip-path

<svg ... clip-path="url(#clipper") viewBox="vx vy width height">
  <defs>
      <clipPath id="clipper">
          <rect x="vx" y="vy" width="100%" height="100%"></rect>
      </clipPath>
  </defs> 
  <!-- other svg content & styles -->
</svg>

This trick can also be used to visualise and troubleshoot viewBox problems.

You might want to reposition and/or scale the viewBox after clipping/cropping it. Do that using the preserveAspectRatio attribute.

Read

Everything you need to know about the SVG viewport, viewBox and preserveAspectRatio: 

http://sarasoueidan.com/blog/svg-coordinate-systems 

(Includes an interactive demo.)

Pitfall #6

CSSOM methods produce unexpected values when retrieving an SVG element's bounding box properties.

CSSOM Methods

CSSOM's `getClientRects()` and `getBoundingClientRect()` method(s) can be used to get the top, right, bottom and left offset coordinates of an element and the width and height of the element's bounding rectangle.

 

CSSOM Methods Used on SVG Elements

...can yield unexpected results.

getBoundingClientRect()

expected result

Pitfall #6: 

Solution

Use getBBox() instead of the CSSOM Methods

var svgElement = document.getElementById('el');
bbox = svgElement.getBBox();

console.log( bbox.x ) ;
console.log( bbox.y ) ;
console.log( bbox.width ) ;  
console.log( bbox.height ) ; 

Important Note

[getBBox()] returns the tight bounding box in current user space (i.e., after application of the ‘transform’ attribute, if any) on the geometry of all contained graphics elements, exclusive of stroking, clipping, masking and filter effects).

Pitfall #7

SVG lacks the concept of relative positioning.

You cannot position an element relative to another element — SVG elements are not governed by a box model.

Pitfall #7:

A Workaround

  • You can nest <svg>s.
  • Each <svg> establishes a coordinate system for its content.
  • The position and dimensions of the <svg> can be retrieved from getBBox() of the element you want to position relative to.
  • That <svg> can then be used to contain and position your element(s).

NESTING SVGs

The inner <svg> gets its properties from the nest’s bounding box properties, and the bird goes INSIDE the <svg> and is positioned relative to it.

Root <svg>

Pitfall #7:

Extra Tip

Use an element's bounding box properties (bbox.x, bbox.y, bbox.width, bbox.height) to define the viewBox area when cropping an SVG to that element.

viewBox="x y width height"

viewBox="bbox.x bbox.y bbox.width bbox.height"

...instead of using an error-prone graphics editor.

Questions?

Thank You!

Tips For Avoiding Common SVG Pitfalls

By Sara Soueidan

Tips For Avoiding Common SVG Pitfalls

Smashing Conf LA, 2015

  • 31,048