Every once in a while I’m motivated to attempt to draw some shapes with <path>
, the all-powerful drawing syntax of SVG. I only understand a fragment of what it all can do, but I know enough to be dangerous. All the straight-line syntax commands (like L
) are pretty straightforward and I find the curved Q
command fairly intuitive. Box yourself into a viewBox="0 0 100 100"
and drawing simple stuff doesn’t seem so bad.
Here’s a classic example of mine that draws things with all the basic commands, but also animates them with CSS (Chromium browsers only):
Weird but true:
<svg viewBox="0 0 10 10">
<path d="M2,2 L8,8" />
</svg>
svg:hover path {
transition: 0.2s;
d: path("M8,2 L2,8");
}
The other day I had a situation where I needed a UI element that has a different icon depending on what state it’s in. It was kind of a “log” shape so the default was straight lines, kinda like a hamburger menu (only four lines so it read more like lines of text), then other various states.
- DEFAULT
- ACTIVE
- SUCCESS
- ERROR
First I wrote the most complicated state machine in the world:
const indicator = document.querySelector(".element");
let currentState = indicator.dataset.state;
indicator.addEventListener("click", () => {
let nextState = "";
if (currentState == "DEFAULT") {
nextState = "ACTIVE";
} else if (currentState == "ACTIVE") {
nextState = "SUCCESS";
} else if (currentState == "SUCCESS") {
nextState = "ERROR";
} else {
nextState = "DEFAULT";
}
indicator.dataset.state = nextState;
currentState = nextState;
});
That opened the door for styling states with data-attributes:
.element {
&[data-state="DEFAULT"] {
}
&[data-state="ACTIVE"] {
}
&[data-state="SUCCESS"] {
}
&[data-state="ERROR"] {
}
}
So now if my element starts with the default state of four lines:
<div class="element" data-state="DEFAULT">
<svg viewBox="0 0 100 100" class="icon">
<path d="M0, 20 Q50, 20 100, 20"></path>
<path d="M0, 40 Q50, 40 100, 40"></path>
<path d="M0, 60 Q50, 60 100, 60"></path>
<path d="M0, 80 Q50, 80 100, 80"></path>
</svg>
</div>
…I can alter those paths in CSS for the rest of the states. For example, I can take those four straight lines and alter them in CSS.
Note the four “straight” lines conveniently have an unused curve point in them. Only paths that have the same number and type of points in them can be animated in CSS. Putting the curve point in there opens doors.
These four new paths actually draw something close to a circle!
.editor-indicator {
&[data-state="ACTIVE"] {
.icon {
:nth-child(1) {
d: path("M50, 0 Q95, 5 100,50");
}
:nth-child(2) {
d: path("M100, 50 Q95, 95 50,100");
}
:nth-child(3) {
d: path("M50,100 Q5, 95 0, 50");
}
:nth-child(4) {
d: path("M0, 50 Q5, 5 50, 0");
}
}
}
}
For the other states, I drew a crude checkmark (for SUCCESS) and a crude exclamation point (for FAILURE).
Here’s a demo (again, Chromium), where you can click it to change the states:
I didn’t end up using the thing because neither Firefox nor Safari support the d: path();
thing in CSS. Not that it doesn’t animate them, it just doesn’t work period, so it was out for me. I just ended up swapping out the icons in the different states.
If you need cross-browser shape morphing, we have a whole article about that.
I love this! Great demo. Too bad it didn’t work cross browser :(
I’m curious, how do you create the shapes for these types of things and then manipulate the points? Do you draw them in a vector program first, or are you “hand coding” SVG since they are fairly simple shapes?
d
will become a presentation attribute (as noted in this interesting discussion, linked in the SVG2 draft spec: https://www.w3.org/2016/04/21-svg-minutes.html), therefore it’s expected to be working in CSS (and JS via the Web Animation API) in all browsers soon.You don’t asked to me but (if it can be helpfull) I think that most often you can code your SVGs directly in a CodePen. There’s not so much to learn. When you have a lot of shapes, you can start in Adobe Illustrator, but it can result to SVG elements or path commands that can’t be edited (in code) easily. Using the pathfinder, expanding appearance, … can transform a simple ellipse, rectangle, etc… into a complex path with floating numbers.
maybe you should look at how d3 implements its changes through states so you can achieve cross browser support.
Works just fine in Firefox nightly for android…
works for me in Firefox 99.0.1