CSS child selector performance vs. class bloat

2019-02-03 03:38发布

问题:

I'm trying to learn to write more efficient CSS, particularly as I'm working with a fairly complex site that needs to render fast.

I'm used to having a lot of this in my HTML/CSS (mainly because I like the readability):

.spotlight {}
.spotlight ul {}
.spotlight ul li {}
.spotlight ul li a {color: #333;}

<div class="spotlight">
  <ul>
    <li><a href="">link</a></li>
    <li><a href="">link</a></li>
    <li><a href="">link</a></li>
  </ul>
</div>

I now understand that browsers run the CSS rule matching process from right to left, meaning that the <a> element in the last CSS rule above would first match every link on the page, leading to performance loss.

So from what I gather, the browser-friendly solution would be to be more specific, and use, for example:

.spotlight {}
.spotlight-link {color: #333;}

    <div class="spotlight">
      <ul>
        <li><a class="spotlight-link" href="">link</a></li>
        <li><a class="spotlight-link" href="">link</a></li>
        <li><a class="spotlight-link" href="">link</a></li>
      </ul>
    </div>

(assuming I'm using inheritance where possible but often still need specific control over the last element down the tree)

What is causing me doubt is: doesn't all the extra HTML bloat from printing class names on elements throughout the page negate performance gains made from avoiding nested CSS child selectors? I'm used to trying to write less HTML and this sort of goes against it. Any insight would be appreciated.

回答1:

You have to weigh it up. Adding a class to every anchor is ridiculous, the extra bloat in the HTML would massively offset the rendering time saved (which would be 1/10,000th of a bee's leg). Not to mention how hard your code would be to maintain.

You just need to stop using unnecessarily expensive selectors, for example

.spotlight ul li a

Can be written as

.spotlight a

If you keep on specifying a single class on the same elements in your HTML (like your second example), you'd probably be better off using a tag selector instead.

You also have to weigh up your time vs the browsers time. How much is it going to cost in your time to save a few nanoseconds on each page load? In all honestly, it's not really worth it.

Also, making your CSS structure match your HTML structure negates the point of CSS - if the HTML changes, you need to change your CSS. So you always want your selectors to be as unspecific as possible.

But there is no right or wrong answer here.



回答2:

The best trade-off, I think, is using the child combinator > for elements that are repeated many times and using classes when things start to become too nested.

Bending the Rules of BEM

The above article strikes the perfect balance, I think, considering our options.

Using SCSS, which ought to be obligatory nowadays, my navigation menus usually look like this (which is definitely the most I will ever nest stuff):

.header__nav {
  > ul {
    > li {
      > a {}
    }
  }
}