I recently came across this CSS selector while trying to find a way to easily space out major blog elements such as paragraphs and images. An example of its use would be something like this:
.post *+* {margin-top: 15px;}
/* or... */
.post > *+* {margin-top: 15px;}
/* if you don't want the margin to apply to nested elements */
At first glance, it seemed pretty useful. So my question is: What downsides are there to using these selectors?
Specifically:
What's the browser support like for this?
Are there any cases you wouldn't want an even margin spacing between elements in an article and if not, is it easier to declare this first and then overwrite or simply declare each element individually?
Does this have performance issues since you're selecting everything twice?
What's the browser support like for this?
Basically, IE7+ and any other modern browser.
There may be corner cases for each browser depending on what elements are actually being selected or queried with the sibling combinator +, but I wouldn't worry about those as much as the fact that the margin is being applied to just about any element that's a sibling for no practical reason.
Are there any cases you wouldn't want an even margin spacing between elements in an article and if not, is it easier to declare this first and then overwrite or simply declare each element individually?
It does seem pretty useful at first glance, but if you think about it, it'll probably be a much better idea to be more specific about what to apply the margin to. This is one rule that I can imagine will be overridden many, many times throughout the rest of the stylesheet by other specific selectors, making it quite redundant and even undesired in many cases. I can't think of any real-world use for a rule like your example.
Bear in mind that, in this specific case, vertical margins will collapse, so you only need to define vertical margins for a set of elements without having to resort to applying margin-top exclusively to all of an element's following siblings.
Does this have performance issues since you're selecting everything twice?
Actually, it's not selecting everything twice. The browser only looks at each element once, then determines whether each element follows another one under the same parent element. It doesn't care what kind of element it follows, as long as it follows another. It doesn't go around selecting every element again then compare to see if they're siblings of each other.
Now, people say that using the universal selector * in conjunction with just about any combinator causes rendering performance catastrophes, so people say that this kind of stuff should be avoided at all costs. But this stuff is hardly important at all (honestly, a selector like * + * is only a few microseconds slower than p + p), so you really don't need to worry about it. Consider the utility of the CSS rule itself first, then decide whether you really need the rule based on that.
Now with all that said (it's getting pretty late here), I would probably have rewritten the example like this, based on what I said above regarding collapsing margins:
.post > * { margin: 15px 0; }
It's probably only worth replacing the * with p if you know that the only children you want to space out are paragraphs:
.post > p { margin: 15px 0; }
Or any paragraphs within .post for that matter (e.g. within blockquotes):
.post p { margin: 15px 0; }
(* being used with the descendant selector is fair game, I'll admit; the child combinator, on the other hand, is limited to only one level of nesting, so for anyone obsessing about performance, this won't hurt at all.)
It's called the "Sibling Selector".
According to SitePoint, it's supported in all recent browsers and in IE8+. IE7 has a few limitations explained on the SitePoint page, but will mostly work as well.
It's defined in the CSS2 spec.
About the performance: a lot of CSS is overriding other selectors. That's part of the cascading nature of it. Also, performance varies so much between render engines that it's not practical to worry about performance when it comes to CSS.
You should also consider IE7 bug related to ignoring adjacent-sibling combinator (as well as :first-child pseudoclass) if HTML comment is in place of where IE7 expects to see an element. There is a workaround that removes comments as DOM nodes after page is loaded in IE7.
Related
Does the star selector in CSS affect page rendering performance?
Are there any caveats using it?
* {
margin:0;
padding:0;
}
When it comes to performance, Steve Souders is the man:
Performance Impact of CSS Selectors
Simplifying CSS Selectors
Shameless quote from one of the reports:
The key to optimizing CSS selectors is
to focus on the rightmost selector,
also called the key selector
(coincidence?). Here’s a much more
expensive selector: A.class0007 * {}.
Although this selector might look
simpler, it’s more expensive for the
browser to match. Because the browser
moves right to left, it starts by
checking all the elements that match
the key selector, “*“. This means the
browser must try to match this
selector against all elements in the
page.
[bold emphasis mine]
For some properties using * can produce unexpected results.
* { color: blue }
li { color: red }
Now given <li><i>text</i></li>, the text will be blue!
One view is that it's not so much that the * is a performance problem, it's that good old favourite - there's an IE issue with it. It affects IE 5, 5.5 and 6 as well as Macintosh variants. Basically, there is something called the HTML star selector bug which applies as follows:
* html
This should be interpreted as no element match because html is root and cannot be a child element. IE interprets this as html.
* * body
Again, should match to no element because body cannot be a grandchild element - even though it is a child element of HTML. IE interprets this as * body.
* html body
This should match no element, but IE interprets this as html body.
The performance side is usually treated that applying * only means that the style applies to every element in a page. I rarely find that this is an issue in its own right - the point at which it would become an issue means that you've probably got way too much markup in there anyway. Similarly, as it applies to everything, it means you need to increase your code to cope with elements that shouldn't have that style. As with everything else, it's up to you to decide what the tradeoffs and balance should be.
Since I'm using the exact same rule in every of my projects and none have serious perfomance issues, I'd say: No, not as far as I know.
So, I'm not sure what I've stumbled upon here. I'm working with some CSS and I know it is common place to do something like this:
#content{
/* Style the content div. */
}
#content p{
/* Style all p elements in the content div. */
}
I'd like to give one specific p element a float:right style. Only one such p element will occur in the content element. Naturally, I'd just give this element an id, but then I had the idea to do it this way:
#content #right_floating_p{
float:right;
}
This works when I run the code, but I was wondering about best practice and whether or not this actually does anything scope wise. I could just as easily define a separate id for right_floating_p, but to me it feels natural that it should be defined with the content id because it will be used only on one p element inside the content element.
If anyone has any information about this syntax, please let me know. Thanks!
My recommendation is to only include the last ID. This is fairly standard separation of concerns. What if you want to change the first ID #content, but the last one #right_floating_p still makes sense and shouldn't change? There is more room for error if you specify something unnecessarily.
Other reasons this is good:
Smaller, faster (but barely) download size for your users.
More readable, in my opinion.
Faster (but barely) performance.
Over-qualifying tags is bad practice in general, as far as performance goes. Browsers read your selectors from right-to-left, by the time it interprets your #content selector, that information is pointless. My advice is to not trust that the browser will optimize for this.
Alvaro nailed it in his comment above.
The id must be unique on the page, but not necessarily across the whole site. So, for instance, if you had the #right_floating_p element on every page, but it had a #content element as an ancestor only on a certain page where you wanted it styled differently, then you'd want to use the #content #right_floating_p selector to apply the context-specific style.
I would suggest only using the most precise selector as you can, not only for readability and file size, but also for specificity.
CSS selectors have a specificity to them, so if you were to override it later (such as with a media query), the more specific selector will override the less specific one.
#content #right_floating_p {
color: red;
}
div #right_floating_p {
color: green; /* Will not apply, as it's less specific */
}
p {
color: black; /* Even less specific */
}
It will work having the first selector, but it's not necessary.
When I studied front end dev at the university a few years ago, our teacher taught us to always provide the full (almost) parental
DOM hierarchy of the targeted element within our CSS selectors.
So in our web projects we had to write selectors like:
div#container div#content p.bread a.external { }
instead of just:
#container #content .bread .external { }
or (I see the disadvantages with class conflicts that may occur here)
.external { }
I personally write my selectors like
#container #content p.bread a.external {}
until I recently read an article saying that it should be avoided (but with no obvious reason why) and another article saying the same but that one was intended for jQuery selectors.
Was my teacher wrong and what is the right (fastest to parse and with most support) way of writing CSS selectors?
Practically speaking, you should use the least specific selectors you can.
div#container div#content p.bread a.external { } is a very, very specific selector. It is unnecessarily specific. There can only be one #content element, and it will surely always be within #container.
Write general rules. Don't attempt to target the precise DOM element. If a.external will capture the set of elements you want, use that. Otherwise you'll end up having to write p.bread a.external, p.potato a.external, p.olive a.external, etc, etc.
The difference in performance will be minimal. The benefits of general, reusable rules are large.
My 2 cents
Specific enough to target only what needs targeting (as others have said) is the general rule.
I agree with lonesomeday that "difference in performance will be minimal," but every added element in the chain is one more check to be done.
So Think About How to Reduce It
Are the ID's needed?
I disagree with Spudley that "there should never be a need to specify more than one ID in a selector." If your site is set up to have different display on different pages, and so #page1 #content is different than #page2 #content for displaying, then that is a legitimate case of two id's in one selector. However,
If all pages are #container #content then the drop the #container.
Also, if all p.bread elements are inside #content, then drop that selector also.
Are element names needed?
Is .bread intended to be used on anything other than a p? If not, drop the p.
Is .external intended to be used on anything other than an a (probably linking to an external site)? If not, drop the a.
Is the decedent relation of classes needed?
Is the .bread .external significant for display? That is, does .external exist outside of a .bread parent and does it change because of that parent? If so, then keep the relation. Otherwise, if the important thing is only the .external (no matter where it is), then that is the only selector you need.
Yes, your teacher was wrong.
From your example:
div#container div#content p.bread a.external { }
Given that an ID in a DOM document must be unique, there should never be a need to specify more than one ID in a selector. So the above selector that contains both #container and #content is immediately wrong simply by that criteria.
An ID is the most efficient and direct way to reference an element. Again, it's unique and instantly accessible, so there's no need to qualify it in any way, so adding div in front of either of the #container or #content here is redundant.
The other two parts of the selector p.bread and a.external are likely to be wrong, but it's not so clear-cut for these.
A selector only needs to specify the parts that are necessary to select the elements required and exclude any elements that are not required. In this example, if all .bread elements are ps or all .external elements are as then the element type a or p would be redundant and should be dropped. But without seeing your actual HTML content, it's not possible to be certain of this in the way that it is possible for the IDs because a given classname can legitimately be applied to multiple elements of multiple type.
Longer selectors such as div#container div#content p.bread a.external { } do take longer, yes. But rarely do they make any noticeable impact on the paint time.
Also, since IDs are (supposed to be) always unique, div#container and div#content should really just be #container and #content, respectively.
Elements are superfluous (or rather should be) when used with ID selectors (#), since your DOM should contain only unique IDs for elements.
It's also worth noting that classes should be used to bunch the styles of the same elements. In case you have two .bread elements in your DOM, but want them styled differently, you should consider using a different class name.
Both ways will work, and the impact on speed will probably be minimal. However there is no need to add the element to your rule, and I would encourage you not to as it helps your rules become more reusable - something you should always aim for.
You should also avoid using location to target elements. E.g. .sidebar h3. Instead, add a class to those h3s and target the class. This means you can reuse those styles you wrote elsewhere, just by adding the class. These are all concepts of Object Oriented CSS, and will help you write more efficient CSS by reducing the amount of duplicate code.
While trying to reduce the HTML size of a web page, I've come across suggestions by Google and the PageSpeed Firefox Add-On regading efficiency of CSS selectors that (almost) made me reconsider the changes:
http://code.google.com/intl/de-DE/speed/page-speed/docs/rendering.html#UseEfficientCSSSelectors
Specifically, descendant selectors are great for selecting a whole block (e.g. DIV) using an ID or CLASS attribute and then keeping all of its child elements free of CLASS/ID attributes. But if the order of traversal for applying the rules is as described by Google, they should not be used:
Descendant selectors are inefficient because, for each element that matches the key, the browser must also traverse up the DOM tree, evaluating every ancestor element until it finds a match or reaches the root element. The less specific the key, the greater the number of nodes that need to be evaluated.
I very much doubt that browsers use such an inefficient order of traversal, surely they would only process subtrees of elements that match the top selector component, i.e. in #foo span {...} only elements below #foo should be checked and not every single span. Can anyone who has looked at recent browser code confirm/deny this?
The second questionable suggestion is about overly qualified selectors:
ID selectors are unique by definition. Including tag or class qualifiers just adds redundant information that needs to be evaluated needlessly.
If ID selectors are unique by definition, why would browsers need to check the redundant information? I know that they do because for example,
div#foo { color: black; }
#foo { color: white; }
will result in black text in a <div id=foo>, but a) it should not be done(? W3C reference needed) and b) I don't see why it would be noticeably slower when it results in a simple O(1) check of the element's tag name.
Can anyone on good terms with modern browsers' source code shed some light on these claims? Since most modern sites use descendant selectors (including SO) and they have clear advantages, I'd very much like to use them...
Edit:
I've experimented a bit with generated pages and it seems that the browsers' handling of descendant selectors is indeed pitiful:
A page consisting of (abbreviated):
#top a {text-decoration: none;}
#foo1 a.foo {color: red;}
#foo2 a.foo {color: red;}
[... repeated 10000 times]
<body id=top>
<div>...[nested 50 times]<a href=foo>bla</a></div>[...]
[previous line repeated 10000 times]
(basically 10000 lines with 50 nested divs each to traverse till the root node and 1 selector that matches out of 10000)
loads and renders (time till window.onload() executes) in 2.2 seconds using Safari 5 and just under 10 seconds with Firefox 3.6.10.
When the .foo class selector is removed from the non-applying rules, the page takes around 200 seconds with Safari 5 and 96 seconds with Firefox 3.6.10. This illustrates how badly the descendant selectors are implemented (in that case, each of the 10000 rules probably causes a traversal till #top, where the rule fails).
How do child selectors fare? #foo > span > div > div > div > div > div a {color: red;} (also never matches but forces traversal of 6 parent nodes) takes 27 seconds with Safari 5 and 31 seconds with Firefox 3.6.10.
Conclusion
Descendant and child selectors both suck currently on major browsers. It's still better to add ugly class/id attributes to all your styled tags if you care about speed, at least for very common HTML tags (such as a, img, div etc.).
Have a look at this recent post by Jonathan Snook: http://snook.ca/archives/html_and_css/css-parent-selectors
You'll see how browsers evaluate expressions and the reasoning behind why certain selectors are inefficient.
A relevant quote from the post:
CSS gets evaluated from right to left.
To determine whether a CSS rule
applies to a particular element, it
starts from the right of the rule and
works it's way left.
If you have a rule like body
div#content p { color: #003366; } then
for every element—as it gets rendered
to the page—it'll first ask if it's a
paragraph element. If it is, it'll
work its way up the DOM and ask if
it's a div with an ID of content. If
it finds what it's looking for, it'll
continue its way up the DOM until it
reaches the body.
By working right to left, the browser
can determine whether a rule applies
to this particular element that it is
trying to paint to the viewport much
faster. To determine which rule is
more or less performant, you need to
figure out how many nodes need to be
evaluated to determine whether a style
can be applied to an element.
So, I was wondering about the following: I have some main content div and a sidebar div and the CSS looks as follows:
.main{
width: 400px;
height: 300px
}
.sidebar{
width: 100px;
height: 300px;
}
I will not include now all the floating properties, since I am only interested in the following:
If I have a p element in both of them and I want them to have different styles, shall I give the paragraphs different classes or shall I define the style for them like this:
.main p{
color: blue;
text-align: right;
font-family: ...
}
And then for .sidebar p I would define something else...
The alternative would be to define a class p.myclass and define the style there.
I am trying to understand what a better practice is. Obviously I need less markup if I have 30 p elements in one of the elements with the first method, since I would have to give them all a class. On the other hand, I create CSS that I can only "use" for that parent element, instead of having a general definition that I can apply in more places in the site...
I noticed that in a lot of "big" websites, almost every single html element has its own class...
Any ideas?
I would definitely go ahead with the containment selector in the case you give. Fewer spurious classes in the markup is easier to maintain, and the rule ‘.main p’ says clearly what it does. Use your judgement to whether more complicated cases are still clear.
Note that ‘.main p’ selects all descendent paragraphs and not just direct children, which may or may not be what you want; accidentally-nested descendant matches are a potential source of bugs (especially for cumulative properties like relative font size). If you want only children to be selected you need ‘.main>p’, which unfortunately does not work in IE6.
This is one reason why many sites go crazy with the classnames: the more involved selectors that could otherwise be used to pick out elements without a classname, tend not to work in IE.
I vote for .main p and .sidebar p because:
It most clearly expresses your intention, as you're expressing it in English
It reduces the number of explicit classes you need in your HTML
If you change your mind later and want an explicit paragraph class with that style you can just add it: .main p, p.foo
In my opinion using nested selectors [ parent child relations ] will be harder to read and maintainable.
Evdn if the design changes in a frequent manner CSS should be less affected by that. So styling individual element will be easier in the case of maintainability.
If the element is going to exist in a predictable location then you can style it based on a parent element.
The major drawback of styling by class on each individual element is the bloat: If you have many of these elements, the CSS attributes will become a noticeable percentage of the transferred bytes. Especially for large documents, saving a couple of KB in the download can count. Even more so with AJAX requests or IE where parsing innerHTML is extremely slow.