Lessons Learned - CSS Pseudo Elements

Lessons Learned - CSS Pseudo Elements

What is the Stacking Context?

I have been working on a variety of link effects that use transitions on the ::before pseudo-element. The general approach is to have an absolutely positioned ::before element with a background transition into the link using translate, scale, skew, and/or opacity. For example:

css
1.link {
2	position: relative; /* need this for ::before absolute to work */
3	display: inline-block;
4	overflow: hidden; 
5	&::before {
6		content: "";
7		position: absolute;
8		top: 0; bottom: 0; left: 0; right: 0;
9		background-color: LightSteelBlue;
10		transition: transform .3s ease;
11		/* base state */
12		transform: translateY(100%);
13	}
14	/* hover state */
15	&:hover {
16		&::before {
17			transform: translateY(0);
18		}
19	}
20}

Link to an example in CodePen

If you try this, you will notice that we have a layering problem. The ::before (pseudo) element appears over the link. This seems counterintuitive to me. The name ::before suggests that it comes before the link. But layering is a mystery, and I know how to solve the problem: give ::before a negative z-index.

css
1.link {
2	...
3	&::before {
4		...
5		z-index: -1;
6	}
7	...
8}

I am so brilliant. Now, my transformations work. You can see my brilliance in this pen.

Or was I "so brilliant"? The transformations no longer appear when I put these fancy links on parent elements with a background color. You can see this by changing the --pageBG variable from transparent to something like FloralWhite in the pen.

I spent hours figuring out why adding a background would cause a problem. All the posts I read did not mention the issue, and StackOverflow offered no help. Finally, I stumbled on this MDN article on "Stacking Context" and it became clear that my understanding of layering (stacking) was elementary. In essence, z-index is a relative value (relative within its stacking context). My knowledge was really lacking (and continues to be) where these stacking contexts exist. I highly recommend reading "Stacking Context" and be sure to look at the related to articles that go into more detail.

So, how does this help us with our fancy :hover effect failing when we place the link on a parent with a background?

Long story short, we must create a new stacking context for the parent. From the MDN article, one way to create a new context is to set the parent's position to relative and give the parent a z-index.

Element with a position value absolute or relative and z-index value other than auto.

Another is to use the `isolation` css property...

Element with an isolation value isolate.

Here is the corrected Pen with the new stacking context applied to the parent of the links.

Here is the link hover effect that I was originally creating. Note: It is not working. You must add the stacking context to make it work with the background. I leave this update as a test of your understanding. :-)

popularity
On Fire
posted
Jan. 27, 2025