CSS backface-visibility Property

Chapter 45 8 mins

Learning outcomes:

  1. What is backface-visibility
  2. A simple example
  3. An example using transform-style

Introduction

So far in this unit, we've learnt about a great deal of concepts related to CSS 3D transformations.

To be specific, we began with getting to know about perspective and how it affects 3D transformations. Then we moved over to consider 3D translations before exploring 3D rotations.

Finally, we learnt about the equally important and powerful concept of a 3D rendering context to get multiple elements to share a common 3D space, established using the transform-style property, set to the value preserve-3d.

Now if we just talk about 3D rotations, there's a special case that arises when we rotate an element in a way such that its backside faces us. To modify the visibility of the backside, we can use the backface-visibility property on the element.

This chapter is dedicated to understanding exactly what is the backface-visibility property; when and how to use it; and how it plays an important part in implementing some nice transitions using 3D rotations.

The backface-visibility property

By default, when an element is rotated via a 3D rotation, and its backside faces the viewer, it's merely shown as a mirror image of the element.

This can be seen as follows.

Here's an initial configuration of a <div>:

<div>A div</div>
div {
   display: inline-block;
   width: 100px;
   height: 100px;
   background-color: yellow;
}
A div

And here's it after being rotated around the y-axis by 180 degrees:

div {
   display: inline-block;
   width: 100px;
   height: 100px;
   background-color: yellow;
transform: rotateY(180deg); }
A div

Notice how the text has been inverted just like in a mirror.

This is great, but sometimes, it's desired to hide the backside of an element whenever it faces us, instead of showing it as a mirror image.

To do so, we have the provision of the backface-visibility property in CSS.

The backface-visibility property is used to control the visibility of the backside of an element.

The two possible values are hidden and visible, akin to the visibility property.

Syntactically, we could express it as follows:

backface-visibility: visible | hidden;

When the value is visible, which is the default, the backface is visible when it faces the viewer. Similarly, when the value is hidden, the backface is hidden when it faces the viewer.

At this point, you might be thinking of some possible application of backface-visibility, and that when could anyone possibly want to get the backside of an element to be hidden.

Well, one pretty common application of backface-visibility is in implementing a flip card transition in CSS.

When the card is rotated, the backface of an element is hidden to allow the card's actual backside to be shown to the viewer instead.

The backface-visibility property gives a live transition, as per the official spec. This means that as an element's backface is exposed, so is the appropriate rendering done in situ to either show or hide the backface, depending on the value of the backface-visibility property.

It's crucially important to remember that backface-visibility only comes into action when we work with 3D transformations, specifically with 3D rotations. If we're not concerned about rotations, we don't need to worry about backface-visibility.

Simple as that!

Let's consider a few examples of backface-visibility.

A simple example

Here's the same <div> example that we saw above, rotated along the y-axis so as to expose its backface:

div {
   display: inline-block;
   width: 100px;
   height: 100px;
   background-color: yellow;
   transform: rotateY(180deg);
}
A div

Now, let's apply the backface-visibility property to it and see what happens:

div {
   display: inline-block;
   width: 100px;
   height: 100px;
   background-color: yellow;
   transform: rotateY(180deg);
backface-visibility: hidden; }
A div

See anything? No?

Well, then that's amazing because there shouldn't be anything shown. The element's backface is facing us and by virtue of backface-visibility set to hidden, it shouldn't be rendered.

This was a fairly basic example; let's now consider a bit more involved example.

Example with transform-style

Suppose we have two <div>s lined next to each other, inside a <section> element.

Here's the HTML:

<section>
   <div>Div 1</div>
   <div>Div 2</div>
</section>

And here's the CSS:

section {
   display: inline-block;
   border: 10px solid #aaa;
}

div {
   display: inline-block;
   width: 100px;
   height: 100px;
   background-color: yellow;
}
Div 1
Div 2

Now, let's say we rotate just one <div> — the second one, to be precise — by 180 degrees around the y-axis:

div:first-child {
   transform: rotateY(180deg);
}
Div 1
Div 2

Just as expected, we'll obviously get a mirror reflection.

Now, let's add backface-visibility: hidden to both the <div>s so to hide their backsides when they face us:

div {
   display: inline-block;
   width: 100px;
   height: 100px;
   background-color: yellow;
backface-visibility: hidden; }
Div 1
Div 2

The second <div> goes out of view as its backside is facing us.

So far, so good.

We shall now rotate the entire <section> by 180 degrees again to see what we get:

section {
   display: inline-block;
   border: 10px solid #aaa;
transform: rotateY(180deg); }
Div 1
Div 2

Well, weirdly, we get a reflection of the <section> rather than the first <div> being shown and the second one hidden.

Can you reason why this happens?

Well, it's because the <div>s are rendered into the plane of <section>. When we rotate the <section> above, we might feel that we are also rotating the <div>s but that's NOT the case, speaking precisely.

The <div>s could be thought of as 'embedded' inside the <section> so when we rotate the <section>, the <div>s themselves aren't rotated; it's just the <section> that's rotated.

However, if we get the <section> to establish a 3D rendering context, we can change this behavior.

Let's first try doing this and then explain it.

We'll apply transform-style: preserve-3d to the <section> element to get the <div>s to share 3D space with it. The rotation applied to <section> would remain as it is:

section {
   display: inline-block;
   border: 10px solid #aaa;
   transform: rotateY(180deg);
transform-style: preserve-3d; }

Let's now see the output we get:

Div 1
Div 2

This time, as we had expected in the previous example, the first <div> gets hidden while the second one gets shown, thanks to the rotation of the <section> and a shared 3D space.

So exactly why do we get this different output now?

Well, when we rotate the <section> now, its transformations travel down to its children <div>s (by virtue of accumulated transformations, which we learnt in the previous chapter CSS 3D Transformation — The transform-style Property).

So, transforming the <section> by 180 degrees is effectively saying to transform the <div> by 180 degrees, independently, which ultimately gets the backface of the first <div> to be shown while that of the second one to be hidden.

In short, it's all simply because of the advent of transform-style: preserve-3d to the <section> element that we get the expected rotation outcome.

If you learn them the right way, 3D transformations aren't really that hard.

What do you say?