I'm currently working on a colorpicker, where a user can select a predefined theme-color:
While this is fairly simple to code and use, there will be cases where the user needs to create a custom color.
So, how do you indicate that a color is custom, is not a part of the default theme-colors — and can be modified?
I've spent quite some time investigating this, and then I discovered how Apple do it in their Notes-app:
Simple and beautiful! The chosen color is displayed at the center of the circle, surrounded by an inner border and a gradient of hues.
But how to achieve this in CSS?
As always, Temani Afif has the answer.
We'll just replace the linear-gradient
with a conic-gradient
:
.box::after {
content: "";
position: absolute;
inset: 0;
border-radius: inherit;
padding: 8px;
background: conic-gradient(
hsl(360, 100%, 50%),
hsl(315, 100%, 50%),
hsl(270, 100%, 50%),
hsl(225, 100%, 50%),
hsl(180, 100%, 50%),
hsl(135, 100%, 50%),
hsl(90, 100%, 50%),
hsl(45, 100%, 50%),
hsl(0, 100%, 50%)
) border-box;
-webkit-mask:
linear-gradient(#fff 0 0) content-box,
linear-gradient(#fff 0 0);
-webkit-mask-composite: xor;
mask-composite: exclude;
}
... which results in this:
Nice! Now, for the "inner border", I created a second mask:
.box::before {
content: "";
position: absolute;
inset: 0;
border-radius: inherit;
padding: 12px;
background: linear-gradient(var(--body-bg) 0 0) border-box;
-webkit-mask:
linear-gradient(#fff 0 0) content-box,
linear-gradient(#fff 0 0);
-webkit-mask-composite: xor;
mask-composite: exclude;
}
Which gives us:
Almost there ... but what about "dark mode"? Did you notice the --body-bg
-variable? That takes care of inheriting the background-color, so:
The great thing about this technique, is that it just works with and without border-radius
:
Final Thoughts
I must admit it annoys me a bit to use both pseudo
-elements for masks: one for the conic-gradient
and one for the inner border. The last one should simply "cut out" an area and let the background-color of the page or section "shine through". If you know how to do this, please share your findings in the comments!
After I finished writing this post, I noticed that Apple's icon is a bit more de-saturated. To achieve this, just change the saturation
-part of the hsl
-colors in the mask.
Example: Change hsl(360, 100%, 50%)
to hsl(360, 80%, 50%)
etc.
Top comments (5)
You can avoid the second mask if you play with background-clip. You add padding to the main element and you color only the content-box area:
Sweet and beautiful! Thank you!
and if you want to get rid of both pseudo-elements you can use multiple gradient and mask like below:
The main color above the conic-gradient and the mask will cut the inner transparent border
Ah, very cool. I have the selected color as a custom prop, so I'll expand with 2 for outer/inner border (15px/8px). Thank you!
That's awesome, thanks for sharing! 👏