#30 Web
15 mins   /

Dissecting the perspective-origin property in CSS

Understand how the perspective-origin property works in tandem with the perspective property in positioning in the perspective view point in the xy plane.

If you ought to work with 3D transforms in CSS, understanding perspective is an unquestionable imperative. It's basically the way to actually have your 3D transforms produce a meaningful, visual effect; otherwise they just get flattened out into the void.

But right after you learn what perspective really is in CSS — particularly the perspective style property — another thing starts to urge to be learned. What is that? The perspective-origin property.

What is perspective-origin?

The perspective-origin property specifies the location of the perspective view point on the xy plane, which is simply the plane consisting of the x-axis and y-axis.

For example, if the perspective-origin of a square object is at its top-left corner, as follows,

Square object with perspective-origin situated at the top-left
Square object with perspective-origin situated at the top-left.

then here's how the corresponding perspective view point will look from the side:

Side view of square object with perspective-origin situated at the top-left.
Side view of square object with perspective-origin situated at the top-left.

See how perspective-origin influences the positioning of the view point — it is in line with the perspective-origin.

To be precise, perspective-origin positions the view point in the x and y axes; positioning in the z-axis is already covered by the perspective property.

Syntactically, perspective-origin is identical to transform-origin:

perspective-origin: x-position y-position |
                    y-position x-position |
                    x-position |
                    y-position

You can specify just one value which represents the x-position (e.g. left) or the y-position (e.g. top), or you can specify two values which represent both x and y values (e.g. top left).

The default is for both the values to be 50%. So, in your specification, if you omit a given position, the other position remains at 50%. For instance, because top corresponds to a y-axis position,

perspective-origin: top

means that the x-position is 50% whereas the y-position is 0% (top trivially means 0%).

Examples

Let's consider some examples demonstrating perspective-origin.

First, let's see a simple case using the default value of perspective-origin. In the following code, three squares are laid out inside a container which has been given display: inline-block to consume only as much of a width as is needed to fit the squares:

HTML
<div class="container">
   <div class="square"></div>
   <div class="square"></div>
   <div class="square"></div>
</div>
CSS
.container {
   background-color: #eee;
   display: inline-block;
   padding: 20px;
}

.square {
   width: 100px;
   height: 100px;
   background-color: gold;
   display: inline-block;
   margin: 10px;
}

By default, when an element is given the perspective property, its perspective-origin is prescribed to its very center. Hence, in the code above, if you apply perspective to .container and then translate the squares backwards, they'll all seem to approach the given perspective-origin point at the center.

Let's see this for real:

CSS
.container {
   perspective: 500px;
}

.square {
   transform: translateZ(-500px);
}

As is evident in the output shown here, everything seems to be moving towards the center. This is simply because the perspective view point, for every square, is positioned at the center (in the xy plane) of the container.

Similarly, if you translate the squares toward the viewer — with a positive z-value — they'll all grow in size but still be focused around the center of the container:

CSS
.square {
   transform: translateZ(120px);
}

Now, let's change this center of focus via the perspective-origin property. I'll go with the top-left corner of the container, using the value top left (you can even use left top). Also, let's bring back translateZ(-500px):

CSS
.container {
   perspective-origin: top left;
}

.square {
   ...
   transform: translateZ(-500px);
}

Indeed, there's a visible difference now! The transformed elements clearly seem to approach the top-left corner of the container, all thanks to the new perspective-origin.

As before, let's see what happens when we translate the squares toward the viewer:

CSS
.square {
   transform: translateZ(120px);
}

Again, as you can see, the transformed elements seem to originate from the top-left corner of the container, and rightly so — that's our new perspective-origin.

Difference between perspective-origin and transform-origin

The difference between perspective-origin and a similarly named property, transform-origin, is that transform-origin is the hinging point at which the transform is applied whereas perspective-origin is the placement of the eye in the xy plane.

For example, when you rotate an element across the y-axis (imagine flipping a card):

  • transform-origin might be set to the left edge of the element and therefore cause the rotation to happen as if the element has a hinge on its left edge, much similar to a book.
  • perspective-origin might be set to the left of edge of the element and therefore cause the rotation to appear as if your eye has been placed at that point.

The following interactive example illustrates the difference between these properties. Click on the "Toggle" button to flip the card and witness the effect of transform-origin vs. perspective-origin:

transform-origin: left

perspective-origin: left

In the first case, transform-origin: left has been set on the yellow card (remember transform-origin is always set on the element to which a transform is applied). In the second case, perspective-origin: left has been set on the parent of the yellow card — which is simply the grey box.

  • In the case of transform-origin: left, when you press the "Toggle" button, you can clearly see that the rotation happens at the left edge of the yellow card — reminiscent of the fact that it is now the "hinging" point.
  • For perspective-origin: left, when you press the "Toggle" button, the rotation happens around the center since the transform-origin is situated at the center of the yellow card. However, at the end of the transition, the card is visible and that's because you're viewing it from the left edge.

Try combining both transform-origin and perspective-origin in the same example and see the effect it produces.

A quick experiment at home!

If this discussion of perspective-origin confuses you, I have an experiment that you can try right now at home and understand why the transform renders as it does in the second case above.

Take a small notebook and keep it in front of one of your eyes while the other is closed; this eye emulates the perspective-origin point.

  • First, align your eye with the center of the book and then rotate the book as shown above.
  • Now, align your eye with the left edge of the book and repeat the rotation. In the latter case, you'll be able to see some part of the book after the rotation, just as depicted in the second case above.

Bilal Adnan

Hi there! 👋 I'm the founder of Codeguage — basically the guy who's trying to make life easy for self-taught devs. You can follow me on LinkedIn or Medium to stay up-to-date with my conversations.