SVG, CSS and You

SVG Summit 2017

@dudleystorey

thenewcode.com

SVG and CSS are becoming more closely entwined

  • SVG presentation attributes are becoming CSS properties
  • CSS animation is finally starting to make sense in the context of SVG 
  • CSS Variables are cool! (And can be used in SVG to great effect)

A typical SVG Export:

<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 18.0.0, 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"
     viewBox="0 0 500 500" enable-background="new 0 0 500 500" xml:space="preserve">
<circle fill="#FF0000" cx="250" cy="250" r="200"/>
</svg>

Cleaned up:

<svg xmlns="http://www.w3.org/2000/svg" 
viewBox="0 0 500 500">
  <circle fill="red" cx="250" cy="250" 
  r="200"/>
</svg>

Better:

<svg xmlns="http://www.w3.org/2000/svg" 
viewBox="0 0 500 500">
<defs>
  <style>
    circle { fill: red; }
  </style>
</defs>
<circle cx="246" cy="252" r="226"/>
</svg>

(All current browsers)

Even better:

<svg xmlns="http://www.w3.org/2000/svg" 
viewBox="0 0 500 500">
<defs>
    <style>
        circle { fill: red; cx: 250; 
            cy: 250; r: 200; }
    </style>
</defs>
    <circle />
</svg>

(              only, at the moment)

This means you can do:

@keyframes throb {
    from   { r: 100; }
    to     { r: 200; }
}
circle {
    animation: throb 2s alternate infinite; 
}

Creating:

All SVG presentation attributes are CSS properties (and can therefore be animated). Those of particular interest to animators include: 

https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute#Presentation_attributes

A complete list:

This means that SVG strokes:

<svg xmlns="http://www.w3.org/2000/svg" 
viewBox="0 0 315.2 98.9">
<path d="M15.9 79.3C92-19.5 135.2 42.2 180 
67s95.6-14.4 118.5-45.2"/>
</svg>

Can be styled with CSS:

path { 
  fill: none;
  stroke: #231F20;
  stroke-width: 6;
  stroke-dasharray: 333.3;
  stroke-dashoffset: 333.3;
}

And animated with the same:

@keyframes pathDevelop {
  to {
    stroke-dashoffset: 0;
  }
}

path { 
  animation: pathDevelop 2s linear forwards;
}

http://thenewcode.com/1183/Web-Developer-Reading-List-CSS-Animations

The problem is finding the length of the path, for the correct values. You can do this in JS:

let path = document.querySelector("path"),
pathLength = path.getTotalLength();

That means that (among other methods) the Web Animations API can be used to animate path stroke:

var path = document.querySelector("path"),
pathLength = path.getTotalLength();
path.style.strokeDasharray = pathLength;
path.style.strokeDashoffset = pathLength;
pathTravel(path, pathLength);

function pathTravel(travelPath, pathDist) {
    travelPath.animate([
        { strokeDashoffset: pathDist },
        { strokeDashoffset: "0" }
        ], {
        duration: pathDist * 5,
        fill: "forwards"
    })
}

http://thenewcode.com/1182/Web-Developer-Reading-List-The-Web-Animations-API

33

36

23

Support:

And an excellent polyfill for the rest:

https://github.com/web-animations/web-animations-js

(Note that the level of support differs across browsers)

Other options:

Vivus (https://maxwellito.github.io/vivus/)

CSS Variables (aka Custom Properties)

  • Similar to (but not entirely overlapping with) CSS preprocessor variables (such as Sass and Less)
  • Most distinct difference: they are written directly in CSS, and remain there (i.e. that are not compiled into anything)
  • This means that they are live and readable by CSS, JavaScript, and anything in the DOM... including SVG!

Variables must be declared:

:root {
    --themeSpotColor: hsl(230, 78%, 55%);
}

Before they can be used:

#logo {
    fill: var(--themeSpotColor);
}

This makes variables incredibly useful for centralizing CSS themes, and using them in inline SVG:

<path style="fill:var(--color_palette, #b84);
    stroke:var(--stroke_palette);
    stroke-width:var(--stroke-width_palette);"

/>

You can also create new variables based on the value of others using calc():

svg {
    --startRad: 50;
    --startColor: blue;
    }
circle {
    r: var(--startRad);
    fill: var(--startColor);
    transition: 1s r;
    cx: 100;
    cy: 100;   
}
circle:hover {
    r: calc(var(--startRad) * 1.5);
}

31

49

36

Support:

Planned support for Edge 15

Right now the best approach for production is to use a pre- or post-processor, baking the result into CSS

9.1

@dudleystorey

codepen.io/dudleystorey/

thenewcode.com