DEV Community

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

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

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! πŸ‘