Download as pdf or txt
Download as pdf or txt
You are on page 1of 11

Home / Articles /

Animating Single Div Art


2 Comments
Author
Go to
Dan Wilson
Comments

Published Updated
May 31, 2017 May 31, 2017

When you dig deep with your tools, it is amazing what you can create out of the most basic of
HTML. I have been constantly impressed with "Single Div Art" by Lynn Fisher
(http://a.singlediv.com/) and others where you take a single generic <div> to create a beautiful
cactus (http://a.singlediv.com/#cactus2) , Alamo (http://a.singlediv.com/#alamo) , or panda.

Embedded Pen Here

It can be hard to jump in and deconstruct how these are made, due to the fact they are using layers
of background gradients, box shadows, text shadows, and more in the midst of just a single div and
it's ::before and ::after pseudo-elements. Before we go any further… check out Lynn Fisher's
article on why and how she started working with single div art
(https://hacks.mozilla.org/2014/09/single-div-drawings-with-css/) .

One thing that single div pieces rarely do is animate. If you can transform your div or one of its
pseudo elements, that's fair (as Lynn Fisher does with her fantastic BB-8
(http://a.singlediv.com/#bb8) ). But you cannot directly change the opacity or transform of the
individual "elements" you create inside your div , since they are not actual DOM elements.

I am a big believer of trying something a little different and interesting to learn tools you otherwise
might never learn. Working with the constraints of a single div might not be great for production
work, but it can be a great exercise (and challenge) to stretch your skills in a fun way. In that spirit,
we'll use this technique to explore how Custom Properties (CSS Variables) work and even provide
us a path to animation inside our div . To illustrate along the way we will be breaking down the
following example with multiple animation approaches:

Embedded Pen Here

This accordion (the instrument, not the UI construct) has three main parts, the keyboard side (our
div ), the bellows (the part that squeezes, which is the div::before ), and the button side
( div::after ). Since the accordion naturally divides into these pieces, we can transform each
piece inside CSS Keyframe animations to get our animation started. The bellows are going between
different scaleX values and the two sides are using countering translateX values to move with
the scaling bellows. Thus, the squeezebox is born.

Embedded Pen Here

Organizing the <div> with CSS


Custom Properties
Animating and thinking about the three big pieces is more straightforward than thinking about what
appears inside. It can be helpful to group and name the individual bits inside the div , and Custom
Properties provide us a native way to do this. Instead of levels of seemingly infinite linear gradient
stops, you can define the -white-key s and --black-key s for a piano keyboard. Instead of a
cross-section of multiple layered gradients you can have a --tea-cup with its individual --tea-
bag and a related --tea-bag-position defined inside.
The left side of the accordion boils down to:

CSS

background:
var(--shine),
var(--shine),
var(--button-key1, var(--button)),
var(--button-key2, var(--button)),
var(--button-key3, var(--button)),
var(--black-keys),
var(--white-keys),
var(--keyboard-base);

Those variable values might be several lines long (even hundreds), but conceptually how the layers
of the keyboard come into play are clearer thanks to the variables.

Embedded Pen Here

While the same can be done with Sass or Less, Custom Properties allow us to modify these values
in the future. We can now conceptually think about animating just our --button-key2 or the
accordion's decorative --shine . There are a few ways to tackle this.

Animating Large Property


Values with CSS Keyframes
The first way is to use CSS keyframe animations to change the property that contains the piece you
want to move. If you want to change something inside your background (say, for example, we want
to change the color of our "shine" lines from red to blue), you can set swap out values in the
background property. Building on the previous code sample:

CSS

div {
/* using background definition from earlier */
--shine: linear-gradient(to right, transparent 29.5%, red 29.5%, red
--shine-blue: linear-gradient(to right, transparent 29.5%, blue 29.5%
animation: modify-shine 2000ms infinite alternate ease-in-out;
}
@keyframes modify-shine {
100% {
background:
var(--shine-blue), /*these two replace the original --shine*/
var(--shine-blue),
/* the rest of the background remains unchanged */
var(--button-key1, var(--button)),
var(--button-key2, var(--button)),
var(--button-key3, var(--button)),
var(--black-keys),
var(--white-keys),
var(--keyboard-base);
}
}

This give us a lot, especially since background is animatable (as are text-shadow and box-
shadow ). In this example there would be a transition from red to blue.

If your property is long, this can be hard to maintain, though Custom Properties can give us a help
by extracting out the parts that don't change to minimize the repetition. We can take it further by
abstracting out pieces that don't need to animate into a new variable - resulting in levels of
variables:
CSS

div {
--static-component:
var(--button-key1, var(--button)),
var(--button-key2, var(--button)),
var(--button-key3, var(--button)),
var(--black-keys),
var(--white-keys),
var(--keyboard-base);
background:
var(--shine),
var(--shine),
var(--static-component);
}
@keyframes modify-shine {
100% {
background:
var(--shine-blue),
var(--shine-blue),
var(--static-component);
}
}

The three musical notes in the accordion are based on this approach by animating text-shadow .

Embedded Pen Here


Animating with Custom
Properties inside CSS Keyframes
A related way to change states is to directly change the custom property inside the keyframes .

CSS

@keyframes {
0% {
--button1-color: var(--color-primary);
}
100% {
--button1-color: var(--color-secondary);
}
}

A custom property has no predefined behavior and is not a useful property until it is used with
var(…) , so the spec states changing one's value will cause it to flip its value at 50%
(https://www.w3.org/TR/css-variables/#syntax) . This is the default behavior for all CSS properties
that are not animatable and means it will not transition between the values.

You may have guessed since I already mentioned the spec that this is not available in all browsers.
Currently, this is supported in Chrome and Opera only.

This will be a quick way to get jump states when it is supported across browsers. If you are viewing
this in Chrome or Opera, the accordion uses this approach to animate the keys on the keyboard and
the buttons on the right side. For a smaller example, here is a "Pixel Art" example using this
approach where the eyes and eyebrows will move in Blink browsers. Other browsers will nicely fall
back to a static image. This is in many ways will use the least amount of code, but will have the
least amount of support.
Embedded Pen Here

Animating Custom Property


Values via JavaScript
A third method is to use JavaScript to set new property values directly (or apply classes that have
different property values). In its basic form, this could be a call to setInterval to toggle an on/off
state for a value (for our piano this could be a key pressed or not).

JavaScript

var div = document.querySelector('div');


var active = false;
setInterval(function() {
active = !active;
div.style.setProperty('--white-key-1',
'var(--white-key-color-' + (active ? 'active' : 'default') +')')
}, 1000);

With the corresponding CSS:

CSS

div {
--white-key-1: var(--white-key-color-default);
--white-key-color-default: #fff;
--white-key-color-active: #ddd;
/* And a linear gradient that follows the following pattern */
background: linear-gradient(to right, var(-white-key-1) 5%, var(--whi
}

Embedded Pen Here

We are using JavaScript to set the white-key-1 to be either the value from the variable white-
key-color-default or white-key-color-active depending on its state.

This method is useful when toggling something on and off (such as with a direct change in size,
position, or color). This is how the buttons on the right side of the accordion are animated (as a
fallback when the Keyframe approach is not supported).

Embedded Pen Here

Each of the nine buttons has CSS uses the following default circle, where --color1 is a light blue
and --button-dim is 1.4vmin:

CSS

--button: radial-gradient(circle,
var(--color1) var(--button-dim),
transparent var(--button-dim));

If i want to change a specific button later to a "pressed" state I can set up a specific value in the
CSS, for example the fourth button:
CSS

--button4: radial-gradient(circle,
var(--button4-color, var(--color1)) var(--button4-dim, var(--button-d
transparent var(--button4-dim, var(--button-dim)));

This property is similar, but it replaces the --button-dim and --color1 with values that are
specific to this button combined with a default value inside the var() . This default value can be
specified in our variables by using the form var(--my-specific-variable, 13px) . We can take
it a little further and even use another variable value as our default, e.g. var(--my-specific-
variable, var(--my-default-variable)) . This second form is what our previous code example
uses to create a specific definition for our fourth button while keeping its default value the same. If
you have buttons you want to remain unchanged, they can use the default --button property in a
different background-position .

In the accordion example, --button4-color or --button4-dim are never explicitly defined in the
CSS. So when loaded they use the default values of --color1 and --button-dim . The JS
ultimately modifies the values and creates our on/off animation.

JavaScript

var enabled = false;


setInterval(function() {
enabled = !enabled;
div.style.setProperty('--button4-dim', enabled ? '1.2vmin' : 'var(--b
div.style.setProperty('--button4-color', enabled ? 'var(--color1alt)'
}, 1000);

This will give us behavior similar to changing the Custom Properties directly in a keyframe where
values jump from state to state with no transition. As we've already discussed, background and
the *-shadow properties are animatable (and transitionable… not in a high performance
transform or opacity kind of way… but in small uses that can be okay).

If we take our current JS on/off approach and combine it with a CSS transition on the
background , we can get a transition instead of a jump state.
CSS

div {
transition: background 2000ms ease-in-out;
}

Combining with
requestAnimationFrame
Depending on how your individual components are composed, the ability to transition the property
may not be possible. If you want to move something, you might need to look to
requestAnimationFrame .

One of my favorite Single Divs out there is a backpack by Tricia Katz:

Embedded Pen Here

I would love for that zipper to move back and forth. With a single custom property to represent the
zipper's x position we can reach for requestAnimationFrame to change that value and move the
zipper right and left.

Embedded Pen Here


Conclusion
There are several approaches to animating inside a div that can stretch your skills. To get the
broadest support we can't rely on CSS alone right now, though we can still get pretty far. Custom
Properties make modifying values more direct, even when we need to combine with JavaScript (and
we can lean on our variable naming to be clear what we are changing).

Embedded Pen Here

Whenever you want to learn a new thing in CSS or JavaScript… see if you can find a "Single Div"-
esque way to learn it. When you need to conceptually break properties apart or animate
complicated values, Custom Properties can bring something new to the table.

You might also like