4

I can write the CSS selector using the child combinator > or just a space indicating any descendant. For example, I have this HTML code:

<span id='test'>
    <a href="#">Hello</a>
</span>

And I can write my CSS code in the following two ways:

#test > a {
    ...
}

or

#test a {
    ...
}

What is the best way, regarding the performance, to write the following CSS code?

Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
mikelplhts
  • 1,181
  • 3
  • 11
  • 32
  • `#test a` is a descendant selector (that is: a child, or a child of a child, etc.) and `#test > a` is a child selector (i.e. direct descendant)... they aren't both same so just use one of them as per needed. – Anonymous Jan 09 '16 at 16:03
  • It doesn't matter. Use the one that works, and is easiest to write, understand, and maintain. Why did you think it might matter? –  Jan 09 '16 at 16:06
  • @torazaburo _Why did you think it might matter?_ Are you asking that to me or to the OP? anyway I was just trying to clear that both aren't same and have different propose so just like you said _use the one that works, and is easiest to write, understand, and maintain_ also that's just a comment not an answer :) – Anonymous Jan 09 '16 at 16:25
  • It was addressing the OP, sorry for not making that clear. –  Jan 09 '16 at 16:26
  • @torazaburo First of all I think that trying to improve their skills, it never hurts. However, in this case, it's pure curiosity. I usually use the `>` selector (when needed), but a colleague of mine pointed out to me that could lead compromising on speed even when using it makes no difference, as in the example. – mikelplhts Jan 09 '16 at 16:46
  • There are two kinds of performance questions. The first is, is A faster than B? The answer could be yes, no, maybe, don't know. The second, and much more important question, is is A faster enough than B to worry about?? The answer in the overwhelmingly majority of cases is "no". I'm a little puzzled by the apparent focus by people learning a language, whether it be CSS or JS, on performance. Both CSS and JS engines are so optimized at this point that it is very hard to try to outguess them. In general, performance issues are something to be addressed when performance problems arise. –  Jan 09 '16 at 17:08

2 Answers2

6

Browsers parse selectors from right to left.

Then if you use #test > a, for each a element in your page, the browser checks whether its parent has id="test".

But if you use #test a, for each a element in your page, the browser checks if some of its ancestors have id="test". There shouldn't be many of those elements in the document, so probably the browser will have to check all ancestors of each a.

I haven't done any tests, but I expect checking all ancestors is slower than checking only the parent.

So probably #test > a is faster.

Community
  • 1
  • 1
Oriol
  • 274,082
  • 63
  • 437
  • 513
  • 5
    Agree with your conclusion. Not to mention that the selectors actually *do different things*, so such a comparison is not always necessary. Plus, the difference in performance is negligible for most web pages. You would have to be dealing with thousands of elements to notice a performance difference. In the real world, there's nobody complaining about selector performance. But it's a common theme at conferences and in blogs. – Michael Benjamin Jan 09 '16 at 22:40
4

Please be aware that both selectors doesn't give you same output! In your example, it does.

But let's check the next HTML code, which contains two links.

<div id="test">
    <p> lorum ipsum <a href="#">here</a> dolor </p>
    <a href="#">read more</a>
</div>

There is a link between the text, and a link after the paragraph, to allow the user to read more text. (like on news sites).

If you use

#test a {
    ...
}

Then you will select both links.

If you use

#test > a {
    ...
}

it will only select the direct descendant link of #test, which is the read more-link ! That is because > is a child combinator. The link in the paragraph won't be selected.

Here below is a snippet to show you the difference.

#test a {
  color: red;
}
#test > a {
  font-weight: bold;
  font-size: 18px;
}
<div id="test">
  <p>lorum ipsum <a href="#">here</a> dolor</p>
  <a href="#">read more</a>
</div>

As you can see, the second CSS rule has only edited the first child <a> element (the "read more" link).

Now, back to your question about the performance in your situation: if you use both selector on the next HTML part

<div id="test">
    <a href="#">Hello</a>
</div>

Performance wise it's same here.

-- edit1: clarification of the above sentence --

When using a selector, it checks from right to left. In this situation, with one div in the body, and one link element inside that div, the performance is same. That is because when using #test > a, it checks for all links to see if the parent of it has id="test". It doesn't traverse the tree further.

When using #test a, it checks for all parents of the link element (till the root) to see if it has id="test". Since the div is already found at the first parent check in this situation, it doesn't have to traverse the tree further.

But in other situation, when the div isn't the only element in the document, it of course make a difference. You cannot compare the difference here because, as mentioned before, the results are different. Unless you ensure that there are no second-level links under the given div. Then, the use of > is faster of course.

-- end edit --

However, if the person extends the content of the above div, he/she may face an unexpected CSS styling.

But to know the overall performance, it really depends of what you want to achieve by CSS (style all links or only the first level ?) and the DOM tree (depth of the tree ?) in the div#tree.

KarelG
  • 5,176
  • 4
  • 33
  • 49
  • *The child combinator performs a BFS (=Breath First Search) on the first level only. Without that >, it checks the whole tree in that div instead.* So I guess what the OP would like to know is, does that make any meaningful difference in performance, to the extent that if I am sure there is only a child involved, that I should then take extra care to use `<` in order to avoid huge performance penalties? –  Jan 09 '16 at 16:09
  • Are you sure it's a BFS? Selectors are parsed right-to-left, not left-to-right. So with `#test > a` only the parent of each `a` is checked. With `#test a` it's all ancestors of each `a`. – Oriol Jan 09 '16 at 16:10
  • 4
    First, I don't understand why you would devote the first half of your post to explaining something the OP presumably already knows. Second, I don't understand what you mean when you say "Performance wise it's same here". No, I don't think it is. Then you go on to say something else that suggests that it's not the same. Is it the same or not? If not the same, how much not the same? –  Jan 09 '16 at 16:14
  • @torazaburo your remark is correct. I have added a clarification. Still, it's comparing apples and pears, unless you ensure that there is no second level links in that div. Then the situation is same. – KarelG Jan 09 '16 at 16:35