A reaction to overly ornamental designs, flat design has been the dominant aesthetic for almost a decade. As gradients, patterns, shadows, and three-dimensional skeuomorphism fell out of fashion, designers embraced solid colours, square corners, and sharp edges.

Anti-skeuomorphism no doubt helped designers focus on feature design and usability without the distraction of what some might still see as flourishes. But, reducing both product and website designs to a bare minimum has had unfortunate repercussions. With little to differentiate their designs, products and websites have adopted a regrettable uniformity which makes it difficult to distinguish between them.

Still, all fashions fade eventually. I’m hopeful that with the styling tools we have today, we’ll move beyond flatness and add an extra dimension. Here are five CSS properties which will bring depth and richness to your designs.

To illustrate how you might use them, I’ve made this design for the 1961 Austin Seven 850, the small car which helped define the swinging sixties.

The original Mini. Red, (British Racing) green, blue designs.

Transparency with alpha values

The simplest way to add transparency to a background colour, border, or text element is using alpha values in your colour styles. These values have been available in combination with RGB (red, green, blue) for years. In RGBA, decimal values below 1 make any colour progressively more transparent. 0 is the most transparent, 1 is the most opaque:

body { color: rgba(255, 0, 153, .75); }

Alpha values allow colour from a background to bleed through.

Alpha values also combine with HSL (hue, saturation, lightness) to form HSLA:

body { color: hsla(0, 0, 100, .75); }

Currently a Working Draft, CSS Color Module Level 4 enables alpha values in RGB and HSL without the additional “A”:

body { color: rgb(255, 0, 153, .75); /* color: hsl(0, 0, 100, .75); */ }

This new module also introduces hexadecimal colours with alpha values. In this new value, the last two digits represent the transparency level, with FF producing 100% opacity and 00 resulting in 100% transparency. For the 75% opacity in my design, I add BF to my white hexadecimal colour:

body { color: #ffffffbf; }

Although there’s already wide support for hexadecimal, HSL, and RGB with alpha values in most modern browsers, the current version of Microsoft Edge for Windows has lagged behind. This situation will no doubt change when Microsoft move Edge to Chromium.

2. Use opacity

Using the opacity property specifies the amount of opacity of any element (obviously) which allows elements below them in the stacking order to be all or partially visible. A value of 0 is most transparent, whereas 1 is most opaque.

Opacity tints images with colour from elements behind them.

This property is especially useful for tinting the colour of elements by allowing any colour behind them to bleed through. The British Motor Corporation logo in the footer of my design is solid white, but reducing its opacity allows it to take on the colour of the body element behind:

[src*="footer"] { opacity: .75; }

You might otherwise choose to use opacity values as part of a CSS filter. 0% opacity is fully transparent, while 100% is fully opaque and appears as if no filter has been applied. Applying a CSS filter is straightforward. First, declare the filter-function and then a value in parentheses:

[src*="footer"] { filter: opacity(75%); }

3. Start blending

Almost universally, contemporary browsers support the same compositing tools we’ve used in graphic design and photo editing software for years. Blend modes including luminosity, multiply, overlay, and screen can easily and quickly add depth to a design. There are two types of blend-mode.

background-blend-mode defines how background layers blend with the background colour behind them, and with each other. My layered design requires three background images applied to the body element:

body { padding: 2rem; background-color: #ba0e37; background-image: url(body-1.png), url(body-2.png), url(body-3.png); background-origin: content-box; background-position: 0 0; background-repeat: no-repeat; background-size: contain; }

From left: Three background images. Far right: How images combine in a browser.

You can apply different background-blend modes for each background image. Specify them in the same order as your background images and separate them with a comma:

body { background-blend-mode: multiply, soft-light, hard-light; }

Six background-blend-mode variations.

When I need to apply an alternative colour palette, there’s no need to export new background assets. I can achieve results simply by changing the background colour and these background-blend modes.

Backgrounds blend behind this brilliant little car.

Sadly, there’s not yet support for blending modes in Edge, so provide an alternative background image for that browser:

@supports not (background-blend-mode: normal) { body { background-image: url(ihatetimvandamme.png); } }

mix-blend-mode , on the other hand, defines how an element’s content should blend with its ancestors.

From left: Screen, overlay, and soft-light mix-blend-mode.

To blend my Mini image with the background colours and images on the body , I add a value of hard-light , plus a filter which converts my full-colour picture to greyscale:

[src*="figure"] { filter: grayscale(100%); mix-blend-mode: hard-light; }

You can also use mix-blend-mode to add depth to text elements, like this headline and large footer paragraph in a green and yellow version of my design:

.theme-green h1, .theme-green footer p:last-of-type { color: #f8Ef1c; mix-blend-mode: difference; }

Text elements blend to add interest in my design.

4. Overlap with CSS Grid

Whereas old-fashioned layout methods reinforced a rigid structure on website designs, CSS Grid opens up the possibility to layer elements without positioning or resorting to margin hacks. The HTML for my design is semantic and simple:

<body> <p>You’ve never seen a car like it</p> <h1><em>1961:</em> small car of the year</h1> <figure> <img src="figure.png" alt="Austin Seven 850"> <figcaption> <ul> <li>Austin Super Seven</li> <li>Morris Super Mini-Minor</li> <li>Austin Seven Cooper</li> <li>Morris Mini-Cooper</li> </ul> <figcaption> </figure> <footer> <p>Today’s car is a Mini</p> <p>Austin Seven 850</p> <img src="footer.png" alt="Austin Seven 850"> <footer> </body>

I begin by applying a three-column symmetrical grid to the body element:

@media screen and (min-width : 48em) { body { display: grid; grid-template-columns: 1fr 1fr 1fr; } }

Three-column symmetrical grid with column and row lines over my design.

Then, I place my elements onto that grid using line numbers:

body > p { grid-column: 1 / -1; } h1 { grid-column: 1 / 3; } figure { grid-column: 1 / -1; } footer { display: contents; } footer div { grid-column: 1 / 3; } [src*="footer"] { grid-column: 3 / -1; align-self: end; }

As sub-grid has yet to see wide adoption, I apply a second grid to my figure element, so I may place my image and figcaption :

figure { display: grid; grid-template-columns: 1fr 3fr; } figcaption { grid-column: 1; } [src*="figure"] { grid-column: 2; }

Left: This conventional alignment lacks energy. Right: Overlapping content adds movement which makes my design more interesting overall.

Previewing the result in a browser shows me the energy associated with driving this little car is missing. To add movement to my design, I change the image’s grid-column values so it occupies the same space as my caption:

figcaption { grid-column: 1; grid-row: 3; } [src*="figure"] { grid-column: 1 / -1; grid-row: 3; padding-left: 5vw; }

5. Stack with z-index

In geometry, the x axis represents horizontal, the y axis represents vertical. In CSS, the z axis represents depth. Z-index values can be either negative or positive and the element with the highest value appears closest to a viewer, regardless of its position in the flow. If you give more than one element the same z-index value, the one which comes last in source order will appear on top.

Visualisation of z-index illustrates the depth in this design.

It’s important to remember that z-index is only applied to elements which have their position property set to either relative or absolute . Without positioning, there is no stacking. However, z-index can be used on elements placed onto a grid.

All techniques combined to form a design which has richness and depth.

As the previous figure image and figcaption occupy the same grid columns and row, I apply a higher z-index value to my caption to bring it closer to the viewer, despite it appearing before the picture in the flow of my content:

figcaption { grid-column: 1; grid-row: 3; z-index: 2; } [src*="figure"] { grid-column: 1 / -1; grid-row: 3; z-index: 1; }

Z’s not dead baby, Z’s not dead

While I’m not advocating a return to the worst excesses of skeuomorphism, I hope product and website designers will realise the value of a more vibrant approach to design; one which appreciates how design can distinguish a brand from its competition.

I’m incredibly grateful to Drew and his team of volunteers for inviting me to write for this incredible publication every year for the past fifteen years. As I closed my first article here on this day all those years ago, “Have a great holiday season!” Z’s still not dead baby, Z’s still not dead.