z-index and transform

code • January 1, 2014

I knew that I wanted to code out the Dribbble shot END by Catt as a single element. I planned on using the main element for the text and pseudo elements to create the tails of the ribbon.

See the Pen END by Catt by Katy DeCorah (@katydecorah) on CodePen

Ribbon diagram

In making all this happen, I was presented with of couple challenges.

  1. Give the ribbon tail a shadow without adding extra elements.
  2. Preserve the stacking order on transform.

Give the ribbon tail a shadow

First, I created a triangle by manipulating the border properties to recreate the shadow effect of the ribbon. It worked, but it didn’t match up perfectly.

Ribbon tail with triangles with opacity Ribbon tail with triangles

And then, it came to me… a trapezoid!

Ribbon tail with trapezoids with opacity Ribbon tail with trapezoids

The trapezoid fit perfectly. I also used a variable $ribbonSize to keep the ribbon tails in proportion with the shadow. In doing so, the ribbon became scalable!

Preserve the stacking order on transform

Before this project, I noticed issues in preserving the stacking order, z-index, of elements once a transform is introduced. Until now, I didn’t know how to remedy it, so I avoided it.

Once I added transform to the main element, the pseudo elements appeared to disregard the z-index: -1 rule and sat on top of the main element.

Ribbon transformed out of stacking order

Through research, I dove into the situation of what takes place between stacking orders and transforms. I learned that once transformed, an element needs to play by 3D rules. Without specifying the transform-style, I was technically still in flat mode.

If flattened, the children will not exist on their own in the 3D-space. transform-style by MDN

To allow the children to exist on their own, I needed to pepper in a couple more properties. First, I told my main element to preserve-3d.

.ribbon {
  ... transform-style: preserve-3d;

Next, I controlled the stacking order of the pseudo elements through translateZ. Think of translateZ as the 3D version of z-index.

.ribbon {
  ... transform-style: preserve-3d;
.ribbon:after {
  ... transform: translateZ(-1em);

After adding these properties, my ribbon tails popped back into place behind the ribbon.

Below is a playground I created to test translateZ.

See the Pen z-index & transform by Katy DeCorah (@katydecorah) on CodePen

Keep reading code