I've always believed (although I now doubt the validity of these beliefs) that:
div.name
Was faster than:
.name
However I've read recently that most CSS selector engines read from right to left, in which case wouldn't the first example actually be slower? As the selector engine would simply find every element with a class of name, and then have to identify which of those were divs?
Which way do CSS selector engines read in general? Left to right or right to left? And if they generally read right to left could someone please offer me an explanation as to why (I can't see how it makes sense to read right to left in terms of a selector engine)?
However I've read recently that most CSS selector engines read from right to left, in which case wouldn't the first example actually be slower?
Which way to CSS selector engines read in general? Left to right or right to left? And if they generally read right to left could someone please offer me an explanation as to why (I can't see how it makes sense to read right to left in terms of a selector engine)?
Frankly, it's nigh impossible to tell which selector will be slower in a given browser, much less across browsers. Performance tends to fluctuate and be unpredictable, especially at such microscopic scales and with unpredictable document structures. Even if we talk about theoretical performance, it ultimately depends on the implementation.
Having said that, as shown in Boris Zbarsky's answer to this other question and in Guffa's answer to yours, a typical browser (this is currently true of all major layout engines) takes an element and evaluates all the candidate selectors to see which ones it matches, rather than finding a set of elements that match a given selector. This is a subtle but very important difference. Boris offers a technical explanation that's not only incredibly detailed, but also authoritative (as he works on Gecko, the engine used by Firefox), so I highly suggest reading it.
But I thought I should address what seems to be another concern in your question:
As the selector engine would simply find every element with a class of name, and then have to identify which of those were divs?
As well as Patrick McElhaney's comment:
The linked question explains why selectors are read right-to-left in general, so #foo ul.round.fancy li.current is read li.current, ul.round.fancy, #foo, but is it really read right-to-left within each element (.current, li, .fancy, .round, ul, #foo)? Should it be?
I have never implemented CSS, nor have I seen how other browsers implement it. We do know from the answers linked above that browsers use right-to-left matching to walk across combinators within selectors, such as the > combinators in this example:
section > div.second > div.third
If an element isn't a div.third, then there is no point checking if its parent is a div.second whose parent is a section.
However, I don't believe that this right-to-left order drills all the way down to the simple selector level. In other words, I don't believe that browsers use right-to-left evaluation for each part of a simple selector sequence (also known as a compound selector) within the right-to-left evaluation across a series of compound selectors separated by combinators.
For example, consider this contrived and highly exaggerated selector:
div.name[data-foo="bar"]:nth-child(5):hover::after
Now, there's no guarantee a browser will necessarily check these conditions for an element in the following order:
Is the pointer over this element?
Is this element the 5th child of its parent?
Does this element have a data-foo attribute with the value bar?
Does this element have a name class?
Is this a div element?
Nor would this selector, which is functionally identical to the above except with its simple selectors jumbled around, necessarily be evaluated in the following order:
div:hover[data-foo="bar"].name:nth-child(5)::after
Is this element the 5th child of its parent?
Does this element have a name class?
Does this element have a data-foo attribute with the value bar?
Is the pointer over this element?
Is this a div element?
There is simply no reason that such an order would be enforced for performance reasons. In fact, I'd think that performance would be enhanced by picking at certain kinds of simple selectors first, no matter where they are in a sequence. (You'll also notice that the ::after is not accounted for — that's because pseudo-elements are not simple selectors and never even enter into the matching equation.)
For example, it's very well-known that ID selectors are the fastest. Well, Boris says this in the last paragraph of his answer to the linked question:
Note also that there are other optimizations browsers already do to avoid even trying to match rules that definitely won't match. For example, if the rightmost selector has an id and that id doesn't match the element's id, then there will be no attempt to match that selector against that element at all in Gecko: the set of "selectors with IDs" that are attempted comes from a hashtable lookup on the element's ID. So this is 70% of the rules which have a pretty good chance of matching that still don't match after considering just the tag/class/id of the rightmost selector.
In other words, whether you have a selector that looks like this:
div#foo.bar:first-child
Or this:
div.bar:first-child#foo
Gecko will always check the ID and the class first, regardless of where it is positioned in the sequence. If the element doesn't have an ID and a class that matches the selector then it's instantly discarded. Pretty darn quick if you ask me.
That was just Gecko as an example. This may differ between implementations as well (e.g. Gecko and WebKit may do it differently from Trident or even Presto). There are strategies and approaches that are generally agreed upon by vendors, of course (there isn't likely to be a difference in checking IDs first), but the little details may differ.
The selector engine doesn't look for element to apply a rule, it looks for rules that apply to a specific element. Therefore it makes sense to read the selectors from right to left.
A selector like this:
div span.text a.demo
would make the selector engine do these checks to see if the selector applies to an element:
Is it an a element with the class demo?
Does it have an ancestor that is a span element with the class text?
Does that element have an ancestor that is a div element?
Related
How do I add arbitrary selectors in CSS rules?
For instance, say I want to make every item of the .effect class turn red if the user hovers over#target. How would I implement this? Is there a robust approach to this? I know about things like nesting .effect inside #target or using the sibling selectors ~ and +, but all of these rely on a certain way of structuring the HTML.
Is this possible at all? It seems like something relatively straight forward. If it's not possible, is there any reason it isn't?
I do not want to use Javascript.
No, you can't.
Don't expect it for the forseeable future either. Let's take a look why!
From the point of view of someone who works on a CSS engine, selectors are actually evaluated backwards. This is certainly a rather interesting and less known aspect of CSS; Whilst the CSS selector specification does not directly define the implementation behaviour, all selectors are defined with this in mind. No hierarchial/ 'structural' selector has been created which can arbitrarily jump around the DOM as that would cause major performance issues in comparison to what we have today.
So, for example, let's take the following selector:
#target:hover .effect
This requires that an element with a class of effect is a child (at any depth) of an element with an ID of target because the selector engine starts by matching elements with a class of effect first, then proceeds to work backwards, stepping up the DOM looking for a parent element with an ID of target next.
Jumping to the parent node is extremely fast. Evaluating this in the forward direction would involve testing all children of any element with an ID of target which is considerably more performance intensive.
This characteristic of CSS evaluation is naturally important for performance; at the worst case, the above selector will only bubble up to the root of the DOM, testing only a handful of elements along the way. The direct child selector, a > b, only tests the direct parent and then stops, for example.
'Baking' the structure of a selector
For even further performance, the structure of a selector is 'baked' into the DOM. There certainly isn't consensus on this, i.e. every CSS engine does it differently, but roughly when the DOM structure of a selector matches (i.e. we have found an element with a class of effect and any parent with an id of target) the selector is recorded as having matched in the DOM, regardless of the hover state on #target. When the hover state on #target changes, it then simply bumps all the selectors that are baked at the element - this may then trigger the whole selector to activate or deactivate. This way we're not constantly testing masses of elements when the mouse moves around, for example.
In short, none of this works either if it could arbritarily jump around the DOM. Elements entering/ leaving the DOM could affect selectors in entirely separate parts of the DOM, so the style engine would potentially be checking the entire DOM to keep this index up to date.
Partially loaded DOM
Also consider that we can test for elements before something, but not after (when evaluated backwards):
h1 + h2
h1 - h2 /* ..? Doesn't exist! */
This is because when we test this particular selector starting against a 'h2' element, the DOM following it might not actually be loaded yet. As soon as an element enters the DOM, either because it's just been parsed from the incoming HTML or it has been added via scripting, we begin checking for which selectors it matches. That means we can't depend on anything being available after the element in the raw HTML, so again this would also be a block for any arbritary DOM hopping.
In Summary
It's currently not possible and it's unlikely to be added any time soon because it invalidates multiple performance characteristics of CSS implementations. That's not to say that it won't be added however; the W3C does appreciate that hardware is getting ever more powerful, so there is always a point at which author convenience will win over implementation performance considerations.
So, putting this a little further into context of the question, take a look at this fiddle created by #Marvin to see what's currently possible with selectors today.
If I select it from behind, it would be
div:nth-last-child(-n+6) { background: #ff0000; }
If I do it from the front, it would be
div:nth-child(4) ~ div { background: #ff0000; }
Both produce the same result.
Which should I choose?
In terms of memory usage, which one is heavier on the browser - is the latter heavier because it has to find every divs after the 4th one?
In terms of browser compatibility, which one has more support - does the latter have more browser supports (IE8 only partially support :nth-last-child)?
Is there anything else to consider?
In terms of memory usage, which one is heavier on the browser - is the latter heavier because it has to find every divs after the 4th one?
Who knows? You'd have to have access to the source code of any browser engine(s) you're interested in, and I wouldn't be surprised if it differed across browsers — it's an extremely low-level implementation detail. And even if you did have access to the source, this information wouldn't be useful to you unless you're a browser developer.
In terms of browser compatibility, which one has more support - does the latter have more browser supports (IE8 only partially support :nth-last-child)?
In terms of browser compatibility, they are completely identical. Internet Explorer 8 doesn't support :nth-last-child() at all. And there are no known versions of any browser that support either :nth-child() or :nth-last-child() but not both.
If you need IE8 support, this technique will let you match every div after the 4th one without using :nth-child() or :nth-last-child() — the only CSS3 selector that's used is the ~ combinator, which IE8 does support:
div:first-child + div + div + div ~ div
This assumes you have exactly 10 divs, but then so do the two selectors you propose.
Which should I choose?
Well, even if you can guarantee that there will only ever be exactly 10 divs, no more, no less and no other children, div:nth-last-child(-n+6) still makes more sense as it does exactly what is described: "match the last 6." div:nth-child(4) ~ div doesn't make it as obvious, since what it's really saying is "match any div after the 4th." It just happens to pick up 6 of them by coincidence.
It also carries less specificity, in case that's important.
Theoretically your first approach (from behind) would be "faster" as you do not nest selectors here as you do in second approach. However performance gain isn't anything worthy in such cases, browsers are "smart" enough to optimise it for you.
Think harder about your use case - which way it can evolve - do you really want to match 7 last rows or leave 3 first different, what should happen if you expand to 20 rows etc...
Rule of thumb - keep your code maintainable as the first goal, optimise only when needed, never do premature optimisations and do not think about it too much. Get your job done and move on :)
This question already has answers here:
What's the difference between an id and a class?
(17 answers)
Difference between id and class [duplicate]
(2 answers)
Closed 7 years ago.
I'm new to CSS, and after learning about ID selectors, the only difference between them and class selectors is the fact you can only have one specific id per element, whereas multiple elements can share the same class name. But then it's easy: name an element a class name that you won't use for any other element. So it seems in that sense, a class can be treated as an I.D.
I'm new to CSS, so I may be missing something here. What advantage do I get using an ID selector over a class selector in a particular case?
Thanks.
Here are a few reasons that come to mind:
Direct Linking.
You can link directly to a specific element on the page by adding the id to the end of the url. See this post for examples: Link to an element within the current page
Javascript Compatibility.
A lot of JS libraries utilize the differences between classes and IDs. For example, they will treat classes as an array of elements, assuming you want to iterate over all of the instances of that class. IDs on the other hand are assumed to be singular, and whatever functionality you are trying to achieve will look for only a single instance. This has minor (almost unnoticeable) performance benefits, but can also break many functions if not used correctly.
Specificity.
When targeting elements on a page, specificity always comes into play. Since IDs and classes have different weights, using them incorrectly can cause problems when you are trying to keep styles from over-writing each other. See here for more info: https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity
Browser Compatability.
While browsers are getting better at conforming to modern CSS standards, there are always going to be quirks. Not every selector works in every browser and some CSS tricks may break when your users visit your site using an old version of IE or some random build of Safari. That being said, IDs will always work, no matter what. This may not relate to your specific case, but could help prevent headaches down the road.
Best Practices/Readability.
Most importantly IMO, is the readability aspect. When looking over another developer's code, I assume when I see a class being specified in the CSS that whatever styles they have set will affect multiple areas of the page. This means I shouldn't just go changing things without further research. Opposite of that, if I see an ID being used, I can assume that any changes to that particular style will affect only that one area, and there shouldn't be any surprises for me down the road.
During my journey of self-teaching CSS, I came across the pseudo-selector :nth-child() (as well as its related selectors :nth-last-child() and :nth-of-type()).
I've studied it enough to understand the syntax and operation - but have yet to see any information about when and why it should be used.
From what I can tell from Google and Stack Overflow is that it's mainly used to stylize table rows and lists - but that seems too simple to be the only operation for a selector that can be so complex.
Am I missing out on something? Thanks in advance!
There Are Many Reasons ...
... as others have noted in comments. But you want some non-table or list reasons, so it seems.
Basic Idea
With these selectors, you are concerned about the ordering of sibling elements within the html itself for the selection (this is why they are so commonly used for tables and lists, because tr, td, and li elements are always siblings of one another in there respective place in tables and lists). Secondarily with these selectors you are concerned about being inclusive or exclusive of types of elements (hence the difference between :nth-child and :nth-of-type; and one common misconception is that these pseudo-classes can count by some .className, but they do not, they count by html element type: i.e. <div>, <li>, <span>, etc.). In general, they allow for selection of some things when the html is not able to be modified, or structure is variable, but you desire a consistent selector.
Some Scenarios
The "why" you might want to target these is what is limitless and I cannot speculate on.
Example 1, say you want to style the second to last element in a div, no matter what type it is (and dynamic html is being generated, so you don't even know for sure what element it may be), then your only way to access that element is :nth-last-child(2).
Example 2, say you want the third h3 inside a div. You have access to change styles but not html (so you cannot put a class on it and it does not have a class or id to target to). However, you know that this h3 is always the third one of its type in the html, though the number of other elements around it may vary. So h3:nth-of-type(3) allows you an ability to target that, an ability you would not have had otherwise.
I could give other scenarios (again, limitless), but if you stick with the concepts noted in "Basic Idea" you can perhaps see why they might be used.
That’s a pretty major difference. This
is why it’s always strongly
recommended that you use unitless
numbers if you’re going to set a
line-height on something like the
html or body elements, or indeed on
any element that is going to have
descendant elements.
http://meyerweb.com/eric/thoughts/2006/02/08/unitless-line-heights/
So now i will follow this suggestion. but is there any cons to follow this?
but is there any cons to follow this?
I can't see any. The behaviour he describes:
So what’s the difference? When you define a united value, like 1em, you’re setting things up to pass along the computed result to any descendants. For example, suppose the following CSS is applied to a document containing the following markup fragment:
Is usually what you want. There may be exceptions with some typographically very specialized designs with fixed line-height s to achieve some sort of effects. But that will be rare, and you'll recognize them when you see them.