Tag: color

How-to guide for creating edge-to-edge color bars that work with a grid

Hard-stop gradients are one of my favorite CSS tricks. Here, Marcel Moreau combines that idea with CSS grid to solve an issue that’s otherwise a pain in the butt. Say you have like a 300px right sidebar on a desktop layout with a unique background color. Easy enough. But then say you want that background color to stretch to the right edge of the browser window even though the grid itself is width-constrained. Tricker.

Direct Link to ArticlePermalink

The post How-to guide for creating edge-to-edge color bars that work with a grid appeared first on CSS-Tricks.


, , , , , , ,

The Expanding Gamut of Color on the Web

CSS was introduced to the web all the way back in 1996. At the time, most computer monitors were pretty terrible. The colors of CSS — whether defined with the RGB, HSL, or hexadecimal format — catered to the monitors of the time, all within the sRGB colorspace.

Most newer devices have a wide-gamut display. A gamut is the range of colors that can be displayed. A wide-gamut display is capable of showing more colors than sRGB. They use the Display P3 colorspace. (There’s also Rec.2020, an even larger colorspace, but that’s pretty rare and not currently worth thinking about.) As Lea Verou of the CSS working group put it, “Our websites are washed out because screens advanced faster than CSS Color did.” If we want to make full use of the range of colors that the majority of screens are capable of displaying, we need to use new CSS colors formats: lab, lch or display-p3.

Examples in the wild can be found on the website of Panic (creators of the once popular Coda text editor and the still very popular Untitled Goose Game) or the marketing site for a product called Playdate. They both make use of strikingly vibrant and intense colors that are uniquely vivid by making use of display-p3.

Screenshot taken from the Panic website showing bright pink text against a stark black background.
Panic’s website features an eye-catching shade of pink.

To get some idea of the range of colors that are missing from sRGB, check out the following Pen. The inner boxes contain a color beyond the sRGB gamut. The outer boxes show that color clamped to the sRGB color gamut (meaning the nearest equivalent color that a browser is capable of showing without using display-p3, lab, or lch). (Note that support is currently limited to Safari users.)

The color picker in Safari Technology Preview helpfully shows which colors lie outside of the sRGB color gamut.

Screenshot of a color picker going from bright green to black with a light curved line signifying the point where colors go past the typical sRGB range.
Any color above or to the right of the white line lie outside of the sRGB gamut

A tale of new syntaxes

Before jumping into the syntax for lab(), lch(), and the color() function, let’s take a look at the new rgb() and hsl() syntaxes (which are supported in all web browsers, minus Internet Explorer).

Type Old Syntax New Syntax
RGB rgb(0, 128, 255) rgb(0 128 255)
RGBa rgba(0, 128, 255, 0.5) rgb(0 128 255 50%)
HSL hsl(198, 28%, 50%) hsl(198 28% 50%)
HSLa hsla(198, 28%, 0.5) hsl(198deg 28% 50% / 50%)
Source: @mathias 

In the older syntax, each number is comma separated: rgb(200, 100, 20);. Commas are no longer necessary, so the space separated value rgb(200 100 20); is valid. To specify transparency, we can now use rgb(200 100 20 / 50%) rather than using  rgba() or hsla(). There’s no real benefit to the newer syntaxes but it’s worth looking at because they match the syntax for lch(), lab() and color()

Type Syntax
Lab lab(56.29% -10.93 16.58 / 50%)
color() color(sRGB 0 0.5 1 / 50%)
LCH lch(56.29% 19.86 236.62 / 50%

lab(), lch() and color() always use space separated numbers (no commas allowed) and a forward slash followed by a percentage to specify transparency. Let’s take a look at how they work.  

The CSS color() function and display-p3 colorspace

The color() function allows a color to be specified in a particular colorspace (rather than using the sRGB colorspace used by rgb(), hsl(), or hex). The colorspace we need to specify in order to use wide-gamut color is display-p3, which uses three numeric values, representing the red, green, and blue channels of the color: 1 0 0 is total red, 0 0 1 is total blue, and 0 1 0 is total green.

background-color: color(display-p3 1 0 0.331); /* vibrant pink color */

At the time of writing, display-p3 is the only way to access high-gamut colors, having been supported in Safari since 2017. However, lab() and lch() will be better options once they are implemented (Chrome and Safari are currently working on it). Here’s a take from Lea Verou

display-p3 is not perceptually uniform, and is difficult to create variants (lighter or darker, more or less vivid etc) by tweaking its parameters. Furthermore, it’s a short-term solution. It works now, because screens that can display a wider gamut than P3 are rare. Once hardware advances again, color(display-p3 ...) will have the same problem as sRGB colors have today. LCH and Lab are device independent, and can represent the entire gamut of human vision so they will work regardless of how hardware advances.

A better lightness: Lab and LCH

You may have seen articles around the web arguing that HSL is easier to reason about than RGB or Hexadecimal values. 

Here’s Chris Coyier in 2015:

The real appeal of HSLa is that it makes more intuitive sense what changing the values will do to the color. Increasing the second value will increase the saturation of that color. Decreasing the third value will decrease the lightness of that color. That makes creating your own color variations on the fly way easier.

While HSL might be easier to understand than hexadecimal or RGB, it’s far from perfect. The way it calculates lightness simply doesn’t match human perception. According to HSL, hsl(240deg 100% 50%) and hsl(60deg 100% 50%) have the same lightness, 50%. Let’s compare the two.

To the human eye, the blue looks darker. As Brian Kardell puts it: 

Doing things like mixing colors, lightening, darkening, can be done well only if they include a sense of how our eyes really work rather than how machines like to think about storing and displaying.

Here’s a visual example from Lea Verou that demonstrates the superiority of Lab/LCH over HSL. She comments

A trick for aesthetically pleasing gradients of the same color at different lightnesses is to convert to Lab, vary the L instead, and then convert back to HSL/RGB.

“The perceived brightness of all of the hues in a spectrum with the same saturation and lightness. […] It’s quite clear they’re different.” —Brian Kardell (Image: Rob Waychert)

Lab and LCH both use the CIELAB colorspace which is designed to align with human vision. If you give two colors the same lightness value, they appear to the human eye to have the same lightness, regardless of their hue.


background-color: lab(40% 83 -104); /* a shade of purple */

The L in lab() stands for lightness and is written as a percentage (which can go up to 400% for extra bright white, but will generally be between 0% and 100% ). A and B don’t stand for anything — they’re color channels. A is a numerical value between green (negative values) and red (positive values) while B is a numerical value between blue (negative values) and yellow (positive values). Lightness is pretty easy for us to understand. The red/green value and blue/yellow value, however, aren’t exactly intuitive. LCH is probably a better alternative.


background-color: lch(69% 56 244); /* a shade of blue */

lch() is the most human-readable of the new color values. L again stand for lightness (and works in exactly the same way), C is for chroma, and H is for hue. Chroma is largely analogous to saturation, but it can also be thought of as the color intensity or vibrancy. Unlike the other new color formats, you can actually predict the sort of effect changing these individual values will have — its similar to HSL in this way. The best way to get your head around it is to try out this LCH color picker.

Defining fallbacks 

We have two kinds of support to think about: browser support for the new CSS color values and the ability of screens to display these colors.

Falling back to the closest matching sRGB value for browsers that don’t support color functions is easy and exactly like we’re used to defining fallback properties:

.pink-text {   color: rgb(255, 0, 79); /* Will be used as a fallback */   color: color(display-p3 1 0 0.331); /* Will be used if supported */ }

The second line of code in the example above will be ignored if the browser doesn’t understand it and the rgb() value will be used instead, thanks to the cascade. It would be laborious to type out two lines of CSS every time you want to specify a color. CSS variables are a great way to deal with this. In this example we’ll use @supports to tell if the browser has support for color functions in CSS:

/* https://webkit.org/blog/10042/wide-gamut-color-in-css-with-display-p3/ */ :root {   --bright-green: rgb(0, 255, 0); } 
 /* Display-P3 color, when supported. */ @supports (color: color(display-p3 1 1 1)) {   :root {     --bright-green: color(display-p3 0 1 0);   } } 
 header {   color: var(--bright-green); }

If the color is particularly important to your design, you could utilize a background-image as most browsers do support high-gamut colors in images.

@supports not (color: color(display-p3 1 0 0.331)) {   @supports (-webkit-background-clip: text){     .pink-text {       background-image: url("pink-P3.png");       background-size: cover;       -webkit-background-clip: text;       -webkit-text-fill-color: transparent;     }   } } 
 .pink-text {   color: rgb(255, 0, 79);   color: color(display-p3 1 0 0.331); }

There is a PostCSS plugin that converts lab() and lch() functions to rgb(). If you’re into Sass there is a tool from Miriam Suzanne called Blend.

A media query for color

@supports tells us whether the browser supports the relevant CSS syntax. What it doesn’t tell us  is whether a user’s monitor can actually display certain color values. If a monitor doesn’t support high-gamut color, the screen will display the nearest equivalent sRGB color. This means all monitors are catered for without writing any extra code.

However, if you’d rather choose the fallback color manually yourself rather than let the browser calculate one for you, you can pass a second color value to the color()  function. This would, however, require browser support for the color function (but support for the second argument hasn’t landed in any browser yet).

background-color: color(display-p3 1 0 0.331, #f54281);

Should you need greater control to do something fancy, the Media Queries Level 4 spec brings a new color-gamut media query that can help us here.

@media (color-gamut: p3) {    /* Code to run only on hardware that supports P3 color */ }

In this example, we are obviously checking for P3 support, but we could also check for the rec-2020 colorspace we alluded to earlier, which has an even wider gamut than P3. The number of screens supporting rec-2020 is currently minimal and only include high-definition televisions, meaning they won’t be a common target for developers in the near future. You can also check for sRGB support, but that is almost all monitors nowadays. The color-gamut query, on the other hand, has reasonably good browser support at the time of writing.

Sidenote: dynamic-range media query

In the Safari 13.1 release notes, the dynamic-range media query is is used to conditionally apply a P3 color.  Apparently, that’s not a good use case. According to Florian Rivoal (editor of the Media Queries specification), this query is designed to be used for video:

[S]ome screen can show ultra-bright lights for brief amounts of times, that are used in videos for things like sparks, direct sunlight, etc. This is much brighter than white, and isn’t meant to be used with static images. It would be uncomfortable, and would also damage the screen.

One more sidenote: Design tool support

Unfortunately popular web design tools like Figma, Sketch and XD do not currently support Lab, LCH or P3 colorspaces. Photoshop, however, does have a Lab color picker.

There we have it! CSS colors are expanding at a time when screens support more colors than ever. It’s an exciting time for color nerds out there!

The post The Expanding Gamut of Color on the Web appeared first on CSS-Tricks.


, ,

No-Comma Color Functions in CSS

There have been a couple of viral tweets about this lately, one from Adam Argyle and one from Mathias Bynes. This is a nice change that makes CSS a bit more clear. Before, every single color function actually needs two functions, one for transparency and one without, this eliminates that need and brings the syntax more-inline with CSS grammar overall.

Lemme make some code block from Mathias’ tweet here.

/* Old Syntax */ rgb(0, 128, 255)  rgba(0, 128, 255, 0.5)  hsl(198, 38% 50%)  hsla(198, 28%, 50%, 0.5)

/* New Syntax */ rgb(0 128 255)  rgb(0 128 255 / 50%)  hsl(198deg 28% 50%)  hsl(198deg 28% 50% / 50%)  lab(56.29% -10.93 16.58 / 50%)  lch(56.29% 19.86 236.62 / 50%)  color(sRGB 0 0.50 1 / 50%)

Thought party:

  • The browser support is pretty good: everything but IE 11.
  • If you need IE 11 support, you can preprocess it (or not use it). PostCSS’s preset-env does it as well as the very specific plugin postcss-color-rgb (weird it doesn’t do HSL also).
  • If you don’t like it, you literally never need to use it. No browser will ever pull support for such an important feature.
  • The reason to switch is muscle memory and consistent-looking codebases as new color functions (e.g, lab, lch, and color) will only support this new syntax.
  • There is a weird hybrid between old and new. You can pass an opacity value to rgb() and it still works like rgb(255, 0, 0, 0.5);.
  • If you need it in Sass (which is apparently a pain to support), there is a weird workaround. I would guess Sass will get around to supporting it. If they can’t, this is the kind of barb that drives people away from projects.
  • Prettier, which is in the business of cleaning up your code from the perspective of spacing and syntax, could intervene here and convert syntax, but it’s not going to (the Prettier stance is to not change the AST).
  • I imagine DevTools will start showing colors in this format, which will drive adoption.
  • Remember even hex code colors have a fancy new format.

The post No-Comma Color Functions in CSS appeared first on CSS-Tricks.


, ,

Creating Color Themes With Custom Properties, HSL, and a Little calc()

Before the advent of CSS custom properties (we might call them “variables” in this article as that’s the spirit of them), implementing multiple color schemes on the same website usually meant writing separate stylesheets. Definitely not the most maintainable thing in the world. Nowadays, though, we can define variables in a single stylesheet and let CSS do the magic.

Even if you aren’t offering something like user-generated or user-chosen color themes, you might still use the concept of theming on your website. For example, it is fairly common to use different colors themes across different areas of the site.

We’re going to build out an example like this:

Same layout, different colors.

In this example, all that changes between sections is the color hue; the variations in lightness are always the same. Here’s an example of a simplified color palette for a specific hue:

A palette of multiple hues might look something like this:

This would take effort to do with RGB color value, but in HSL only one value changes.

Enter custom properties

Custom properties have been around for a while and are widely supported. Polyfills and other solutions for IE 11 are also available.

The syntax is very similar to traditional CSS. Here is an overview of the basic usage:

It’s common to see variables defined on the :root pseudo-element, which is always <html> in HTML, but with higher specificity. That said, variables can be defined on any element which is useful for scoping specific variables to specific elements. For example, here are variables defined on data attributes:

Adding calc() to the mix

Variables don’t have to be fixed values. We can leverage the power of the calc() function to automatically calculate values for us while adhering to a uniform pattern:

Since CSS doesn’t support loops, a preprocessor would be handy to generate a part of the code. But remember: CSS variables are not the same as Sass variables.

Implementing CSS variables

What we’re basically trying to do is change the color of the same component on different sections of the same page. Like this:

We have three sections in tabs with their own IDs: #food, #lifestyle, and #travel. Each section corresponds to a different hue. The  data-theme-attribute on the div.wrapper element defines which hue is currently in use.

When #travel is the active tab, we’re using the --first-hue variable, which has a value of 180°. That is what gets used as the --hue value on the section, resulting in a teal color:

<div class="wrapper" data-theme="travel">
.wrapper[data-theme="travel"] {   --hue: var(--first-hue);  /* = 180° = teal */ }

Clicking any of the tabs updates the data-theme attribute to the ID of the section, while removing the hash (#) from it. This takes a smidge of JavaScript. That’s one of the (many) nice things about CSS: they can be accessed and manipulated with JavaScript. This is a far cry from preprocessor variables, which compile into values at the build stage and are no longer accessible in the DOM.

<li><a href="#food">Food</a></li>
const wrapper = document.querySelector('.wrapper'); document.querySelector("nav").addEventListener('click', e => {   e.preventDefault();   e.stopPropagation();   // Get theme name from URL and ditch the hash   wrapper.dataset.theme = e.target.getAttribute('href').substr(1); })

Progressive enhancement

When we use JavaScript, we should be mindful of scenarios where a user may have disabled it. Otherwise, our scripts — and our UI by extension — are inaccessible. This snippet ensures that the site content is still accessible, even in those situations:

document.querySelectorAll('section').forEach((section, i) => {   if (i) { // hide all but the first section     section.style.display = 'none';   } })

This merely allows the tabs to scroll up the page to the corresponding section. Sure, theming is gone, but providing content is much more important.

While I chose to go with a single-page approach, it’s also possible to serve the sections as separate pages and set [data-theme] on the server side. 

Another approach

So far, we’ve assumed that color values change linearly and are thus subject to a mathematical approach. But even in situations where this is only partially true, we may still be able to benefit from the same concept. For instance, if lightness follows a pattern but hue doesn’t, we could split up the stylesheet like this:

<head>   <style>     :root {       --hue: 260;     }   </style>   <link rel="stylesheet" href="stylesheet-with-calculations-based-on-any-hue.css"> </head>

Supporting web components

Web components are an exciting (and evolving) concept. It’s enticing to think we can have encapsulated components that can be reused anywhere and theme them on a case-by-case basis. One component with many contexts!

We can use CSS variable theming with web components. It requires us to use a host-context() pseudo-selector. (Thanks to habemuscode for pointing this out to me!)

:host-context(body[data-theme="color-1"]) {   --shade-1: var(--outsideHSL); }

In summary…

Theming a website with CSS custom properties is much easier than the workaround approaches we’ve resorted to in the past. It’s more maintainable (one stylesheet), performant (less code), and opens up new possibilities (using JavaScript). Not to mention, CSS custom properties become even more powerful when they’re used with HSL colors and the calc() function.

We just looked at one example where we can change the color theme of a component based on the section where it is used. But again, there is much more opportunity here when we start to get into things like letting users change themes themselves – a topic that Chris explores in this article.

The post Creating Color Themes With Custom Properties, HSL, and a Little calc() appeared first on CSS-Tricks.


, , , , , ,

Wide Gamut Color in CSS with Display-P3

Here’s something I’d never heard of before: Display-P3 support in CSS Color Module Level 4 spec. This is a new color profile supported by certain displays and it introduces a much wider range of colors that we can choose from.

Right now the syntax looks something like this in CSS:

header {   color: rgb(0, 255, 0); /* fallback color */   color: color(display-p3 0 1 0); }

It looks weird, huh? Over on the WebKit blog, Nikita Vasilyev shows how we can see these new colors in Safari’s DevTools:

Back in 2016, Dean Jackson wrote about improving color on the web and why Apple is interested in this much wider color gamut. The general idea is that more accurate colors make for a better and more vibrant user experience.

Also, it looks like all this is only available in Safari right now.

Direct Link to ArticlePermalink

The post Wide Gamut Color in CSS with Display-P3 appeared first on CSS-Tricks.


, , ,

Programming Sass to Create Accessible Color Combinations

We’re all looking for low-hanging fruit to make our sites and apps more accessible. One of the easier things we can do is make sure the colors we use are easy on the eyes. High color contrast is something that benefits everyone. It not only reduces eye strain in general, but is crucial for folks who deal with reduced vision.

So let’s not only use better color combinations in our designs but find a way to make it easier for us to implement high contrasts. There’s one specific strategy we use over at Oomph that lets a Sass function do all the heavy lifting for us. I’ll walk you through how we put that together.

Want to jump right to the code because you already understand everything there is to know about color accessibility? Here you go.

What we mean by “accessible color combinations”

Color contrast is also one of those things we may think we have handled. But there’s more to high color contrasts than eyeballing a design. There are different levels of acceptable criteria that the WCAG has defined as being accessible. It’s actually humbling to crack open the WebAIM Contrast Checker and run a site’s color combinations through it.

My team adheres to WCAG’s Level AA guidelines by default. This means that: 

  • Text that is 24px and larger, or 19px and larger if bold, should have a Color Contrast Ratio (CCR) of 3.0:1.
  • Text that is smaller than 24px should have a CCR of 4.5:1.

If a site needs to adhere to the enhanced guidelines for Level AAA, the requirements are a little higher:

  • Text that is 24px and larger, or 19px and larger if bold, should have a CCR of 4.5:1.
  • Text that is smaller than 24px should have a CCR of 7:1.

Ratios? Huh? Yeah, there’s some math involved here. But the good news is that we don’t need to do it ourselves or even have the same thorough understanding about how they’re calculated the way Stacie Arellano recently shared (which is a must read if you’re into the science of color accessibility).

That’s where Sass comes in. We can leverage it to run difficult mathematical computations that would otherwise fly over many of our heads. But first, I think it’s worth dealing with accessible colors at the design level.

Accessible color palettes start with the designs

That’s correct. The core of the work of creating an accessible color palette starts with the designs. Ideally, any web design ought to consult a tool to verify that any color combinations in use pass the established guidelines — and then tweak the colors that don’t. When our design team does this, they use a tool that we developed internally. It works on a list of colors, testing them over a dark and a light color, as well as providing a way to test other combinations. 

ColorCube provides an overview of an entire color palette, showing how each color performs when paired with white, black, and even each other. It even displays results for WCAG Levels AA and AAA next to each result. The tool was designed to throw a lot of information at the user all at once when evaluating a list of colors.

This is the first thing our team does. I’d venture to guess that many brand colors aren’t chosen with accessibility at the forefront. I often find that those colors need to change when they get translated to a web design. Through education, conversation, and visual samples, we get the client to sign off on the new color palette. I’ll admit: that part can be harder than the actual work of implementing accessible colors combinations.

The Color Contrast Audit: A typical design delivery when working with an existing brand’s color palette. Here, we suggest to stop using the brand color Emerald with white, but use an “Alt” version that is slightly darker instead. 

The problem that I wanted to solve with automation are the edge cases. You can’t fault a designer for missing some instance where two colors combine in an unintended way — it just happens. And those edge cases will come up, whether it is during the build or even a year later when new colors are added to the system.

Developing for accessibility while keeping true to the intent of a color system

The trick when changing colors to meet accessibility requirements is not changing them so much that they don’t look like the same color anymore. A brand that loves its emerald green color is going to want to maintain the intent of that color — it’s “emerald-ness.” To make it pass for accessibility when it is used as text over a white background, we might have to darken the green and increase its saturation. But we still want the color to “read” the same as the original color.

To achieve this, we use the Hue Saturation Lightness (HSL) color model. HSL gives us the ability to keep the hue as it is but adjust the saturation (i.e. increase or decrease color) and lightness (i.e. add more black or more white). The hue is what makes a green that green, or a blue that blue. It is the “soul” of the color, to get a little mystical about it. 

Hue is represented as a color wheel with a value between 0° and 360° — yellow at 60°, green at 120°, cyan at 180°, etc. Saturation is a percentage ranging from 0% (no saturation) to 100% (full saturation). Lightness is also a value that goes from 0% to 100%, where no lightness is at 0%, no black and no white is at 50%, and 100% is all lightness, or very light.

A quick visual of what tweaking a color looks like in our tool:

With HSL, changing the low-contrast green to a higher contrast meant changing the saturation from 63 to 95 and the lightness from 45 to 26 on the left. That’s when the color gets a green check mark in the middle when used with white. The new green still feels like it is in the same family, though, because the Hue remained at 136, which is like the color’s “soul.”

To learn more, play around with the fun HSL visualizer mothereffinghsl.com. But for a more in-depth description of color blindness, WCAG color contrast levels, and the HSL color space, we wrote an in-depth blog post about it.

The use case I want to solve

Designers can adjust colors with the tools that we just reviewed, but so far, no Sass that I have found could do it with mathematical magic. There had to be a way. 

These are some similar approaches I have seen in the wild:

  • An idea by Josh Bader uses CSS variables and colors split into their RGB values to calculate whether white or black is the best accessible color to use in a given situation.
  • Another idea by Facundo Corradini does something similar with HSL values and a very cool “switch function” in CSS.

I didn’t like these approaches. I didn’t want to fallback to white or black. I wanted colors to be maintained but adjusted to be accessible. Additionally, changing colors to their RGB or HSL components and storing them with CSS variables seemed messy and unsustainable for a large codebase.

I wanted to use a preprocessor like Sass to do this: given two colors, automagically adjust one of them so the pair receives a passing WCAG grade. The rules state a few other things to consider as well — size of the text and whether or not the font is bold. The solution had to take this into account. 

In code terms, I wanted to do this:

// Transform this non-passing color pair: .example {   background-color: #444;   color: #0094c2; // a 2.79 contrast ratio when AA requires 4.5   font-size: 1.25rem;   font-weight: normal; } 
 // To this passing color pair: .example {   background-color: #444;   color: #00c0fc; // a 4.61 contrast ratio   font-size: 1.25rem;   font-weight: normal; }

A solution that does this would be able to catch and handle those edge cases we mentioned earlier. Maybe the designer accounted for a brand blue to be used over a light blue, but not a light gray. Maybe the red used in error messages needs to be tweaked for this one form that has a one-off background color. Maybe we want to implement a dark mode feature to the UI without having to retest all the colors again. These are the use cases I had in mind going into this. 

With formulas can come automation

The W3C has provided the community with formulas that help analyze two colors used together. The formula multiplies the RGB channels of both colors by magic numbers (a visual weight based on how humans perceive these color channels) and then divides them to come up with a ratio from 0.0 (no contrast) to 21.0 (all the contrast, only possible with white and black). While imperfect, this is the formula we use right now:

If L1 is the relative luminance of a first color  And L2 is the relative luminance of a second color, then - Color Contrast Ratio = (L1 + 0.05) / (L2 + 0.05) Where - L = 0.2126 * R + 0.7152 * G + 0.0722 * B And - if R sRGB <= 0.03928 then R = R sRGB /12.92 else R = ((R sRGB +0.055)/1.055) ^ 2.4 - if G sRGB <= 0.03928 then G = G sRGB /12.92 else G = ((G sRGB +0.055)/1.055) ^ 2.4 - if B sRGB <= 0.03928 then B = B sRGB /12.92 else B = ((B sRGB +0.055)/1.055) ^ 2.4 And - R sRGB = R 8bit /255 - G sRGB = G 8bit /255 - B sRGB = B 8bit /255

While the formula looks complex, it’s just math right? Well, not so fast. There is a part at the end of a few lines where the value is multiplied by a decimal power — raised to the power of 2.4. Notice that? Turns out that it’s complex math which most programming languages can accomplish — think Javascript’s math.pow() function — but Sass is not powerful enough to do it. 

There’s got to be another way…

Of course there is. It just took some time to find it. 🙂

My first version used a complex series of math calculations that did the work of decimal powers within the limited confines of what Sass can accomplish. Lots of Googling found folks much smarter than me supplying the functions. Unfortunately, calculating only a handful of color contrast combinations increased Sass build times exponentially. So, that means Sass can do it, but that does not mean it should. In production, build times for a large codebase could increase to several minutes. That’s not acceptable. 

After more Googling, I came across a post from someone who was trying to do a similar thing. They also ran into the lack of exponent support in Sass. They wanted to explore “the possibility of using Newtonian approximation for the fractional parts of the exponent.” I totally understand the impulse (not). Instead, they decided to use a “lookup table.” It’s a genius solution. Rather than doing the math from scratch every time, a lookup table provides all the possible answers pre-calculated. The Sass function retrieves the answer from the list and it’s done.

In their words:

The only part [of the Sass that] involves exponentiation is the per-channel color space conversions done as part of the luminance calculation. [T]here are only 256 possible values for each channel. This means that we can easily create a lookup table.

Now we’re cooking. I had found a more performant direction. 

Usage example

Using the function should be easy and flexible. Given a set of two colors, adjust the first color so it passes the correct contrast value for the given WCAG level when used with the second color. Optional parameters will also take the font size or boldness into account.

// @function a11y-color( //   $ color-to-adjust, //   $ color-that-will-stay-the-same, //   $ wcag-level: 'AA', //   $ font-size: 16, //   $ bold: false // ); 
 // Sass sample usage declaring only what is required .example {   background-color: #444;   color: a11y-color(#0094c2, #444); // a 2.79 contrast ratio when AA requires 4.5 for small text that is not bold } 
 // Compiled CSS results: .example {   background-color: #444;   color: #00c0fc; // which is a 4.61 contrast ratio }

I used a function instead of a mixin because I preferred the output of a single value independent from a CSS rule. With a function, the author can determine which color should change. 

An example with more parameters in place looks like this:

// Sass .example-2 {   background-color: a11y-color(#0094c2, #f0f0f0, 'AAA', 1.25rem, true); // a 3.06 contrast ratio when AAA requires 4.5 for text 19px or larger that is also bold   color: #f0f0f0;   font-size: 1.25rem;   font-weight: bold; } 
 // Compiled CSS results: .example-2 {   background-color: #087597; // a 4.6 contrast ratio   color: #f0f0f0;   font-size: 1.25rem;   font-weight: bold; }

A deeper dive into the heart of the Sass function

To explain the approach, let’s walk through what the final function is doing, line by line. There are lots of helper functions along the way, but the comments and logic in the core function explain the approach:

// Expected: // $ fg as a color that will change // $ bg as a color that will be static and not change // Optional: // $ level, default 'AA'. 'AAA' also accepted // $ size, default 16. PX expected, EM and REM allowed // $ bold, boolean, default false. Whether or not the font is currently bold // @function a11y-color($ fg, $ bg, $ level: 'AA', $ size: 16, $ bold: false) {   // Helper: make sure the font size value is acceptable   $ font-size: validate-font-size($ size);   // Helper: With the level, font size, and bold boolean, return the proper target ratio. 3.0, 4.5, or 7.0 results expected   $ ratio: get-ratio($ level, $ font-size, $ bold);   // Calculate the first contrast ratio of the given pair   $ original-contrast: color-contrast($ fg, $ bg);      @if $ original-contrast >= $ ratio {     // If we pass the ratio already, return the original color     @return $ fg;   } @else {     // Doesn't pass. Time to get to work     // Should the color be lightened or darkened?     // Helper: Single color input, 'light' or 'dark' as output     $ fg-lod: light-or-dark($ fg);     $ bg-lod: light-or-dark($ bg); 
     // Set a "step" value to lighten or darken a color     // Note: Higher percentage steps means faster compile time, but we might overstep the required threshold too far with something higher than 5%     $ step: 2%;          // Run through some cases where we want to darken, or use a negative step value     @if $ fg-lod == 'light' and $ bg-lod == 'light' {       // Both are light colors, darken the fg (make the step value negative)       $ step: - $ step;     } @else if $ fg-lod == 'dark' and $ bg-lod == 'light' {       // bg is light, fg is dark but does not pass, darken more       $ step: - $ step;     }     // Keeping the rest of the logic here, but our default values do not change, so this logic is not needed     //@else if $ fg-lod == 'light' and $ bg-lod == 'dark' {     //  // bg is dark, fg is light but does not pass, lighten further     //  $ step: $ step;     //} @else if $ fg-lod == 'dark' and $ bg-lod == 'dark' {     //  // Both are dark, so lighten the fg     //  $ step: $ step;     //}          // The magic happens here     // Loop through with a @while statement until the color combination passes our required ratio. Scale the color by our step value until the expression is false     // This might loop 100 times or more depending on the colors     @while color-contrast($ fg, $ bg) < $ ratio {       // Moving the lightness is most effective, but also moving the saturation by a little bit is nice and helps maintain the "power" of the color       $ fg: scale-color($ fg, $ lightness: $ step, $ saturation: $ step/2);     }     @return $ fg;   } }

The final Sass file

Here’s the entire set of functions! Open this in CodePen to edit the color variables at the top of the file and see the adjustments that the Sass makes:

All helper functions are there as well as the 256-line lookup table. Lots of comments should help folks understand what is going on. 

When an edge case has been encountered, a version in SassMeister with debug output was helpful while I was developing it to see what might be happening. (I changed the main function to a mixin so I can debug the output.) Feel free to poke around at this as well.

Play with this gist on SassMeister.

And finally, the functions have been stripped out of CodePen and put into a GitHub repo. Drop issues into the queue if you run into problems. 

Cool code! But can I use this in production?


I’d like to say yes, but I’ve been iterating on this thorny problem for a while now. I feel confident in this code but would love more input. Use it on a small project and kick the tires. Let me know how the build time performs. Let me know if you come across edge cases where passing color values are not being supplied. Submit issues to the GutHub repo. Suggest improvements based on other code you’ve seen in the wild. 

I’d love to say that I have Automated All the A11y Things, but I also know it needs to be road-tested before it can be called Production Ready™. I’m excited to introduce it to the world. Thanks for reading and I hope to hear how you are using it real soon.

The post Programming Sass to Create Accessible Color Combinations appeared first on CSS-Tricks.


, , , , ,

4 Ways to Animate the Color of a Text Link on Hover

Let’s create a pure CSS effect that changes the color of a text link on hover… but slide that new color in instead of simply swapping colors.

There are four different techniques we can use to do this. Let’s look at those while being mindful of important things, like accessibility, performance, and browser support in mind.

Let’s get started!

Technique 1: Using background-clip: text

At the time of writing, the background-clip: text property is an experimental feature and is not supported in Internet Explorer 11 and below.

This technique involves creating knockout text with a hard stop gradient. The markup consists of a single HTML link (<a>) element to create a hyperlink:

<a href="#">Link Hover</a>

We can start adding styles to the hyperlink. Using overflow: hidden will clip any content outside of the hyperlink during the hover transition:

a {   position: relative;   display: inline-block;   font-size: 2em;   font-weight: 800;   color: royalblue;   overflow: hidden; }

We will need to use a linear gradient with a hard stop at 50% to the starting color we want the link to be as well as the color that it will change to:

a {   /* Same as before */   background: linear-gradient(to right, midnightblue, midnightblue 50%, royalblue 50%); }

Let’s use background-clip to clip the gradient and the text value to display the text. We will also use the background-size and background-position properties to have the starting color appear:

a {   /* Same as before */   background-clip: text;   -webkit-background-clip: text;   -webkit-text-fill-color: transparent;   background-size: 200% 100%;   background-position: 100%; }

Finally, let’s add the transition CSS property and :hover CSS pseudo-class to the hyperlink. To have the link fill from left to right on hover, use the background-position property:

a {   /* Same as before */   transition: background-position 275ms ease; } a:hover {   background-position: 0 100%; }

While this technique does achieve the hover effect, Safari and Chrome will clip text decorations and shadows, meaning they won’t be displayed. Applying text styles, such as an underline, with the text-decoration CSS property will not work. Perhaps consider using other approaches when creating underlines.

Technique 2: Using width/height

This works by using a data attribute containing the same text as the one in the <a> tag and setting the width (filling the text from left-to-right or right-to-left) or height (filling the text from top-to-bottom or bottom-to-top), from 0% to 100% on hover.

Here is the markup:

<a href="#" data-content="Link Hover">Link Hover</a>

The CSS is similar to the previous technique minus the background CSS properties. The text-decoration property will work here:

a {   position: relative;   display: inline-block;   font-size: 2em;   color: royalblue;   font-weight: 800;   text-decoration: underline;   overflow: hidden; }

This is when we need to use the content from the data-content attribute. It will be positioned above the content in the <a> tag. We get to use the nice little trick of copying the text in the data attribute and displaying it via the attr() function on the content property of the element’s ::before pseudo-element.

a::before {   position: absolute;   content: attr(data-content); /* Prints the value of the attribute */   top: 0;   left: 0;   color: midnightblue;   text-decoration: underline;   overflow: hidden;   transition: width 275ms ease; }

To keep the text from wrapping to the next line, white-space: nowrap will be applied. To change the link fill color, set the value for the color CSS property using the ::before pseudo-element and having the width start at 0:

a::before {   /* Same as before */   width: 0;   white-space: nowrap; }

Increase the width to 100% to the ::before pseudo element to complete the text effect on hover:

a:hover::before {   width: 100%; }

While this technique does the trick, using the width or height properties will not produce a performant CSS transition. It is best to use either the transform or opacity properties to achieve a smooth, 60fps transition.

Using the text-decoration CSS property can allow for different underline styles to appear in the CSS transition. I created a demo showcasing this using the next technique: the clip-path CSS property.

Technique 3: Using clip-path

For this technique, we will be using the clip-path CSS property with a polygon shape. The polygon will have four vertices, with two of them expanding to the right on hover:

The markup is the same as the previous technique. We will use a ::before pseudo-element again, but the CSS is different:

a::before {   position: absolute;   content: attr(data-content);   color: midnightblue;   text-decoration: underline;   clip-path: polygon(0 0, 0 0, 0% 100%, 0 100%);   transition: clip-path 275ms ease; }

Unlike the previous techniques, text-decoration: underline must be declared to the ::before pseudo-element for the color to fill the underline on hover.

Now let’s look into the CSS for the clip-path technique:

clip-path: polygon(0 0, 0 0, 0% 100%, 0 100%);

The polygon’s vertices of the clip-path property are set in percentages to define coordinates by the order written:

  • 0 0 = top left
  • 0 0 = top right
  • 100% 0 = bottom right
  • 0 100% = bottom left

The direction of the fill effect can be changed by modifying the coordinates. Now that we have an idea for the coordinates, we can make the polygon expand to the right on hover:

a:hover::before {   clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%); }

This technique works pretty well, but note that support for the clip-path property varies between browsers. Creating a CSS transition with clip-path is a better alternative than using the width/height technique; however, it does affect the browser paint.

Technique 4: Using transform

The markup for this technique uses a masking method with a <span> element. Since we will be using duplicated content in a separate element, we will use aria-hidden="true" to improve accessibility — that will hide it from screen readers so the content isn’t read twice:

<a href="#"><span data-content="Link Hover" aria-hidden="true"></span>Link Hover</a>

The CSS for the <span> element contains a transition that will be starting from the left:

span {   position: absolute;   top: 0;   left: 0;   overflow: hidden;   transform: translateX(-100%);   transition: transform 275ms ease; }

Next, we need to get the <span> to slide the right like this:

To do this, we will use the translateX() CSS function and set it to 0:

a:hover span {   transform: translateX(0); }

Then, we will use the ::before pseudo-element for the <span>, again using the data-content attribute we did before. We’ll set the position by translating it 100% along the x-axis.

span::before {    display: inline-block;   content: attr(data-content);   color: midnightblue;   transform: translateX(100%);   transition: transform 275ms ease;   text-decoration: underline; }

Much like the <span> element, the position of the ::before pseudo-element will also be set to  translateX(0):

a:hover span::before {   transform: translateX(0); }

While this technique is the the most cross-browser compatible of the bunch, it requires more markup and CSS to get there. That said, using the transform CSS property is great for performance as it does not trigger repaints and thus produces smooth, 60fps CSS transitions.

There we have it!

We just looked at four different techniques to achieve the same effect. Although each has its pros and cons, you can see that it’s totally possible to slide in a color change on text. It’s a neat little effect that makes links feel a little more interactive.

The post 4 Ways to Animate the Color of a Text Link on Hover appeared first on CSS-Tricks.


, , , , ,

Understanding Web Accessibility Color Contrast Guidelines and Ratios

What should you do when you get a complaint about the color contrast in your web design? It might seem perfectly fine to you because you’re able to read content throughout the site, but to someone else, it might be a totally different experience. How can put yourself in that person’s shoes to improve their experience?

There are some relatively easy ways to test contrast. For example, you can check the site on your phone or tablet in bright sunlight, or add a CSS filter to mimic a grayscale view). But… you don’t have to trust your eyes. Not everyone has your exact eyes anyway, so your subjective opinion can possibly be a faulty measurement. 

You can mathematically know if two colors have enough contrast between them. 

The W3C has a document called Web Content Accessibility Guidelines (WCAG) 2.1 that covers  successful contrast guidelines. Before we get to the math, we need to know what contrast ratio scores we are aiming to meet or exceed. To get a passing grade (AA), the contrast ratio is 4.5:1 for most body text and 3:1 for larger text. 

How did the W3C arrive at these ratios?

The guidelines were created for anyone using a standard browser, with no additional assistive technology. The contrast ratios that the WCAG suggests were based initially on earlier contrast standards and adjusted to accommodate newer display technologies, like antialiased text, so content would be readable by people with a variety of visual or cognitive difficulties, whether it be due to age, sickness, or other losses of visual acuity.  

We’re basically aiming to make text readable for someone with 20/40 vision, which is equivilent to the vision of someone 80 years old. Visual acuity of 20/40 means you can only read something at 20 feet away that someone with perfect 20/20 vision could read if it was 40 feet away.

So, say your design calls for antialiased text because it looks much smoother on a screen. It actually sacrifices a bit of contrast and ding your ratio. The WCAG goes into more detail on how scoring works.

There are other standards that take contrast in consideration, and the WCAG used some of these considerations to develop their scoring. One is called the Human Factors Engineering of Computer Workstations (ANSI/HFES 100-2007) was published in 2007 and designated as an American standard for ergonomics. It combined and replaced two earlier standards that were created by separate committees. The goal of the combined standard was to accommodate 90% of computer users, and cover many aspects of computer use and ergonomics, including visual displays and contrast. So, that means we have physical screens to consider in our designs.

What does the ratio mean?

The contrast ratio explains the difference between the lightest color brightness and the darkest color brightness in a given range. It’s the relative luminance of each color.

Let’s start with an egregious example of a teal color text on a light gray background. 

<h1>Title of Your Awesome Site</h1>
h1 {   background-color: #1ABC9C;   color: #888888; }

It’s worth calling out that some tools, like WordPress, provide a helpful warning for this when there’s a poorly contrasted text and background combination. In the case of WordPress, a you get notice in the sidebar.

“This color combination may be hard for people to read. Try using a brighter background color and/or a darker text color.”

“OK,” you say. “Perhaps you think that teal on gray color combination is not exactly great, but I can still make out what the content says.“ (I’m glad one of us can because it’s pretty much a muddy gray mess to me.)

The contrast ratio for that fine piece of hypertext is 1.47:1.

I wanted a better understanding of what the contrast scores were actually checking and came to find that it requires the use of mathematics… with a side of understanding the differences between human and computer vision.  This journey taught me about the history of computer vision and a bit about biology, and gave me a small review of some math concepts I haven’t touched since college.

Here’s the equation:

(L1 + 0.05) / (L2 + 0.05)
  • L1 is the relative luminance of the lighter of the colors.
  • L2 is the relative luminance of the darker of the colors.

This seems simple, right? But first we need to determine the relative luminance for each color to get those variables.

OK, back to relative luminance

We mentioned it in passing, but it’s worth going deeper into relative luminance, or the relative brightness of any color expressed into a spectrum between 0 (black) and 1 (white).

To determine the relative luminance for each color, we first need to get the RGB notation for a color. Sometimes we’re working with HEX color values and need to covert that over to RGB. There are online calculators that will do this for us, but there’s solid math happening in the background that makes it happen. Our teal hex color, #1ABC9C, becomes an RGB of 26, 188, 156.

Next, we take each value of the RGB color and divide each one by 255 (the max integer of RGB values) to get a linear value between 0 and 1. 

So now with our teal color it looks like this:

Component Equation Value
Red 26/255 0.10196078
Green 188/255 0.73725490
Blue 156/255 0.61176471

Then we apply gamma correction, which defines the relationship between a pixel’s numerical value and its actual luminance, to each component part of the RGB color. If the linear value of a component is less than .03938, we divide it by 12.92. Otherwise, we add .055 and divide the total by 1.055 and take the result to the power of 2.4.

Our gamma corrected color components from our teal color end up like this:

Component Equation Value
Red ((0.10196078 +.055)/1.055) ^ 2.4 0.01032982
Green ((0.73725490 +.055)/1.055) ^ 2.4 0.50288646
Blue ((0.61176471 +.055)/1.055) ^ 2.4 0.33245154

This part of our equation comes from the formula for determining relative luminance.

We just sort of sped past gamma correction there without talking much about it and what it does. In short, it translates what a computer “sees” into the human perception of brightness. Computers record light directly where twice the photons equals twice the brightness. Human eyes perceive more levels of light in dim conditions and fewer in bright conditions. The digital devices around us make gamma encoding and decoding calculations all the time. It’s used to show us things on the screens that match up to our perception of how things appear to our eyes.

Finally, we multiply the different colors by numbers that signify how bright that color appears to the human eye. That means we determine the luminance of each color by multiplying the red component value by .2126, the green component value by .7152, and the blue component by .0722 before adding all three of those results together. You’ll note that green gets the highest value here,

So, one last time for teal:

Component Equation Value
Red 0.01032982  X 0.2126 0.00219611973
Green 0.50288646  X 0.7152 0.35966439619
Blue 0.33245154  X 0.0722 0.02400300118

…and add them together for luminance!

L1 = 0.00219611973 + 0.35966439619 + 0.02400300118 = 0.38586352

If we do the same to get our L2 value, that gives us 0.24620133.

We finally have the L1 and L2 values we need to calculate contrast. To determine which value is  L1 and and which is L2 , we need to make sure that the larger number (which shows the lighter color) is always L1 and is divided by the smaller/darker color as L2.

Now compare that result with the WCAG success criterias. For standard text size, between 18-22 points, a minimul result of 4.5 will pass with a grade of AA. If our text is larger, then a slightly lower score of  3 will do the job. But to get the highest WCAG grade (AAA), we have to have a contrast ratio result of at least 7. Our lovely combination fails all tests, coming far under 4.5 for regular text or 3 for headline style text. Time to choose some better colors!

I’m so glad we have computers and online tools to do this work for us! Trying to work out the details step-by-step on paper gave me a couple weeks of frustration. It was a lot of me getting things wrong when comparing results to those of automated contrast checkers.

Remember how teachers in school always wanted you to show your math work to prove how you got to the answer? I made something to help us out.

If you view this demo with the console open, you’ll see the math that goes into each step of the calculations. Go ahead, try our two example colors, like #1ABC9C and #888888.

I just want my page to have proper contrast, what do I do?!

There are a variety of accessibility resources that you can can audit your site. Here’s a list I put together, and there’s another list here on CSS-Tricks.

But here are a few tips to get you started.

First, identify areas that are not serving your accessibility needs.

The WAVE accessibility tool is a good place to start. Run your site through that and it will give you contrast results and help identify trouble areas.

Yay, passing scores!

Follow the suggestions of the audit

Use best practices to improve your scores, and remove the errors. Once you identify contrast errors, you can try out some different options right there in the WAVE tool. Click on the color box to pop open a color picker. Then play around until the errors go away, and you’ll know what you can replace in your code.

Run the test again

This way, you can make sure your changes improved things. Congratulations! You just made your product better for all users, not just ones affected by the accessibility errors!

What comes next is up to you!

You can make it easier on yourself and start all new products with the goal of making them accessible. Make accessibility guidelines part of your requirements for both technology and design. You’ll save yourself potentially hundreds of hours of remediation, and potential legal complaints. U.S. government and education websites are required to comply, but other industries are often taken to task for not making their sites equally available for all people.

If you have the option, consider using established and tested frameworks and web libraries (like Bootstrap or Google’s Material Design) that have already figured out optimum contrast theme colors. In many cases, you can take just what you need (like only the CSS) or at least review their color palettes to inform choices. You should still check the contrast though because, while most standard text options in a framework may follow contrast ratio WCAG suggestions, things like alert and message styles may not. (I’m looking at you, Bootstrap!)

Derek Kay has reviewed a list of web frameworks with a focus on accessibility, which I suggest you read if you are looking for more options. The U.S. Web Design System shows one way to solve color/contrast puzzles using their CSS token system that labels colors to make contrast differences super clear), but they also link to several very good resources for improving and understanding contrast.

We took a deeper dive here than perhaps you ever really need to know, but understanding what a contrast ratio is and what it actually means should help you remember to keep contrast in mind when designing future sites, web apps, and other software.

Having a clearer understanding of what the contrast ratio means helps me to remember who poor contrast can affect, and how to improve web and mobile products overall.

I’m not the ultimate subject expert on contrast, just a very, very curious girl who sometimes has issues reading things on the web with low contrast.

If you have any additional thoughts, corrections or further research to share, please leave a comment and I’ll amend this article! The fuller our understanding of the needs and requirements of our sites is, the better we can plan improvements and ultimately serve the needs of our audiences.

The post Understanding Web Accessibility Color Contrast Guidelines and Ratios appeared first on CSS-Tricks.


, , , , ,

The Best Color Functions in CSS?

I’ve said before that HSL is the best color format we have. Most of us aren’t like David DeSandro, who can read hex codes. HSL(a) is Hue, Saturation, Lightness, and alpha, if we need it.

hsl(120, 100%, 40%)

Hue isn’t intuitive, but it’s not that weird. You take a trip around the color wheel from 0 to 360. Saturation is more obvious where 0% has all the color sucked out, like grayscale, and 100% is fully rich color at that hue. Lightness is “normal” at 50% and adds white or black as you go toward 100% and 0%, respectively. I’m sure that’s not the correct scientific or technical way of explaining it, but that’s the brain logic.

There are still issues with using HSL, which Brian Kardell explains in depth. I’m far from a color expert, but I think I see what Brian (and Adam) are saying in that article. Say you have three different colors and they all have the exact same lightness in HSL. That doesn’t mean they are all actually the same lightness. That’s kinda weird, particularly when you’re using this color format as part of a system of colors.

The good news is that there are color features already specced as a CSS Level 4 module that help with this: Lab and LCH. Check out the example from Adam where the colors in Lab have values that reflect their actual lightness much more accurately to how we perceive it.


There are color spaces like Lab and LCH which deal with the full spectrum and have qualities like perceptual uniformness. Thus, if we want great color functions for use in real design systems everyone seems to agree that having support to do said math in the Lab/LCH color spaces is the ideal enabling feature.

In the bug ticket for Chrome, Tab thinks these would be almost trivial to implement.

Note that lab()/lch()/gray() can all be eagerly converted into our existing color infrastructure; they don’t introduce any fundamentally new concepts, they’re just a better way to specify colors, more closely associated with how our eyes actually function rather than being closely tied to how rgb pixels function.

The conversion functions to turn it into rgb are a little bit of code, but it’s just some exponentials and a bit of matrix multiplication, and it’s well-documented in the spec.

This should be a GoodFirstBug sort of thing, I think.

The post The Best Color Functions in CSS? appeared first on CSS-Tricks.


, ,

So Many Color Links

There’s been a run of tools, articles, and resources about color lately. Please allow me to close a few tabs by rounding them up here for your enjoyment.

Curated colors in context

Happy Hues demonstrates a bunch of color palettes in the context of the site itself. That’s a nice way to do it, because choosing nice colors isn’t enough — it’s all about context. It can go bad, as the Refactoring UI blog demonstrates.

Dynamic, Date-Based Color with JavaScript, HSL, and CSS Variables

Rob Weychert shows off how he created date-based color schemes (so that every single day of the past 30 years would have a unique color scheme, each day looking slightly different than the day before).

Calculating Color: Dynamic Color Theming with Pure CSS.

Una Kravets creates color themes just with CSS. No JavaScript. No CSS preprocessing. Just Custom Properties, HSL colors, and some calc() in Calculating Color: Dynamic Color Theming with Pure CSS.

Color Tools

We’ve tweeted about color tools a lot. We’ve even threaded them up from time-to-time.

Visualizing Every Pantone Color of the Year

Adam Fuhrer took 20 years of top Pantone colors and matched them with wonderful photos. I love that the photos link to the personal sites of the actual photographers. It weirdly reminds me that you can browse Dribbble by color.

A Handy Sass-Powered Tool for Making Balanced Color Palettes

Stephanie Eckles blogged about using Sass to do math on colors to calculate and graph their luminance, saturation, and lightness, which can give you a by-the-numbers look to see if your color scheme is cohesive or not.


Leonardo is an interactive color palette tool that helps interpolate colors and generate variations based on contrast ratio.

Color Puns


The post So Many Color Links appeared first on CSS-Tricks.


, ,