SVG animation with CSS and Greensock
// some basic starter examples
// xmlns is good to keep in for backwards compatibility
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="450px" height="100px" viewBox="0 0 450 100"> // width can be pull out and define in css for responsive
<rect x="10" y="5" fill="white" stroke="black" width="90" height="90" />
<circle fill="white" stroke="black" cx="170" cy="50" r="45" /> //cx: center point on the x axis, cy: center point on the y axis
<polygon fill="white" stroke="black" points="279,5 294,35 328,40 303,62 309,94 279,79 248,94 254,62 230,39 263,35 " />
<line fill="none" stroke="black" x1="410" y1="95" x2="440" y2="6" />
<line fill="none" stroke="black" x1="360" y1="6" x2="360" y2="95" />
</svg>
// polyline: array of points for mapping coordinates or data viz
<polyline points="14,17 136,37 77,117 230,87 132,158 172,158" />
Default: preserveAspectRatio = "xMidYMid meet"
// uniformly scales, like background-size: cover in css
// align the ___ of the element's viewBox with the ___ value of the viewport
Takes two parameters: <align> <meetOrSlice>
x___ Y___ ______
min min meet
mid mid slice
max max
Or None
Meet (default):
- Entire viewBox is visible within viewport
- the viewBox is scaled up as much as possible, meeting other criteria
- viewBox < viewport
Slice:
- entire viewport is covered by the viewBox
- the viewBox is scaled down as much as possible, meeting other criteria
- viewBox > viewport
// Resources
- jankfree.org
- advanced performance audits with devTools by Paul Irish
- CSS-Tricks Article: Weighing SVG Animation techniques with benchmarks
// paths and groups
<svg viewBox="0 0 218.8 87.1">
<g>
<path d="M7.3 75L25.9 6.8s58.4-6.4 3.5 13-41.1 32.8-11.2 30.8h15.9v5.5s42.6 18.8 0 20.6" /> //no z at the end so it's not closed
<path d="M133.1 58.2s12.7-69.2 24.4-47.5c0 0 4.1 8.6 9.5.9 0 0 5-10 10.4.9 0 0 12.2 32.6
13.6 43 0 0 39.8 5.4 15.8 15.4-13.2 5.5-53.8 13.1-77.4 5.9.1 0-51.9-15.4 3.7-18.6z" />
</g>
</svg>
// g will group together and can assign group class to a set of grouped elements and move multiple things at once
<g fill="none" stroke="black">
...
</g>
// explanation on the letters in path data
for Path letter: (cap: absolute, non cap: relative positioning)
Path letter Path meaning Note
M, m moveTo start of the path, start of a new path
L, l lineTo
H, h horizontal line drawn
from current position
V, v vertical line drawn
from current position
Ending Paths
Z, z joins the end of a path end of the path
// path example
// Curve commands
C, c cubic-bezier
S, s refecting cubic-bezier
Q, q quadratic bezier- where both sides share the same control point
T, t command control point that's been reflected
A, a elliptical arc
// SVGs for animation support breakdown
// or how I learned to love the inline
For image src, object, embed, background url, and iframe, you can only designate animation if inside the SVG
But for inline, both SVG animation and interaction are supported
=> so if you are animating your svgs, put it inline in your code
// Title and associative aria tags (WIP)
<svg aria-labelledby="title" id="svg"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 765 587">
<title id="title" lang="en">
Circle of icons that illustrate global warming solutions
</title>
1. Platonic Shapes
2. ViewBox
3. PreserveAspectRatio
4. Grouping
5. Drawing Paths
6. SVG on Export
// Media queries for layout and fallback with Modernizr
// break page up to smaller components and resize/rearrange components with diff screen sizes
// media query example element, mobile first
@media (max-width: 825px) {
.container {
width: 100%;
}
}
@media (min-width: 826px) {
.container {
width: 825px;
}
}
// fallback
.inlinesvg .fallback {
dislay: none;
}
.no-inlinesvg .fallback {
width: 500px;
height: 500px;
display: block;
}
// After export from illustrator, before implementation
// OPTIMIZE!!!
- SVGOMG // preferred
https://jakearchibald.github.io/svgomg/
- Peter Collingridge's SVG editor // can go in and edit some more
https://petercollingridge.appspot.com/svg-editor
- SVGO / SVGO-GUI // terminal-based
[class^="star"] {
animation: blink 2s ease-in-out infinite both;
}
[class^="dot"] {
animation: blink 5s -3s ease-in-out infinite both;
}
@keyframes blink {
50% { opacity: 0; }
}
// No width and height for the SVG itself, instead define it in CSS
.initial {
width: 50%;
float: left;
margin: 0 7% 0 0;
}
// we are using percentage here, but we could also use flexbox
viewBox="0 0 490 474" preserveAspectRatio="xMidYMid meet"
// Define smaller viewBox, put in preserveAspectRatio (tho this is also the default)
// Animation MEDIA Queries
(adjust initial object, affects animation)
[class^="mountain"], [class^="grass"] {
transform: skew(2deg);
}
@media screen and ( max-width: 500px ) {
[class^="mountain"], [class^="grass"] {
transform: skew(1.5deg);
}
}
// viewbox shift in sprite with javascript
// acts like a window to show and hide the requisite parts of the sprite
var shape = document.getelementById("svg");
//media query event handler
if (matchMedia) {
var mg = window.matchMedia("(min-width: 500px)");
mq.addListener(WidthChange);
WidthChange(mq);
}
function widthChange(mq) {
if (mq.matches) {
shape.setAttribute("viewBox", "0 0 490 474");
} else {
shape.setAttribute("viewBox", "0 490 500 500");
}
}
// Elemental Motion
- Further away is less contrast, blurry
- Does the air or environment affect movement
- Reducing precision allows for understanding
- Combine techniques
// Animating with CSS, refresher
// Keyframes
@keyframes animation-name-you-pick {
0% {
background: blue;
transform: translateX(0);
}
50% {
background: purple;
transform: translateX(50px);
}
100% {
background: red;
transform: translateX(100px);
}
}
// Animation properties -shorthand
.ball {
animation: animation-name-you-pick 2s 2s 3 alternate ease-in-out forwards;
}
// animating SVG with CSS has the following gotchas
- moving the whole SVG instead of the circle
- background doesn't work for SVG, we use fill
- Apply the fill to the circle, not whole SVG
// instead of apply animation to the whole div, we will apply to the circle instead and instead of animating background color, we will use fill. Also make viewBox wider so the circle does not animate out of it
<svg width="200px" height="70px" vewBox="0 0 200 70">
<circle class="ball2" cx="45" cy="45" r=25" />
</svg>
@keyframes second-animation {
0% {
fill: blue;
transform: translateX(0);
}
50% {
fill: purple;
transform: translateX(50px);
}
100% {
fill: red;
transform: translateX(100px);
}
}
// Key takeaways
- Target the circle, expend the viewBox, use fill, and remove the fill from the markup