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.
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:hover,
.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:hover,
.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
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
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
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%))
produced:
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 themix
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.
color.alpha(1);
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.