DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’»

DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’» is a community of 966,904 amazing developers

We're a place where coders share, stay up-to-date and grow their careers.

Create account Log in
Cover image for Recreating Apple's Color Picker Icon
Mads Stoumann
Mads Stoumann

Posted on

Recreating Apple's Color Picker Icon

I'm currently working on a colorpicker, where a user can select a predefined theme-color:

Initial colorpicker

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:

Apple Color Picker

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; 
}
Enter fullscreen mode Exit fullscreen mode

... which results in this:

Color Picker Icon with gradient border

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; 
}
Enter fullscreen mode Exit fullscreen mode

Which gives us:

With inner white border

Almost there ... but what about "dark mode"? Did you notice the --body-bg-variable? That takes care of inheriting the background-color, so:

Dark mode

The great thing about this technique, is that it just works with and without border-radius:

Square picker


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.

Desaturated

Top comments (5)

Collapse
 
afif profile image
Temani Afif

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:

Collapse
 
madsstoumann profile image
Mads Stoumann Author

Sweet and beautiful! Thank you!

Collapse
 
afif profile image
Temani Afif

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

Thread Thread
 
madsstoumann profile image
Mads Stoumann Author

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!

Collapse
 
chrisdrit profile image
ChrisDrit

That's awesome, thanks for sharing! πŸ‘

Want the CSS badge for your profile?

It's awarded to the top CSS author each week. Start your post here!