Two specific CSS selector-isms which will bite you in the rear

 



A small document describing two possible scenarios to find yourself in and wasting time on.

SELECTING THE FIRST ELEMENT OF ELEMENTS

Awhile ago I ran into a problem using :first-child with
document.querySelector. I have learned this selector literally means "select
the element if it is the first child. It is super important to emphasize
this, because if you have, for example:

  <body><h1>hi</h1><p>my name is l</p></body>

Your selector p:first-child will not match! For the simple reason that it is
not the first child of <body>
, <h1> is.

So how can we select the first child of a specific type? :first-of-type !

  document.querySelector('p') == document.querySelector('p:first-of-type')

In CSS files though, the former selects all <p> elements, whereas the
latter just selects the first.

QUERYSELECTOR DOES NOT SCOPE TO THE ELEMENT

It turns out when you do something like:

  // html: <div class="a"><div class="b"><div class="c"></div></div></div>
  const b = document.querySelector('.b');
  b.querySelector('.a .c');

What do you expect the result to be?

On my first and only try, I guessed it would not select anything. But no, it
does select .c
! This is because querySelector does not scope to the
element it's called from
! It scopes all selectors to :root, which is
<html>.

To scope the selector is very simple though: b.querySelector(':scope .a .c')
which would then return nothing as we expect.
 

Conclusion

Now you know CSS is even more broken than you originally knew :^).

Seriously though the semantics around selectors is so non-intuitive. Is there a better future for styling?

I think idea of a set of styles is useful, but anything else is not. The implicitness of cascading makes reasoning very, very hard.

Comments