Dudley Storey
Web development writer, teacher, and speaker. Author of Pro CSS3 Animation (Apress). Contributing editor at Smashing Magazine.
Consultant, Staff Writer at CSS-Tricks
Editor, writer, teacher, Smashing Magazine
This pen.
Pieces of the UI move to aid in an informative UX choreography. This can typically be done with well placed CSS, some JS to trigger interactions. Responsive can be achieved with good CSS media queries.
This pen.
@mixin accelerate($name) {
will-change: $name;
transform: translateZ(0);
backface-visibility: hidden;
perspective: 1000px;
}
.foo {
@include accelerate(transform);
}
src: Wealthfront
Case Study: Netflix
This pen.
Compare to using text with photos to illustrate an article.
var shape = document.getElementById("svg");
// media query event handler
if (matchMedia) {
var mq = window.matchMedia("(min-width: 500px)");
mq.addListener(WidthChange);
WidthChange(mq);
}
// media query change
function WidthChange(mq) {
if (mq.matches) {
shape.setAttribute("viewBox", "0 0 490 474");
}
else {
shape.setAttribute("viewBox", "0 490 500 500");
}
};
Acts like a window to show and hide the requisite parts of the sprite
here's why...
(I don't work for them and they don't pay me.)
Bad transform origin bug on rotation, soon to be solved in Firefox.
More in this CSS-Tricks article.
Chrome
IE
Firefox
Safari (zoomed)
The issue with longer CSS animations:
This pen.
This pen courtesy of GreenSock.
This pen.
//variable declaration for the global repeated animations
const gear = $("#gear1, #gear2, #gear3");
...
//animation that's repeated for all of the sections
function revolve() {
let tl = new TimelineMax();
tl.add("begin");
tl.to(gear, 4, {
transformOrigin: "50% 50%",
rotation: 360,
ease: Linear.easeNone
}, "begin");
...
return tl;
}
const repeat = new TimelineMax({repeat:-1});
repeat.add(revolve());
function paintPanda() {
let tl = new TimelineMax();
tl.to(lh, 1, {
scaleY: 1.2,
rotation: -5,
transformOrigin: "50% 0",
ease: Circ.easeOut
}, "paintIt+=1");
...
return tl;
}
//create a timeline but initially pause it so that we can control it via click
const triggerPaint = new TimelineMax({ paused: true });
triggerPaint.add(paintPanda());
//this button kicks off the panda painting timeline
button.addEventListener("click", function() {
triggerPaint.restart();
});
...
MorphSVGPlugin.convertToPath("ellipse");
function flame() {
var tl = new TimelineMax();
tl.add("begin");
tl.fromTo(blurNode, 2.5, {
attr: {
stdDeviation: 9
}
}, {
attr: {
stdDeviation: 3
}
}, "begin");
var num = 9;
for (var i = 1; i <= num; i++) {
tl.to(fStable, 1, {
morphSVG: {
shape: "#f" + i
},
opacity: ((Math.random() * 0.7) + 0.7),
ease: Linear.easeNone
}, "begin+=" + i);
}
By Blake Bowen
function solve(data) {
var size = data.length;
var last = size - 4;
var path = "M" + [data[0], data[1]];
for (var i = 0; i < size - 2; i +=2) {
var x0 = i ? data[i - 2] : data[0];
var y0 = i ? data[i - 1] : data[1];
var x1 = data[i + 0];
var y1 = data[i + 1];
var x2 = data[i + 2];
var y2 = data[i + 3];
var x3 = i !== last ? data[i + 4] : x2;
var y3 = i !== last ? data[i + 5] : y2;
var cp1x = (-x0 + 6 * x1 + x2) / 6;
var cp1y = (-y0 + 6 * y1 + y2) / 6;
var cp2x = (x1 + 6 * x2 - x3) / 6;
var cp2y = (y1 + 6 * y2 - y3) / 6;
path += "C" + [cp1x, cp1y, cp2x, cp2y, x2, y2];
}
return path;
}
Article about history in computer science.
var poly = document.querySelector("polyline");
var path = document.querySelector("path");
var points = [
100,350,
200,100,
300,350,
400,150,
500,350,
600,200,
700,350
];
poly.setAttribute("points", points);
path.setAttribute("d", solve(points));
var points = [
100,350,
200,150,
300,350,
400,120,
500,350,
600,180,
700,350
];
var points = [
100,350,
200,100,
300,350,
400,150,
500,350,
600,200,
700,350
];
This pen.
(one source example, The Whole Brain Group)
This pen.
Change the viewbox in JavaScript like we did before:
Media queries for layout, and fallback with Modernizr:
/* media query example element, mobile first */
@media (max-width: 825px) {
container {
width: 100%;
}
}
@media (min-width: 826px) {
.container {
width: 825px;
}
}
You already know this!
Title and associative aria tags:
<svg aria-labelledby="title"
id="svg"
role="presentation"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 765 587">
<title id="title"
lang="en">
Icons that illustrate Global Warming Solutions
</title>
Title for elements in the SVG DOM
Role to let the screen reader know whether to traverse
This resource, with support charts.
This article by Heather Migliorisi.
This is one of the coolest things about SMIL, but the promise of support has a longer tail with GreenSock.
TweenMax.to($firefly1, 6, {
bezier: {
type:"soft",
values:[{x:10, y:30}, {x:-30, y:20}, {x:-40, y:10},
{x:30, y:20}, {x:10, y:30}],
autoRotate:true
},
ease:Linear.easeNone, repeat:-1}, "start+=3");
Motion along a path: Fireflies
TweenMax.set(cow, {
svgOrigin:"321.05, 323.3",
rotation:50
});
What the DOM actually sees
var radius = balloon.getAttribute("r");
var cySet = balloon.getAttribute("cy");
balloon.setAttribute('r', parseInt(radius) + 10);
balloon.setAttribute('cy', parseInt(cySet) - 10);
if (parseInt(radius) > 125) {
ion.sound.play("balloon-pop3");
var balloonTl = new TimelineMax();
balloonTl.add("pop");
balloonTl.to("#balloon", 0.05, {
scale: 5,
opacity: 0,
transformOrigin: "50% 50%",
ease: Circ.easeOut
}, "pop");
...
setTimeout(function(){
balloon.setAttribute("r", "45");
balloon.setAttribute("cy", "233.5");
}, 200);
}
This pen.
tl.call(addAttr);
tl.fromTo(feTurb, 1, {
attr: {
baseFrequency: '0 0'
}
}, {
attr: {
baseFrequency: '0.8 1.2'
},
ease: Sine.easeOut
});
tl.to(feTurb, 1, {
attr: {
baseFrequency: '0 0'
},
ease: Sine.easeIn
});
tl.call(removeAttr);
// filter attribute helpers
function addAttr() {
feTurb.setAttribute('baseFrequency', '0 0');
}
function removeAttr() {
var applyFilter = document.getElementById("applyFilter");
applyFilter.removeAttribute("filter");
}
Encapsulate what is changing
Encapsulate what is changing- Vuex/Redux
export const store = new Vuex.Store({
state: {
showWeather: false,
template: 0
},
mutations: {
toggle: state => state.showWeather = !state.showWeather,
updateTemplate: (state) => {
state.showWeather = !state.showWeather;
state.template = (state.template + 1) % 4;
}
}
});
Watchers/Observables/RxJS
<div id="app" @mousemove="coordinates">
coordinates(e) {
...
this.startArms.progress(1 - (e.clientX / walleCoords)).pause();
}
HTML (Vue Component)
JavaScript
@sarah_edo on twitter
By Dudley Storey
Web development writer, teacher, and speaker. Author of Pro CSS3 Animation (Apress). Contributing editor at Smashing Magazine.