:nth-child() counts line breaks as spans in CSS

November 25, 2021 , I learned...

I was diddling around and working with this markup:

<h1>
  Hidd<span>e</span>n
  <br>
  Br<span>a</span>in
</h1>

I wanted to select the second <span> so, naturally:

.span:nth-child(2) { ... }

And gosh darn it was I surprised that my styles weren’t showing up! Making sure I had the syntax right, I went for:

.span:nth-child(1) { ... }

It worked! More head scratching. Hmm, OK, why not?

.span:nth-child(3) { ... }

By golly, not only did that work but it selected the second <span> in the process, giving me exactly what I had aimed for. CSS apparently selects <br> elements when counting :nth-child(). New to me!

And guess what? It worked when I put any dang element in place <br>. Everything, like <div>, <main>, <input>, <abbr>, <kbd>, you name it.

I can’t find anything in the Selectors Level 4 spec on the :nth-child() side of things. I also looked at the HTML Standard and came up empty on the <span> side of things. I even thought that perhaps it was just a bug with Safari, but it works across the board.

I dunno. Maybe I’m overlooking something obvious. But today I learned that :nth-child() counts all elements when it searches spans. I mean, look, it counts the only <span> inside an element when it’s the last child, like:

<!-- Not that you'd ever do this -->
<h1>
  Hidd<div>e</div>n
  <abbr></abbr>
  Br<span>a</span>in
</h1>