BAD BOY

Cet article est également disponible en français

In previous articles I’ve created various graphical effects with CSS blend modes, but potentially one of the most useful applications for blends is within text on web pages.

Contrast is a basic accessibility concern often overlooked by designers in love with subtlety, shading, and thin sans-serif fonts. But contrast becomes an inescapable issue when text crosses into an area similar in color to itself:

body {
	text-align: center;
	font-family: Montserrat, sans-serif;
	color: #000;
	background-image: linear-gradient(90deg,#fff 49.9%,#000 50%);
}
h1 {
	font-size: 10vw;
}

You can see the result in Figure 1.

Figure 1: Text made illegible by a background

Without any treatment, the second word is completely unreadable. In traditional web design, there just two equally discouraging ways of dealing with this:

  1. Turn the text into an ;
  2. Add a substantial amount of markup and CSS to the page.

But with blend modes, we can flip the color of the text wherever it crosses into the black background:

h1 {
	color: #fff;
	mix-blend-mode: difference; 
}
The words BAD BOY, half-black and half-white, against a reversed background

The result is what you see at the top of the page.

This remains in effect even if a letter only partially crosses the black-white terminator:

…or if the background is an image.

Progressive Enhancement with Blend Modes

Because Internet Explorer does not yet support blend modes (although it is listed as being “under consideration” for Microsoft Edge), you must ensure that web page text remains legible even if blend modes are not applied. For the example at the top of this page, that’s fairly straightforward: if you can assume that the text always remains on a single line, you could simply make the text black and wrap the second word in a <span> element, coloring it white with CSS, creating the same effect regardless of the browser used.

The words BAD BOY, half-black and half-white, set against a photograph of a bridge reflected in a streamA more sophisticated approach would be to detect if the browser supported blends and apply color changes based on that information. You could do so using Modernizr:


Modernizr.addTest("mix-blend-mode", function(){
	return Modernizr.testProp("mixBlendMode");
});

Or @supports tested via JavaScript:

if ("CSS" in window && "supports" in window.CSS) {
	var support = window.CSS.supports("mix-blend-mode","difference");
	support = support?"mix-blend-mode":"no-mix-blend-mode";
	document.documentElement.className += support;
}

With the following in your stylesheet:

h1 { color: #000; }
.mix-blend-mode body {
	background-image: linear-gradient(90deg,#fff 49.9%,#000 50%);
}
.mix-blend-mode h1 { color: #fff; }

Or more directly, via @supports in CSS, with no dependency on JavaScript at all:

@supports (mix-blend-mode: difference) {
	body {
		background-image: linear-gradient(90deg,#fff 49.9%,#000 50%);
	}
	h1 { color: #fff; }
}

However you achieve it, the goal is the same: create a web page that looks good without blend modes, and use advanced CSS to enhance it.

Not A Cure-All

As the name implies, difference works best for contrast when the base color is significantly darker than, or the same as, the text color. As the background gets lighter, contrast changes tend to become less effective against white text: you’ll see this by experimenting with color values of the gradient and text in the CodePen demo. difference is not a panacea for a poorly planned color scheme, but it can be very effective in many cases.

Photograph by Andrew Stein, licensed under Creative Commons.

Enjoy this piece? I invite you to follow me at twitter.com/dudleystorey to learn more.
Check out the CodePen demo for this article at https://codepen.io/dudleystorey/pen/Xbdmjv