So I've recently been doing a lot of work with Concrete5. I noticed, however, that the default theme has many CSS rules which are defined like so:
#page #central #sidebar p{line-height:24px}
Since "sidebar" is an ID there should only be one "sidebar" on the entire page (assuming that it validates, which I'm taking care it does). Therefore if #sidebar
is in #page #central
, it should always be in #page #central
. No matter what. On every page.
By this logic, the following rule does the exact same thing:
#sidebar p{line-height:24px}
Testing this, sure enough, it worked. So my question is- which would have better performance? Is there a speed-related reason that the Concrete5 team went with the longer specification, or was it merely to help future developers locate the #sidebar
div? I can see arguments for it being faster in either case.
If case 1 is faster (#page #central #sidebar
):
If the browser uses a breadth-first-search algorithm to locate the proper DOM element then finding #sidebar
would involve searching the second tier of EVERY DOM element that had children before it reached the third tier, at which point it would still have several elements it looks at before finding #sidebar
. By specifying the elements in this way the breadth-first-search would recognize #page
and know that it only needs to continue searching within this element, rather than continuing with the entire DOM.
If case 2 is faster (#sidebar
):
If the browser searches the entire document in the order it's written, rather th开发者_StackOverflowan treating the DOM like a tree, then it would be performing a single linear search rather than three linear searches. In fact, even in the best-case scenario where it's smart enough to recognize the start and end points of the previously found DOM element (essentially a depth-first-search), it would still have to read just as many lines of code in a linear search - first it would read until it found #page
, then it would start reading from the start of #page
until it found #center
, then it would read from the start of #center
until it found #sidebar
. The only difference then would be the slight amount of overhead involved in switching from one search to another
Short story: the more of anything you use, the slower it is to parse.
An ID is always unique, so you should only ever use one; but even with classes, specifying any other elements or criteria is always going to be slower.
http://css-tricks.com/efficiently-rendering-css/
That article goes far more in depth into exactly what you are asking about.
AFAIK there is no feasible way of testing the speed of browsers CSS matching algorithm, and the differences between #page #central #sidebar
and #sidebar
as far as speed is concerned is so negligible that it's not worth worrying about.
What is worth worrying about is the difference in specificity.
Sometimes it's worth adding an extra id/class/element to a selector to make sure the style doesn't get overwritten by mistake with a simple selector later on in the cascade.
#page #central #sidebar p
has a specificity of 3-0-1, while #sidebar p
has a specificity of 1-0-1, which means that #page #central #sidebar p
will take precedence.
Additionally, you mentioned:
...if #sidebar is in #page #central, it should always be in #page #central. No matter what. On every page.
This is very much not the case, and is important to understand why. Just because an id
is unique, does not mean that it must follow the exact same page structure on every page.
For example: a popular content management system (Drupal) allows the developer to specify rules for the placement of blocks on differing areas of different pages. I may want the #search-block
to be in the #header
on the homepage and then in the #sidebar
in all other pages. using a more specific selector would allow me to give the #search-block
different styles depending on what its parent containers are.
Performance issues aside, these don't always translate to the same thing.
#header {
background: blue;
}
#home #header {
background: red;
}
This is a perfectly valid use of the cascade to make one page appear different to another. I use this pattern all the time, usually because I assign class
or id
to my body
element, as a hook for CSS and JavaScript.
I don't know about performance, nor do I care, but putting multiple ID selectors together certainly means differently from using just one ID selector, and I'm pretty sure people don't chain selectors like that for performance reasons more than anything else.
#page #central #sidebar p
This only finds p
in #sidebar
if #sidebar
is in #central
which is inside #page
. Therefore it won't find these #sidebar
s:
<body>
<div id="sidebar"></div>
</body>
<body>
<div id="page">
<div id="sidebar"></div>
</div>
</body>
<body>
<div id="central">
<div id="sidebar"></div>
</div>
</body>
Again, not sure about performance, but of course the browser has to do more work here because it has to check the DOM hierarchy for each element as it parses this selector from right to left. It's for a real reason; if your CSS says to style #sidebar
such and such only if it's found in #page #central
, the browser is going to have to do those checks before attempting to apply styles.
#sidebar p
This finds p
in #sidebar
, wherever in the DOM #sidebar
may be located.
Also, maybe I misread your question, but regarding this:
Since "sidebar" is an ID there should only be one "sidebar" on the entire page (assuming that it validates, which I'm taking care it does). Therefore if
#sidebar
is in#page #central
, it should always be in#page #central
. No matter what. On every page.
No, not always. You could place #sidebar
anywhere, it's just that the selector with all three IDs picks up #sidebar
if and only if it lives in #page #central
. The only way to satisfy your assumption is to ensure your markup is structured as such. Your styles can't and won't know about your markup, especially not if it's being used to style multiple pages across a site.
With that said, if you can ensure your markup always contains #page #central #sidebar
in that structure, then there's no problem with selecting #sidebar
alone. My point is that different selectors mean different things and you don't just pick one or the other for performance reasons — more often that not it's beyond that.
精彩评论