In section 202, we learned about the CSS colour model, about named colours, system colours, specifying colours using RGB, HSL, or one of the other colour models supported by CSS.
In this section, we’re going to learn about various other techniques and functions we can use in CSS to control the appearance of our elements, starting with background.
Background
We’ve already met the background-color property, which we’ve used in several demos so far in the course, but CSS can do a lot more with backgrounds than just set them to a solid colour.
One of the oldest web design techniques is using images as element backgrounds, and over the years CSS has added properties that give us a huge amount of control over exactly how an image should be used as a background.
We’ll kick off with the simplest possible example:
body {
background-image: url(background-tile-100px.png);
font-family: Consolas, 'Courier New', Courier, monospace;
height: 200px;
}The background image is shown at its native size — 100x100 pixels in this example — and covers the whole background with a repeating tile pattern.
The background-repeat property takes one or two parameters; if you give it two parameters, the first one is the horizontal repeat, the second is the vertical:
repeat- the default; repeat the image to cover the entire background area, clipping if it overflows the element’s content area.no-repeat- just show the image oncespace- repeat the image as many times as possible, but leave a space between adjacent tiles so that none of them get clipped.round- stretch (distort) the image rather than clipping it. If the element will accommodate 1.49 backgrounds, you’ll get a single tile stretched to fit. If the element will accommodate 1.5 backgrounds, you’ll get two tiles, shrunk to fit. The tile’s aspect ratio is not preserved.repeat-x: shorthand forrepeat no-repeatrepeat-y: shorthand forno-repeat repeat
background-size controls, well, the size of the background: contain makes the background small enough that the element contains at least one full copy of the background; cover shrinks the background enough to cover the element, and crops any overmatter. If you specify background-size a single unit, that sets the width of the element; if you specify two units, that’s width and height.
background-attachment controls how the element’s background responds to scrolling - is the background attached to the viewport (fixed), to the document (scroll), or to the element itself (local) ? You’ll also notice if you look closely at this example that if the background-attachment is set to fixed, then the background-size is relative to the viewport, not the element itself:
background-origin controls whether the top-left corner - the origin - of the background is relative to the element’s border, padding, or content:
background-clip determines whether the background fills the border, padding, or content box of the element, or only applies to the actual letterforms of the element’s text.
In CSS, the border is always drawn over the top of the background, so
border-boxclipping is only visible if the border has transparency or transparent regions
<section style="background-clip: border-box;">AB</section>
<section style="background-clip: padding-box;">CD</section>
<section style="background-clip: content-box;">EF</section>
<section style="background-clip: text; color: transparent;">GH</section>
<p style="clear: both;">
Photo by <a href="https://unsplash.com/@sickle">Sergey Pesterev</a> on <a
href="https://unsplash.com/photos/wdMWMHXUpsc">Unsplash</a>
</p>
and background-position sets the initial position of the background image, relative to the background-origin:
CSS Gradients
One of the most useful features of modern CSS is buried in the spec as a syntactical footnote to the background-image feature, because as well as specifying the background image as a URL, you can use a CSS gradient as a background.
Technically, CSS treats a gradient as a special kind of image, and supports three basic gradients - linear, radial, and conic:
body {
text-align: center;
}
section {
width: 30vw;
height: 30vw;
display: inline-block;
font-family: Arial, Helvetica, sans-serif;
font-weight: 900;
color: #fff;
text-align: center;
}
section.linear {
background-image: linear-gradient(to bottom, red, yellow, green, blue, indigo, red);
}
section.radial {
background-image: radial-gradient(red, yellow, green, blue, indigo, red);
}
section.conic {
background-image: conic-gradient(red, yellow, green, blue, indigo, red);
}
<section class="linear">linear gradient</section>
<section class="radial">radial gradient</section>
<section class="conic">conic gradient</section>You can specify the exact position of the colour stops in a gradient:
body {
overflow: hidden;
text-align: center;
}
section {
width: 30vw;
height: 30vw;
display: inline-block;
font-family: Arial, Helvetica, sans-serif;
font-size: 1.5vw;
color: #fff;
text-align: center;
}
section.linear {
background-image: linear-gradient(to bottom, black, black 40px, yellow 50px, red 80%, green 90%, blue);
}
section.radial {
background-image: radial-gradient(red, red 20%, yellow 25%, green 30%, blue 35%, indigo 40%, red 50%);
}
section.conic {
background-image: conic-gradient(red, red 90deg, yellow 90deg, green 50%, blue 55%, indigo 60%, red);
}
<section class="linear">linear gradient</section>
<section class="radial">radial gradient</section>
<section class="conic">conic gradient</section>Angles in CSS
We briefly met CSS angles when we looked at colour wheels in the section on CSS colour models. Angles crop up in all kinds of places in CSS — most obviously, in the functions for rotating an element, which we’ll meet later — but they’re also used to specify the direction of a linear-gradient, and the postions of the colour stops when using a conic-gradient.
You can specify angles in CSS using:
- Degrees:
90deg. One full circle is 360 degrees. (You knew that, right?) - Radians:
3.1416rad; a full circle is 2π radians (but you can’t use π as a number in CSS, so working in radians you’ll end up with lots of decimal places ) - Gradians:
100grad. A full circle is 400 gradians; 100 gradians is a right angle. - Turns.
0.5turn- a full circle is 1 turn.
The full docs are over on MDN if you need them: https://developer.mozilla.org/en-US/docs/Web/CSS/angle
For the linear-gradient function, you can specify the direction of the gradient, as an angle:
* {
box-sizing: border-box;
}
div {
padding: 1vw;
font-family: Consolas, 'Courier New', Courier, monospace;
width: 20vw;
height: 20vw;
display: inline-block;
border: 1px solid black;
font-size: 0.8rem;
}
<div
style="background-image: linear-gradient(0deg, white 30%, red, yellow, blue, white 70%);">
0deg</div>
<div
style="background-image: linear-gradient(22deg, white 30%, red, yellow, blue, white 70%);">
22deg</div>
<div
style="background-image: linear-gradient(to left, white 30%, red, yellow, blue, white 70%);">
to left</div>
<div
style="background-image: linear-gradient(to right, white 30%, red, yellow, blue, white 70%);">
to right</div>
<div
style="background-image: linear-gradient(to bottom left, white 30%, red, yellow, blue, white 70%);">
to bottom left</div>
<div
style="background-image: linear-gradient(to bottom right, white 30%, red, yellow, blue, white 70%);">
to bottom right</div>
<div
style="background-image: linear-gradient(-0.33turn, white 30%, red, yellow, blue, white 70%);">
-0.33turn</div>
<div
style="background-image: linear-gradient(-0.33rad, white 30%, red, yellow, blue, white 70%);">
-0.33rad</div>For radial gradients, you can specify the gradient’s origin point, independently of the background position:
* {
box-sizing: border-box;
}
div {
float: left;
margin: 1vw;
width: 20vw;
height: 20vw;
border: 1px solid #000;
&#a {
background-image: radial-gradient(at 0 , yellow, red, blue, purple);
}
&#b {
background-image: radial-gradient(at 0 100%, yellow, red, blue, purple);
}
&#c {
background-image: radial-gradient(at 150% 150%,
white 0 40%,
skyblue 40%,
white 45% 70%,
skyblue 70%,
white 75%);
}
&#d {
border-radius: 100%;
background-image: radial-gradient(at 25% 25%, pink 2%, red 25%, darkred 70%);
}
}
<div id="a"></div>
<div id="b"></div>
<div id="c"></div>
<div id="d"></div>For conic gradients, you can specify both the origin point, and the starting angle:
* {
box-sizing: border-box;
}
div {
float: left;
margin: 1vw;
width: 20vw;
height: 20vw;
border: 1px solid #000;
&#a {
background-image: conic-gradient(yellow, red, blue, purple);
}
&#b {
background-image: conic-gradient(from 45deg, yellow, red, blue, purple);
}
&#c {
background-image: conic-gradient(at 0 100%, yellow, red, blue, purple);
}
&#d {
background-image: conic-gradient(from 45deg at 0 100%, yellow, red, blue, purple);
}
&#e {
background-image: conic-gradient(from 60deg at 0 50%, yellow, red, blue, purple);
}
&#f {
background-image: conic-gradient(from 45deg at -80% 110%,
black 0 5deg,
red 5deg 10deg,
orange 10deg 15deg,
gold 15deg 20deg,
green 20deg 25deg,
skyblue 25deg 30deg,
purple 30deg 35deg,
black 35deg);
}
&#g {
background-image: conic-gradient(from 45deg at -80% 110%,
black 0 5deg,
red,
orange,
gold ,
rgb(0, 202, 0),
skyblue,
purple,
black 35deg);
}
&#h {
background-image: conic-gradient(from 0 at 50% 25%,
skyblue 90deg,
green 90deg 130deg,
grey 130deg 135deg,
black 135deg 179deg,
#fff 179deg 181deg,
black 181deg 225deg,
grey 225deg 230deg,
green 230deg 270deg,
skyblue 270deg
);
}
<div id="a"></div>
<div id="b"></div>
<div id="c"></div>
<div id="d"></div>
<div id="e"></div>
<div id="f"></div>
<div id="g"></div>
<div id="h"></div>There’s also a repeating version of each gradient:
body {
overflow: hidden;
text-align: center;
}
section {
width: 30vw;
height: 30vw;
display: inline-block;
font-family: Arial, Helvetica, sans-serif;
font-weight: 900;
font-size: 1.5vw;
color: #fff;
text-align: center;
}
section.linear {
background-image: repeating-linear-gradient(45deg,
black,
black 10px,
red 10px,
red 12px,
black 12px,
black 20px,
blue 20px,
blue 22px);
}
section.radial {
background-image: repeating-radial-gradient(black,
black 10px,
red 11px,
red 14px,
black 15px,
black 25px,
blue 26px,
blue 29px,
black 30px);
}
section.conic {
background-image: repeating-conic-gradient(black 0deg 6deg,
red 7.5deg,
black 9deg 21deg,
blue 22.5deg,
black 24deg 36deg,
yellow 37.5deg,
black 39deg 45deg);
}
<section class="linear">repeating linear gradient</section>
<section class="radial">repeating radial gradient</section>
<section class="conic">repeating conic gradient</section>Watch out for the difference between a repeating gradient, and repeating a gradient; you can also use a regular non-repeating gradient pattern to create a single background tile, and then repeat that tile across the element’s background. One particularly neat trick here is to use a conic gradient to create one “tile” of a repeating chequerboard pattern:
section {
display: flex;
justify-content: space-around;
div {
outline: 1px solid black;
width: 32vw;
height: 16vw;
background-size: 8vw 8vw;
margin-bottom: 1rem;
}
&.no-repeat {
div {
background-repeat: no-repeat;
}
}
div:nth-child(1) {
background-image: linear-gradient(to top left, gold 50%, blue 50%);
}
div:nth-child(2) {
background-image: radial-gradient(gold 30%, blue 30%);
}
div:nth-child(3) {
background-image: conic-gradient(gold 0 90deg,
blue 90deg 180deg,
gold 180deg 270deg,
blue 270deg 360deg);
}
}Composing Multiple Backgrounds
OK, so you’ve seen about five hundred different ways to use an image as the background of an element… important, but not exciting.
What makes CSS backgrounds really useful is that an element can have more than one background - and we can control how multiple backgrounds are combined, giving us a way to create some really cool visual effects.
How about a background photograph, and then overlaying that with a transparent gradient effect?
body { text-align: center; }
section {
margin: 0 auto;
width: 75vw;
height: 50vw;
background-image:
linear-gradient(to right, #00f9 0% 33%, #fff9 33% 67%, #f009 67% 100%),
url(amelia-cui-V9lFsmelUOo-unsplash.jpg);
background-size: 100%, contain;
background-repeat: no-repeat, no-repeat;
}Or combining multiple repeated gradients with a handwriting font to create something reminiscent of a school exercise book?
<!DOCTYPE html>
<html lang="en">
<head>
<title>Exercise Book</title>
<style>
html { margin: 0; padding: 0; }
body {
background:
repeating-linear-gradient(to bottom, #fff0 0rem 1.95rem, skyblue 1.95rem 2rem),
linear-gradient(to right, #fff0 0rem 3rem, #f009 3rem 3.1rem, #fff0 3.1rem),
#fff;
padding: 0;
margin: 0;
pre {
font-family: cursive;
line-height: 2rem;
font-size: 1.1rem;
margin: 0.5rem 0 0 3.5rem;
h1 {
font-size: inherit;
margin: 0;
padding: 0;
text-decoration: 1px underline double;
}
}
}
</style>
</head>
<body>
<pre><h1>A CSS Limerick</h1>
There was a young man from Loch Ness,
Who tried to avoid CSS,
But styling one page,
Sent him into a rage,
And created a terrible mess
<em>- by Dylan Beattie, age 46¾</em>
</pre>
</body>
</html>The thing to remember about composing multiple CSS backgrounds is that you need to provide multiple values for each property:
background-image: <image1> <image2>, <image3>, <image4>;
background-size: <size1>, <size2>, <size3>, <size4>;
background-position: <position1>, <position2>, <position3>, <position4>;
The first background is drawn closest to the viewer, the final background is drawn furthest away from the viewer, and only the final image can be a solid colour (even if that colour has transparency; if you need a transparent colour layer as part of a background stack, use a gradient that only defines one colour).
Background Shorthand
So far, almost every example we’ve seen has explicitly specified each property in turn. Many CSS features also support a shorthand syntax we can use to specify multiple related properties using a single rule. In the case of backgrounds, the shorthand property is background, followed by one more background layers, separated by commas, where each layer is specified using a shorthand syntax which includes one or more of:
background-imagebackground-position/ background-size- note that size must follow position, and they must be separated with a/background-repeatbackground-originbackground-clipbackground-attachmentbackground-color
Here’s an example of a five-layer background, specified using the background shorthand:
body {
background:
/* First layer: the purple smoke curl */
url(purple-smoke-curl.png) bottom left -300px / 600px 1200px no-repeat,
/* second layer: the bottom right logotype */
url(indigo-designs.png) bottom 20px right 20px / min(20vw, 300px) no-repeat fixed,
/* third layer: the black-to-indigo gradient */
linear-gradient(to bottom right, #000e 0 50%, #4b008299) fixed,
/* fourth layer: the pinstripe */
repeating-linear-gradient(115deg, #0000 0 10px, white 11px 12px, #0000 13px) fixed,
/* bottom layer: solid black */
#000;
max-width: 540px;
padding-left: 200px;
padding-right: 20vw;
color: #fff;
font-family: 'Lucida Grande', 'Lucida Sans', Arial, sans-serif;
footer {
font-size: 60%;
}
}z-index
Using absolute positioning, we can have elements in a document which are painted over the top of each other. 3D computer graphics traditionally uses three coordinates (x,y,z), where x is horizontal, y is vertical, and the z-axis is pointing either away from the viewer into the screen, or out of the screen towards the viewer, depending which system you’re using. CSS doesn’t use a true 3D coordinate system, but we can “move” elements forwards or backwards in the rendering stack using a property called the z-index.
<div>
<span style="z-index: 1;">z-index: 1</span>
<span style="z-index: 2;">z-index: 2</span>
<span style="z-index: 3;">z-index: 3</span>
</div>
<div>
<span style="z-index: 3;">z-index: 3</span>
<span style="z-index: 2;">z-index: 2</span>
<span style="z-index: 1;">z-index: 1</span>
</div>
<div>
<span style="z-index: 2;">z-index: 2</span>
<span style="z-index: 3;">z-index: 3</span>
<span style="z-index: 1;">z-index: 1</span>
</div>
z-index can take any integer value, including negative values to move something backwards in the display stack. In practice, you’ll see it used in two ways. Well-engineered CSS tends to use small z-index values - 3, 4, 5 - to assign elements to a predetermined series of layers, because somebody sat down and figured it all out in advance and a well-engineered site will seldom have more than half-a-dozen elements in a render stack.
In my experience, it’s also common to see z-index values like 99 and 999 because some long-suffering maintenance developer has to add a cookie warning banner or a chat popover window or something, and the only way to get it to appear on top of all the existing elements on the page is to use a very high z-index.
If you’re curious,
z-indexis a 32-bit signed integer in all modern browsers, which means the highestz-indexyou can have is (2^31-1) = 2147483647. But hey - twenty one billion layers ought to be enough for anybody, right?
Stacking elements like this is relatively simple when they’re all solid: you only see the one at the front. But once we start introducing concepts like opacity, it can get very interesting indeed.
<div>
<span style="z-index: 1;">z-index: 1</span>
<span style="z-index: 2;">z-index: 2</span>
<span style="z-index: 3;">z-index: 3</span>
</div>
<div>
<span style="z-index: 3; opacity: 0.8;">z-index: 3</span>
<span style="z-index: 2; opacity: 0.8;">z-index: 2</span>
<span style="z-index: 1; opacity: 0.8;">z-index: 1</span>
</div>
<div>
<span style="z-index: 2;background-color: rgb(145 255 122 / 0.8);">
z-index: 2</span>
<span style="z-index: 3;background-color: rgb(124 218 255 / 0.8);">
z-index: 3</span>
<span style="z-index: 1;background-color: rgb(216 132 255 / 0.8);">
z-index: 1</span>
</div>
Notice how in this example, the boxes in the middle have opacity applied to the entire element, so it affects the text and border as well as the background, whereas the boxes on the right are opaque elements with a transparent background, so the text and border is still drawn at full intensity.
Stacking Contexts
A stacking context defines a group of associated elements that will be stacked independently of any other group of elements. Every page has at least one stacking context, created by the root <html> element, and giving just about element a z-index will create another stacking context - check out features creating stacking contexts at MDN if you want the full list. It’s not very interesting.
If you want to create a new stacking context without specifying a z-index, use the isolation: isolate property. This is particularly useful for controlling the composition of the ::before and ::after pseudo-elements without affecting the originating element’s position in the document stack.
Using CSS Blend Modes
In all the examples above, we only see the further layer if the nearer layer has some transparency to it; if foreground background layers are fully opaque, the background layer is completely covered and doesn’t affect what ends up on the screen.
Multiple backgrounds is one of the places where we can use something called blend modes; a bunch of algorithms that started out in fundamental computer graphics, made their way into applications like Photoshop, and have ended up baked into browsers as part of the latest CSS standards.
Before we go any further, there are two things to bear in mind about blend modes and filters. First: you can use them to create just about any effect imaginable; by combining blend modes, you can create literally thousands of different effects.
Second: the vast majority of those will not yield anything useful. Many of them won’t actually do anything at all. It’s incredibly hard to predict what a given combination of blend modes will actually do, and using them in your own code often boils down to a lengthy iterative process of trial and error. There are a handful of genuinely useful applications of CSS blend modes, and once in while you’ll find a scenario where a background blend mode actually solves a problem, but if you’re staring at them going “…why would I ever use this?”, you’re not alone.
The descriptions here are taken directly from the MDN documentation on blend modes:
-
The final color is the top color, regardless of what the bottom color is. The effect is like two opaque pieces of paper overlapping.
-
The final color is the result of multiplying the top and bottom colors. A black layer leads to a black final layer, and a white layer leads to no change. The effect is like two images printed on transparent film overlapping.
-
The final color is the result of inverting the colors, multiplying them, and inverting that value. A black layer leads to no change, and a white layer leads to a white final layer. The effect is like shining two projectors onto the same screen.
-
The final color is the result of
multiplyif the bottom color is darker, orscreenif the bottom color is lighter. This blend mode is equivalent tohard-lightbut with the layers swapped. -
The final color is composed of the darkest values of each color channel.
-
The final color is composed of the lightest values of each color channel.
-
The final color is the result of dividing the bottom color by the inverse of the top color. A black foreground leads to no change. A foreground with the inverse color of the backdrop leads to a fully lit color. This blend mode is similar to
screen, but the foreground need only be as light as the inverse of the backdrop to create a fully lit color. -
The final color is the result of inverting the bottom color, dividing the value by the top color, and inverting that value. A white foreground leads to no change. A foreground with the inverse color of the backdrop leads to a black final image. This blend mode is similar to
multiply, but the foreground need only be as dark as the inverse of the backdrop to make the final image black. -
The final color is the result of
multiplyif the top color is darker, orscreenif the top color is lighter. This blend mode is equivalent tooverlaybut with the layers swapped. The effect is similar to shining a harsh spotlight on the backdrop. -
The final color is similar to
hard-light, but softer. This blend mode behaves similar tohard-light. The effect is similar to shining a diffused spotlight on the backdrop. -
The final color is the result of subtracting the darker of the two colors from the lighter one. A black layer has no effect, while a white layer inverts the other layer’s color.
-
The final color is similar to
difference, but with less contrast. As withdifference, a black layer has no effect, while a white layer inverts the other layer’s color. -
The final color has the hue of the top color, while using the saturation and luminosity of the bottom color.
-
The final color has the saturation of the top color, while using the hue and luminosity of the bottom color. A pure gray backdrop, having no saturation, will have no effect.
-
The final color has the hue and saturation of the top color, while using the luminosity of the bottom color. The effect preserves gray levels and can be used to colorize the foreground.
-
The final color has the luminosity of the top color, while using the hue and saturation of the bottom color. This blend mode is equivalent to
color, but with the layers swapped.
Here’s what they look like.
To apply blend modes to multiple background on the same element, use background-blend-mode; if you want to blend elements against other elements, use mix-blend-mode.
One particularly useful example of blend modes is creating duotone images to use as element backgrounds:
html {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
main {
display: flex;
gap: 10px;
justify-content: space-between;
}
section {
color: #fff;
align-items: flex-end;
padding: 2vw;
box-sizing: border-box;
font-weight: 900;
font-size: 4vw;
line-height: 0.9em;
display: flex;
width: 30vw;
height: 30vw;
background-blend-mode: color, saturation;
background-position: center;
background-size: cover;
}
section.blues {
background-image:
linear-gradient(royalblue),
linear-gradient(black),
url(dominik-scythe-XV9F-gfmThs-unsplash.jpg);
}
section.jazz {
background-image:
linear-gradient(crimson),
linear-gradient(black),
url(reno-laithienne-MGfDE60G0-M-unsplash.jpg);
}
section.rock {
background-image:
linear-gradient(purple),
linear-gradient(black),
url(adam-gritco-eZaO39RrjxU-unsplash.jpg);
}
footer {
margin: 10px auto;
font-size: 10px;
}For a full duotone effect, sometimes known as a split tone, you can apply one tint to the shadows and a separate tint to the highlights by using a ::before and ::after pseudoelement, with different mix-blend-mode properties applied to the ::before and ::after layer.
footer {
margin: 10px auto;
font-size: 10px;
line-height: 14px;
display: flex;
justify-content: space-between;
}
main {
display: flex;
justify-content: space-between;
}
section {
background-position: center;
background-repeat: no-repeat;
background-size: cover;
box-sizing: border-box;
color: #fff;
display: flex;
font-family: Arial, Helvetica, sans-serif;
font-size: 10vw;
font-weight: 900;
height: 30vw;
justify-content: flex-start;
padding-top: 18vw;
padding-left: 1vw;
position: relative;
width: 30vw;
&:hover::before {
display: none;
}
&:hover::after {
display: none;
}
}
section::before, section::after {
content: '';
display: block;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
section::before {
mix-blend-mode: darken;
}
section::after {
mix-blend-mode: lighten;
}
section#skyline {
background-image: url(sean-pollock-PhYq704ffdA-unsplash.jpg);
&::before { background-color: lime; }
&::after { background-color: navy; }
}
section#coolpup {
background-image: url(mollie-sivaram-ts1zXzsD7xc-unsplash.jpg);
&::before { background-color: yellow; }
&::after { background-color: red; }
}
section#monster {
background-image: url(filip-mroz-0hJL8lBl0qQ-unsplash.jpg);
background-size: 180%;
&::before { background-color: magenta; }
&::after { background-color: blue; }In this example, I’ve used a :hover pseudo-class to reveal the unfiltered background image when you mouse-over each element; this effect also relies on very specific combinations of colours, so you’ll need to experiment if you want to recreate it using your own colour palette and images.
CSS Filters and Stacking Elements
We can do some pretty cool things using layered backgrounds, but if we want to get really creative, we need to learn about CSS filters.
Using the filter property, we can apply a range of visual effects to any element in the document.
body {
text-align: center;
}
section {
background: linear-gradient(to right,
hsl(000, 50%, 30%),
hsl(060, 50%, 30%),
hsl(120, 50%, 30%),
hsl(180, 50%, 30%),
hsl(240, 50%, 30%),
hsl(300, 50%, 30%));
color: white;
width: 30vw;
display: inline-block;
font-size: 20px;
text-align: center;
font-weight: 900;
display: inline-block;
font-family: Consolas, 'Courier New', Courier, monospace;
padding: 20px 0;
margin: 4px;
span {
display: block;
color: white;
&:nth-child(2) {
color: black;
}
}
<section>
<span>no filter</span>
<span>no filter</span>
</section>
<section style="filter: blur(2px);">
<span>blur(2px)</span>
<span>blur(2px)</span>
</section>
<section style="filter: sepia();">
<span>sepia</span>
<span>sepia</span>
</section>
<section style="filter: grayscale(100%);">
<span>grayscale(100%)</span>
<span>grayscale(100%)</span>
</section>
<section style="filter: hue-rotate(90deg);">
<span>hue-rotate(90deg)</span>
<span>hue-rotate(90deg)</span>
</section>
<section style="filter: invert(100%);">
<span>invert(100%)</span>
<span>invert(100%)</span>
</section>
<section style="filter: brightness(50%);">
<span>brightness(50%)</span>
<span>brightness(50%)</span>
</section>
<section style="filter: brightness(200%);">
<span>brightness(200%)</span>
<span>brightness(200%)</span>
</section>
<section style="filter: contrast(200%);">
<span>contrast(200%)</span>
<span>contrast(200%)</span>
</section>
<section style="filter: contrast(50%);">
<span>contrast(50%)</span>
<span>contrast(50%)</span>
</section>
<section style="filter: saturate(50%);">
<span>saturate(50%)</span>
<span>saturate(50%)</span>
</section>
<section style="filter: saturate(200%);">
<span>saturate(200%)</span>
<span>saturate(200%)</span>
</section>
<section style="filter: opacity(50%);">
<span>opacity(50%)</span>
<span>opacity(50%)</span>
</section>
<section style="filter: drop-shadow(5px 5px 2px rgba(0,0,0,0.8));">
<span>drop-shadow</span>
<span>drop-shadow</span>
</section>
<section style="filter: drop-shadow(10px 10px 0px magenta);">
<span>drop-shadow</span>
<span>drop-shadow</span>
</section>You can combine multiple filters on a single element; if you do this, remember that filters are applied in the order they’re defined; applying contrast after blur will produce a very different outcome to applying blur after contrast:
p {
margin: 2vw;
}
div {
display: inline-block;
width: 21vw;
height: 20vw;
margin: 0 1vw;
outline: 2px solid #000;
background-image: url(david-clode-Ue2tcqeomdw-unsplash.jpg);
background-size: cover;
background-position: center;
&:nth-child(2) {
filter: saturate(0.2) contrast(50) blur(0.2vw);
}
&:nth-child(3) {
filter: blur(0.2vw) contrast(50) saturate(0.2);
}
&:nth-child(4) {
filter: blur(0.2vw) saturate(0.2) contrast(50);
}
}Backdrop Filter
And finally… backdrop filter. You know that cool translucent effect you sometimes see on things like Windows Terminal?
Yeah. We can totally do that. If you apply any of the CSS filter functions using the backdrop-filter property, they’ll be applied to the background that appears behind the target element.
body {
width: 100vw;
height: 200vh;
overflow-x: hidden;
background-image: url(josh-soto-M76ZhVCMtYw-unsplash.jpg);
background-size: cover;
background-position: center;
}
main {
position: fixed;
display: flex;
flex-wrap: wrap;
justify-content: space-around;
gap: 1rem;
}
div {
box-sizing: border-box;
width: 30vw;
height: 7rem;
font-family: Consolas, 'Courier New', Courier, monospace;
display: inline-block;
padding: 1em;
border: 5px solid #000;
color: #fff;
code {
background-color: #000;
color: #fff;
padding: 5px;
border-radius: 3px;
}
&:nth-child(1) {
backdrop-filter: invert(0.8);
}
&:nth-child(2) {
backdrop-filter: grayscale();
}
&:nth-child(3) {
backdrop-filter: blur(10px);
}
&:nth-child(4) {
backdrop-filter: hue-rotate(180deg);
}
&:nth-child(5) {
backdrop-filter: saturate(0.5);
}
&:nth-child(6) {
backdrop-filter: contrast(0.2);
}
&:nth-child(7) {
backdrop-filter: sepia(1);
}
&:nth-child(8) {
backdrop-filter: brightness(0.2);
}
&:nth-child(9) {
backdrop-filter: blur(5px) contrast(20) brightness(0.5);
}Backdrop filters are particularly useful for darkening a background image behind elements, so you can ensure that light-coloured text remains legible without completely covering the background - and like before, you can combine multiple filters in a single property to achieve effects like solarization.
Review and Recap
In this section, we’ve learned about CSS backgrounds, blend modes, stacking contexts, and filters — all features we can use to control how overlapping elements are composed by the browser.
- We’ve learned about background properties like
background-repeat,background-size,background-attachment,background-origin,background-clipandbackground-positioncontrol how an element’s background is composed relative to the element itself - We learned how to use linear, radial, and conic gradients to create various kinds of background effects - and the difference between a repeating gradient, and repeating a gradient.
- We’ve seen how to give an element multiple backgrounds, how to control their stacking order, and how to use the
backgroundproperty shorthand to define multiple properties in a single rule - We’ve met
z-index,isolation, and stacking contexts, use to control the rendering order of overlapping elements - We’ve used CSS blend modes to create visual effects like duotone backgrounds
- We’ve used CSS filters like
blur()andbrightness()to change the appearance of elements, and usedbackdrop-filterto apply visual effects to an element’s backdrop.
Links and References
- Compositing and Blending In CSS by Sara Souiedan
- https://www.sarasoueidan.com/blog/compositing-and-blending-in-css/
- The CSS property you didn’t know you needed by Francesco Vetere
- https://dev.to/francescovetere/the-css-property-you-didnt-know-you-needed-3fk0
- Exploring CSS Isolation Property: Enhancing Web Design with Stacking Contexts
- https://levelup.gitconnected.com/exploring-css-isolation-property-enhancing-web-design-with-stacking-contexts-87dedfa0f2c0