A couple of weeks ago, while fiddling around with my iPhone's Control Center, I noticed a new icon: "Dark Mode":
I've seen plenty "Dark Mode"-icons — most of them involving the sun and the moon — but this one is so simple and intuitive.
Let's re-create it in SVG, and add some CSS magic!
First, we need a circle:
<circle r="195" cx="200" cy="200" fill="#FFF" stroke="#000" stroke-width="10" />
I've added a black stroke, so the icon works on light backgrounds as well:
Now, the semi-circle is a bit more complicated. For this, we need an Arc.
In SVG, this is called A
, and is within a path
:
<path d=" M 200 375 A 175 175 0 0 1 200 2" />
While you can manually code arcs, it's much easier to use a tool for it. Here's an online tool, you can use.
Now, we have this:
Let's add two more semi-circles
<path d=" M 200 300 A 100 100 0 0 1 200 100" fill="#FFF" />
<path d=" M 200 100 A 100 100 180 0 1 200 300" />
— and we have this:
Now for the fun part! Let's add a single CSS Custom Property, that can either be 0
or 1
:
body {
--dark-mode: 0;
}
Using this property, we'll set the background-color
of the page:
body {
background-color: hsl(0, 0%, calc(100% * (1 - var(--dark-mode))));
}
In hsl
, the third paramter is lightness. 0%
is black, while 100%
is white. So we'll multiply 100%
with either 1
(dark mode on) or 0
(dark mode off).
We'll use the same property to invert
and rotate
the icon:
.class {
filter: invert(var(--dark-mode));
transform: rotate(calc(var(--dark-mode) * 180deg));
}
Now, if you change the --dark-mode
-property to 1
, the icon will invert and rotate, and the background of the page will change to black:
How you toggle the property is up to you. The "no-JS"-way could be a checkbox
, while the JS-way could be something like this:
element.addEventListener('click', () => {
const current = document.body.style.getPropertyValue("--dark-mode") - 0;
document.body.style.setProperty("--dark-mode", 1 - current);
})
First, get the current status using getPropertyValue()
. Convert it to a numeric value by subtracting a 0
(old JS-hack!), then set the opposite value using setProperty()
.
Here's a Codepen demo:
NOTE: In the Codepen, I've added the JS-toggle-function to the
svg
itself. In production, add proper semantics, like a<button>
or similar.
Top comments (6)
If you are interested here is a CSS only solution :)
I had a sneaking feeling you’d do that 😁 Great work, as always.
I started one then thought, I'll just wait for @afif 😅
Maybe we can push him to add a cool animation to it? 😉
why not 😉 (I am using :has() which works on Safari and Chrome with flag enabled, Yes I am lazy to use old stuff )
This is really cool, thanks for sharing!