* { color:black; }
#content * { color:black; }
I'd say the first is VERY easy for a browser to paint... Or is that one shameful as well?

Stephanie (Sullivan) Rewis said on October 10, 2010

Thanks for writing the thoughts you explained to me on IM the other day. :) Great explanation! And yes, I've given up my desire (currently) for a parent selector. I'm also rethinking how I write CSS. OOCSS is looking better and better all the time.

Sean Curtis said on October 10, 2010

Why couldn't the parent selector work when the tag is closed like the :last-child one does in Safari/Chrome/Opera? Eg first P is rendered, 2nd one, third one with span, div is closed, checks for span/last-child/whatever-else, applies styles?

Jonathan Snook said on October 10, 2010

@Rudie: #content * is less efficient than *. The reason is because with just a plain *, only one element is evaluated to determine if it matches the selector. With #content *, every ancestor of the element being evaluated has to be checked to see if it has an ID of content applied to it.

@Sean Curtis: There are various ways it could decide to handle it, all with various pros and cons. It could not render the div until all child elements are loaded but that might mean seeing an empty page until the entire document loads. Or, it could wait until the closing element to decide before re-rendering the style but then you still have all the child elements to re-render. That isn't an issue that :last-child has, per se. At least, not on the same scale.

cooljaz124 said on October 10, 2010

Which will load faster - An HTML page with a .css or a page with all css implemented using Javascript/Jquery ?

Keith Clark said on October 10, 2010

Sean, having a parent selector would mean the child nodes would have to monitor their parents for a change to the DOM. What your suggesting would be ok for applying styles during page load but I don't think the initial load time is the big issue - the problem is recalculating styles when the browser needs to redraw the viewport - that's what killed IE's performance when using expressions.

It would be interesting to run speed tests on this stuff but I think it's beyond the scope of JavaScript - it would need to be done during the vendors build/test process.

Brendan Falkowski said on October 10, 2010

The static test renders using Safari/Mac in 5ms. Aside from the great test case for :last-child implementation, I'm not sure there is a great value in CSS performance optimization. Google Page Speed recommends avoiding descendent selectors which seems a little absurd. A robot would suggest using only ID selectors to eliminate specificity.

I'd be curious if 1000 adjacent selectors is slower than 1 extra HTTP request. That's an extreme case, but in the total page speed scheme isn't CSS the least important?

Jonathan Snook said on October 10, 2010

@COOLJAZ12: that depends on whether the JavaScript is applying the same CSS and selectors as there would've been in the beginning. It also depends on when you have to worry about render time. CSS will almost always be faster.

@Brendan Falkowski: It depends on what you're doing. The problem with complex rendering is that it can impact JavaScript performance. It can also affect rendering performance if you're making a lot of repetitive changesa€”say, with animations. Complex applications like Yahoo! Mail benefit from simplified selectors and improved rendering times because of the amount of work that is being done on the client. If you have a blog then it really isn't an issue because the page is rendered once, with few rules needing to get evaluated. Changing everything to ID or class selectors won't be worth the maintenance headache.

Dmitry Scriptin said on October 10, 2010

From the "philosophical" point of view, :parent selector breaks the concept of CSS in its' "Cascading" part. What :parent does is reversing the flow of rules: while everything go inside and down, it goes outside.

So, I think it's not only the question of performance.

Also I think that the someone's need for this selector is a consequence of his/her misunderstang of CSS basic ideas. We don't actually need this, we can handle everything without it. And it would be bette (IMO) to not have this selector to keep CSS, you know, pure.

Scott said on October 10, 2010

Actually given your explanation of descendent selectors, I don't see how a parent selector could be any worse.

Take '.module:has(span)' - when the browser gets to a span element, all it needs to do is search upwards through the current tree to find .module, same as with the descendent selector. If it finds .module then it can apply the styles to that element right away. Assuming you do not have anything more complex than that simple boolean selector, it should be exactly as fast (or slow) as descendent selectors.

That's not to say a parent selector is a good idea. Developers seem to be very keen to strip HTML to as bare bones as possible, while creating a horrid mess of CSS selectors. Usually adding one simple class can eradicate many lines of CSS.

Jonathan Snook said on October 10, 2010

Scott, the difference is that a descendant selector is only evaluated once when that element is inserted by going directly up the tree. A parent selector would need to be evaluated each and every time a child selector was added. And then once a parent selector was matched, each and every child element would need to be potentially re-rendered. That's a potential for magnitudes of difference when it comes to performance.

For example:

.module span would fail immediately on all of the P's. Only when it hit the span would it attempt to work its way linearly up the tree.

.module:has(span) can't render when .module renders, when it should. Instead, the P gets rendered and the styles on .module get re-evaluated (and fail). Note, we're now checking to see if a rule applies on two elements for every element inserted in the DOM. That's twice as many as before. Once we hit the span, any style on the span renders and then the .module is re-evaluated and then the styles on ALL of the child elements are re-evaluated and re-rendered because of inheritance.

Huge difference.

Arieh said on October 10, 2010

I disagree with your conclusion. Few reasons:
1. A language shouldn't be about performance. Performance is for developers to worry about.
2. The fact that the standard way of doing it is slow doesn't mean it's the way browsers do it. I'm pretty sure browsers can do smart evaluations of rules and determine what is the best way for evaluating them. For example - if a browser sees #content *, it could simply search that #content first. It's doable and feasible, and I doubt that with all the performance wars going on browsers aren't "cheating" a whole lot.

So my point is - CSS is always about how can you best describe the hierarchy of a page. It's up to the browser to worry about performance, and PageSpeed, although a nice tool, always yells at me for very generic uses. The amount of work it would take to add classes to very element I might use is simply non realistic.
As for the parent selector - I agree with Sccot, that it's much more probable that the reason is that it's upside down, and that's counter CSS (although as I understand cascading means that every rules that follows on the same element will cascade on the previous).

Paul D. said on October 10, 2010

I'm pretty sure Safari lead developer Dave Hyatt himself has said that performance issues make a parent selector unfeasible.

yves torres said on October 11, 2010

Totally agree with Arieh, working like this wouldn't be feasible, never mind bloating your html source into a big fast bastard child.

As long as you're not developing the next Yahoo Mail or an application of similar size and scope, I think it's pretty safe to disregard Google Page Speed's results.

Of course there are a few performance tweaks it suggests that do make sense and are easy to implement but other's are just doubtful.

I've got a question about serving gzipped content, is this unproblematic? I've had some bad experiences with caching content, which is a very annoying problem to have.


Remy Sharp said on October 11, 2010

Whilst I agree with everything you've said - and the performance and rendering demos are great - I don't think a parent selector is a lost cause.

Based on these demos, I can't see why E:parent wouldn't fit perfectly amongst the suite of CSS selectors.

Does it matter that it doesn't follow the "normal" CSS syntax style? I don't think it does. It still cascades, it would still have a specificity weight and I think it's long overdue - as per my post: http://remysharp.com/css-parent-selector/

Scott said on October 11, 2010

Jonathan, thanks for the explanation. You are of course right - once you match that parent you do need to re-evaluate the children.

However, there may be ways to mitigate performance hits - for example combining my and Arieh's suggestions and waiting until certain elements are completely loaded in the DOM before applying styles to their children.

Now when we encounter our .module element, we know the :has selector applies to it. We simply grab its entire HTML contents before applying the CSS. If we find a span along the way, we know to apply those styles. We can think of it like adding a .containsSpan class, in the same way you could think of :nth-child(even) would add .even to alternate elements.

I guess this only works for elements further down the DOM, containing fewer elements. If the selector is applied to the body tag the performance hit is going to return.

Brendan Falkowski said on October 11, 2010

@ Jonathan Snook I can see the application vs. blog angle making a difference to some degree. Rails apps using the domain.com/#/action/name pattern as a single-page controller would naturally ID elements that change the DOM asynchronously. There isn't any extra work to slim the CSS selectors and it helps human readability too.

Factoring JS and DOM manipulation really depends on whether the inactive elements are removed or just hidden. Rendering a new interface (even without a preloaded DOM) would still be much faster than a standard AJAX request I think.

I don't doubt at Yahoo! Mail's DOM complexity the difference is visible. For most sites I'd bet the incremental upgrades in browser engines provide more enhancement than language optimization though. JS has been 1-2x faster with each release.

Jon Raasch said on October 11, 2010

Hey thanks this was a really interesting read, I really like posts that get down to the "why" as opposed to the "how" (or the "do this because I said so").

Kenneth said on October 12, 2010

Thanks, this was nicely explained.

I'm surprised this is blocked on performance grounds though. I can do plenty of CSS that slows my browser down. It's the clever developer that chooses the right tools for the right job. If you're concerned with page speed, it's up to you to re-evaluate your selectors.

It feels a bit like someone's hiding the scissors, so we can't hurt ourselves.

Ian said on October 15, 2010

I don't think we should ever have a parent selector. To cascade means to flow the style down to child elements. If you need to target the parent change the markup not the way CSS works.

Simon said on October 15, 2010

So why do browsers behave like this? Why not apply the CSS after the HTML is fully loaded and use xpath to find the elements? That would be so much faster, easier and powerful. To bad some strange people decided that HTML5 doesn't have to be valid XML, like XHTML and XHTML5

Nicolas Chevallier said on October 17, 2010

Thank you for the article. I just (finally) had managed to understand how the layout elements by browsers. It is much clearer than the explanations given by Steve Souders I find (or that the Google team PageSpeed). And enhanced ability to better manage my CSS rules.

Niels Matthijs said on October 17, 2010

Boo to the Google Page Speed page. While in context that article is not harmful many people will needlessly take over what they are suggesting.

It's okay to worry a little about performance but when it comes to css we have worse problems to tackle. I can't imagine taking over a css of a project I never worked on that was constructed using their guidelines.

Not complaining about this article though. Good reading.

Tyler Herman said on October 19, 2010

I always complained about this (to myself mostly) but I'm glad I at least know the reason now, so I thank you for that.

nyteshade said on October 20, 2010

seems like a :parent pseudo-selector should work like last-element as someone else mentioned before, upon the closing of the tag in question. At this point, go up a single level for #mydiv:parent {color: blue} and target #mydiv's parent element. For multiple parents, #mydiv:parents(p), simply traverse upwards for any p elements that recursively apply to <parent-node>. Parent pathing is almost always a shorter trip then adjacent pathing. In which examples would a parent element not exist?

Montoya said on October 21, 2010

I hate how this wasn't totally obvious already. I just kinda figured people knew this.

Iain Dooley said on October 24, 2010

The one place that I would have liked a parent selector in the past is on hover.

It would be easy enough for a browser to process this on demand rather than during initial page load. So it could be included in CSS but not recommend for use with anything other than :hover states for performance reasons.

Ben Curtis said on October 25, 2010

It's worth keeping in mind that CSS is not a "language" but a standard, and part of the standardization process involves successful implementations of the standard. If the W3C were to declare a parent selector, and all of the browser makers were to say it would cause performance issues, then you would have a few possible outcomes:

  1. The browser makers do not want to implement it, since just the presence of the selector in the CSS would cause the performance hit and any browser that implements it would be thought of as the slowest, least performant browser, and as a result it must be dropped from the standard; or
  2. A few browsers would implement it to be compliant, but would do so in a second pass after all HTML is loaded and would not reevaluate when the DOM changes or on hover events (essentially the same as a JS solution); or
  3. Browsers implement it, take the performance hit, and all sane developers avoid it while other developers use it for simple, inconsequential stylings.

In none of these conditions is the web actually better. In none of these does being "standard compliant" actually improve things. I think that it's vital to remember that we aren't designing a perfect world, but rather paving a road to a better world.

Ben Curtis said on October 25, 2010

I should have re-read my post. I meant in point #1 that if no browsers implement a proposed parent selector because they would lose market share by doing so, then the parent selector would have no implementations and would be stricken from the proposed standard.

Richard said on November 09, 2010

My personal feeling is that the obsession with Page Speed nowadays is a bit pointless.

I remember with dial-ups when speed was probably the priority thing which needed improving, but broadband means that the only reason I get bothered by such a thing is if a site is hosted on a particularly bad server.

I'd rather improvements be made with things like parent selectors, and font embedding to make the page-building side easier.

Stephen Young said on December 02, 2010

@Jonathan Snook Your deep understanding of CSS has forced me to re-evaluate what I thought was my competent understanding of the subject. Great article!

@Iain Dooley: I too wish we had


Or some other kind of pseudo class for additional hover support. I prefer doing as much mouse-hover-interaction as possible in CSS.

Tom Conte said on December 03, 2010

While we are on the topic of site performance, how do you prefer to write your CSS code? Would you rather keep all styles on one line per selector or list each style on a new line? I assume with very large sites, CSS files can become quite unmanageable and writing code on a new line would be easier to manage. If you throw sub-versioning into the mix, does your opinion change?

Jonathan Snook said on December 04, 2010

@Tom: As you can see by looking at the code for this site, I like the everything on one line. However, working in a larger team, I've had to adjust my style. This was also partially to do with the fact that our heavy use of CSS3 made single-line CSS harder to work with. Now, we do each property/value on its own line. We also break up the files into various components, so each file never really gets that large.

Tom Conte said on December 06, 2010

Thanks for your response Jonathan. Fellow developers of mine, on their own projects, write CSS on one line but working in teams they would switch to multi-line CSS. That seems to be the norm then, though, I haven't heard about CSS3 being an issue with single line CSS.

marc said on May 06, 2011

Why not just render the effects of has() after the element has been completed (all children loaded)?

Sorry, comments are closed for this post. If you have any further questions or comments, feel free to send them to me directly.