New ColorMe Features

Since releasing it two weeks ago, ColorMe has had time to simmer and I’ve gotten a bunch of great feedback. In that time I’ve made improvements and feature additions. New features include; support for hsl(a) and rrggbbaa colors. Red, green, and blue color adjusters. And the option to choose the format of the output color.

The first updates I made I snuck in the day after release. Those were improvements to the color adjuster sliders for touch devices. Or more accurate, devices without hover support. I knew the initial design had usability issues on mobile, but decided to ship it and iterate.

The main problem was the horizontal scrolling interfering with the range sliders. The thumb of the sliders was too hard to get a hold of with a finger. And it was tough to adjust the slider instead of scrolling horizontal. For this first update I didn't change the UI completely for touch devices. For now I only increased the size of the thumb on the range sliders in this pull request.

A screenshot of touch device use of color adjusters on ColorMe
The new size of an inactive and an active thumb on touch devices. It looks odd here, but easier to see and handle when you’re using a finger instead of a mouse pointer.

By default the CSS targets all devices. The range slider thumb is large. Almost comical in size and off center vertically when active. It looks strange in a screenshot, but the larger size and y-offset make it easier to control when using a finger.

.adjusterValRange::-webkit-slider-thumb {
  height: 1.6rem;
  margin-top: -0.8rem;
  width: 1.6rem;

.adjusterValRange::-webkit-slider-thumb:active {
  margin-top: -1.8rem;
  height: 2.5rem;
  width: 2.5rem;

To decrease the thumb size on devices with hover support , I used the hover media query available in Media Queries Level 4.

@media (hover) {
  .adjusterValRange::-webkit-slider-thumb {
    height: 0.75rem;
    margin-top: -0.3rem;
    width: 0.75rem;

  .adjusterValRange::-webkit-slider-thumb:active {
    margin-top: -0.5rem;
    height: 1.1rem;
    width: 1.1rem;

I’m a huge fan of using the hover media query instead of relying on screen size. The issue isn’t caused because the screen is too narrow. It’s caused by not having the fine control a mouse and cursor provide. The new media query isn’t available in all browsers yet, but support is good enough for these purposes.

You can see the full CSS for the adjuster range sliders in Adjuster.css.

Usability of the adjusters on touch devices still has room for improvement. There’s an open issue about it in the repo. Along with the ideas there, I have an alternate UI I’d like to try out. That will likely be the next round of changes I make to the project.

Red, green, and blue adjusters

An animated gif showing red, green, and blue color adjusters ColorMe
Adjust the red, green, and blue channels.

In the first release I also left out three of the available color adjusters. Red, green, and blue. Those are in place now. They do what they say on package. Each one adjusts that single channel. Could be helpful for finding that perfect reddish-greenish-blue. Or for finding a good complementary color.

New supported formats

An animated gif showing new format inputs in ColorMe
hsl(a) and rrggbbaa formats now supported.

One of the first bits of feedback I got was from my coworker, Justin. He said ColorMe should support rrggbbaa colors for the base color. I’d never used them before so I took some time to educate myself. If they’re new to you too, read this post. Then play with them in ColorMe to get a better feel how they work. I’ve been using the alpha adjuster to go through each value to see what the percentage is in hex. It’s still taking me some time to think about alpha values as hex, but I'm a fan. You should give it a try if you haven’t already.

I also added support for hsl(a) base colors. This was a no-brainer. It just didn't make the cut for first release.

Choosing output color format

An animated gif showing new format selection in ColorMe
You can now choose the output color format.

OK, this is a fun one! Also the one that required the most effort. A request I got was the ability to see the output color in hex or hsl(a) format instead of only rgb(a). This was also something I’d been wanting. So I took the idea and ran with it.

You now have the option to choose the format for the output color. There are up to seven different formats depending on the color. The full list of formats is; hex, hex shorthand, rrggbbaa, rrggbbaa shorthand, rgb(a), hsl(a), and keyword. Depending on the base color some of them are available and some aren’t.

When you choose a format, ColorMe will do its best to hold on to your selection. Sometimes though there's no way to display a color in a certain format. For example; say you enter the color red. The output format is "keyword". Now, say you adjust the alpha value to 90%. There is no hex or keyword format for the new color. In that case ColorMe switches to the rgba format. It also disables the hex, hex shorthand, rrggbbaa shorthand and keyword formats because those aren't available. In the UI, this just happen for you. React makes short work out of maintaining view layer updates. Behind the scenes there’s a lot of logic to determining what formats work for each color.

If you’re interested in that logic, have a look at the getColorFormats function in utils/color.js. The code there isn’t clever. Most of it is if statements representing what I knew should be true about each format. Because this type of logic can be brittle when making changes, I also wrote a battery of tests to let me know when I break things.

A bug fix and open-source sleuthing

As I was tinkering with the UI, I hit one of those voodoo, ghost-looking bugs. After fiddling with the knobs a while longer, I saw the pattern and was able to reproduce the issue.

When using the alpha adjuster with the tint, shade, or contrast adjusters, the alpha value was wrong. For example, this code;

color(red a(10%) tint(50%))


rgba(255, 128, 128, 0.19999999999999996)

when I expected it to produce:

rgba(255, 128, 128, 0.1)

First I made sure my code wasn't up to anything fishy. Then started looking at my dependencies. The unexpected results were coming from the the css-color-function package. To complicate things more, the problematic code didn't end in css-color-function. It was its use of another color package.

css-color-function uses the mix function of that color package for tint, shade, and contrast adjusters. The Color.mix function was ported from Sass. In Sass, the mix function not only mixes color channels, it also mixes the alpha channel.

The opacity of the colors is also considered when weighting the components.

From the Sass docs on the mix function

As far as I can tell, this isn't the intended behavior of the color function adjusters. For ColorMe, I forked css-color-function and modified its blend method. The problematic adjusters use that method. What I did was take the alpha value out of play before mixing colors. Then put it back when finished. Here's my updated version of the blend method:

exports.blend = function (color, args) {
  var targetAlpha = color.alpha();

  // Reset the alpha value to one. This is required because color.mix mixes
  // the alpha value as well as rgb values. For blend() purposes, that's not
  // what we want.

  var other = new Color(args[0].value);
  var percentage = 1 - parseInt(args[1].value, 10) / 100;

  // Finally set the alpha value of the mixed color to the target value.
  color.mix(other, percentage).alpha(targetAlpha);

ColorMe is now using my fork of css-color-function. I opened a pull request to get the changes the original fork. I also added more detail about the cause and solution in the description of that PR.

Pull requests beget pull requests

When I started pulling at this thread I found two other projects affected by it. I'm sure there are others. I opened a pull request in postcss-color-function and reported the problem in postcss-cssnext.

More to come

I had a lot fun with these updates, hope folks find them useful. As said I have more ideas for future ColorMe updates. And as always if you see issues or have ideas, open an issue.

Thanks for reading