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;
}
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);
}
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.
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);
}
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;
}
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;
}
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);
}
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;
}
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);
}
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:
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?