A Little Reminder That Pseudo Elements are Children, Kinda.

grid.png

Here’s a container with some child elements:

<div class="container">
  <div>item</div>
  <div>item</div>
  <div>item</div>
</div>

If I do:

.container::before {
  content: "x"
}

I’m essentially doing:

<div class="container">
  [[[ ::before psuedo-element here ]]]
  <div>item</div>
  <div>item</div>
  <div>item</div>
</div>

Which will behave just like a child element mostly. One tricky thing is that no selector selects it other than the one you used to create it (or a similar selector that is literally a ::before or ::after that ends up in the same place).

To illustrate, say I set up that container to be a 2×3 grid and make each item a kind of pillbox design:

.container {
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-gap: 0.5rem;
}

.container > * {
  background: darkgray;
  border-radius: 4px;
  padding: 0.5rem;
}

Without the pseudo-element, that would be like this:

Six items in a clean two-by-two grid

If I add that pseudo-element selector as above, I’d get this:

Six items in a two-by-two grid, but with a seventh item at the beginning, pushing elements over by one

It makes sense, but it can also come as a surprise. Pseudo-elements are often decorative (they should pretty much only be decorative), so having it participate in a content grid just feels weird.

Notice that the .container > * selector didn’t pick it up and make it darkgray because you can’t select a pseudo-element that way. That’s another minor gotcha.

In my day-to-day, I find pseudo-elements are typically absolutely-positioned to do something decorative — so, if you had:

.container::before {
  content: "";
  position: absolute;
  /* Do something decorative */
}

…you probably wouldn’t even notice. Technically, the pseudo-element is still a child, so it’s still in there doing its thing, but isn’t participating in the grid. This isn’t unique to CSS Grid either. For instance, you’ll find by using flexbox that your pseudo-element becomes a flex item. You’re free to float your pseudo-element or do any other sort of layout with it as well.

DevTools makes it fairly clear that it is in the DOM like a child element:

DevTools with a ::before element selected

There are a couple more gotchas!

One is :nth-child(). You’d think that if pseduo-elements are actually children, they would effect :nth-child() calculations, but they don’t. That means doing something like this:

.container > :nth-child(2) {
  background: red;
}

…is going to select the same element whether or not there is a ::before pseudo-element or not. The same is true for ::after and :nth-last-child and friends. That’s why I put “kinda” in the title. If pseudo-elements were exactly like child elements, they would affect these selectors.

Another gotcha is that you can’t select a pseudo-element in JavaScript like you could a regular child element. document.querySelector(".container::before"); is going to return null. If the reason you are trying to get your hands on the pseudo-element in JavaScript is to see its styles, you can do that with a little CSSOM magic:

const styles = window.getComputedStyle(
  document.querySelector('.container'),
  '::before'
);
console.log(styles.content); // "x"
console.log(styles.color); // rgb(255, 0, 0)
console.log(styles.getPropertyValue('color'); // rgb(255, 0, 0)

Have you run into any gotchas with pseudo-elements?

The post A Little Reminder That Pseudo Elements are Children, Kinda. appeared first on CSS-Tricks.


This post was originally posted here

Check out our Starter Sites built with #ToolWeLove including Toolset, Elementor Pro, and Astra Pro.

 

Share this page

Share on facebook
Share on google
Share on twitter
Share on linkedin
Share on email

Embrace the Political

The tech industry has long held the belief that technology is apolitical. People are flawed, but the machines? They are neutral. They are pure. This

Read More »
sendinblue