Yahoo! Developer Network Blog

« Previous | Main | Next »


July 9, 2007

High Performance Web Sites: Rule 5 – Put Stylesheets at the Top

While researching performance at Yahoo!, we discovered that moving stylesheets to the document HEAD makes pages load faster. This is because putting stylesheets in the HEAD allows the page to render progressively.

Front-end engineers that care about performance want a page to load progressively; that is, we want the browser to display whatever content it has as soon as possible. This is especially important for pages with a lot of content and for users on slower Internet connections. The importance of giving users visual feedback, such as progress indicators, has been well researched and documented. In our case the HTML page is the progress indicator! When the browser loads the page progressively the header, the navigation bar, the logo at the top, etc. all serve as visual feedback for the user who is waiting for the page. This improves the overall user experience.

The problem with putting stylesheets near the bottom of the document is that it prohibits progressive rendering in many browsers, including Internet Explorer. Browsers block rendering to avoid having to redraw elements of the page if their styles change. The user is stuck viewing a blank white page. Firefox doesn't block rendering, which means when the stylesheet is done loading it's possible elements in the page will have to be redrawn, resulting in the flash of unstyled content problem.

The HTML specification clearly states that stylesheets are to be included in the HEAD of the page: "Unlike A, [LINK] may only appear in the HEAD section of a document, although it may appear any number of times." Neither of the alternatives, the blank white screen or flash of unstyled content, are worth the risk. The optimal solution is to follow the HTML specification and load your stylesheets in the document HEAD.

Steve Souders

[Steve Souders is Yahoo!'s Chief Performance Yahoo!. This is one in a series of Best Practices for Speeding Up Your Web Site. This article is based on Steve's book High Performance Web Sites, published by O'Reilly.]

Posted at July 9, 2007 12:26 PM | Permalink

Bookmark this on Delicious

Comments

currently the YSlow gives an "F" to sites that DO put their CSS in the head, but inside that CSS file reference additional CSS files through the use of @import.

@import "/css/yui-reset.css";
@import "main.css";

does this too effect progressive rendering?

Posted by: Brian Suda at July 25, 2007 4:07 AM

YSlow gave me a "B", saying my stylesheet was being called outside of the section.
My stylesheet is only called from the HEAD area, from a link rel="stylesheet"

It seems odd that YSlow says:
1 external stylesheets were found outside the document HEAD.

Viewing the HTML headers and contents shows it is only being called once in the resulting HTML. Why does YSlow think I am calling it outside of the HEAD?

Posted by: Steve Robins at July 25, 2007 9:06 AM

I had the same experience as Steve - was told it was outside the Head, even though these two lines were not:



Posted by: glen at July 25, 2007 12:30 PM

Ok, so this rule needs to be adjusted for external stylesheets that are linked from the style sheet specified in the head.

For one, there is nothing wrong with this method, and in fact all of the style sheet information is still located in the head of the document. What this allows for is that the markup can stay the same, but the style sheets can be added or removed from the master style sheet. Allowing presentation and markup to be entirely separate.

Posted by: Alexander Wolfe at July 25, 2007 1:18 PM

I don't understand this rule. Why would browsers block rendering just because the CSS has not been fully downloaded yet? Unlike Javascript which may change the structure of the HTML and therefore browsers must suspend DOM construction, CSS doesn't change the structure and so rendering the unstyled HTML first and then rendering the styled HTML a second time is not destructive. It may be inefficient, but I think it is an acceptable trade off for seeing the content sooner.

And why is progressive rendering not possible when the CSS is at the bottom? Can't the browser render the HTML first? Isn't that the definition of progressive? And then as the CSS is downloaded, start progressively rendering the styles over the HTML.

The only performance-related argument I can think of is that by avoiding the initial render of plain HTML, the computer can reserve more CPU to render the CSS, but I think that would only save a few microseconds.

Posted by: Jordan at July 25, 2007 9:48 PM

We have the same problem. I thought maybe it was because we were using a protocol-inspecific URL: e.g., href="//foo.example.com/style.css", and maybe some matching algorithm didn't properly normalize the URL before matching ... ?

Posted by: pudge at July 26, 2007 11:11 AM

Of course this applies to backend framework based page generation with JS embedding, but not FullAJAX on-demand loaders (these load CSS as well on demand) (WebComponent Frameworks)... see http://system.dlv.phpb002.de , check with firebug. Its the fastest FullAJAX F-Grade site I know of, at least I´d be intersted in seeing something faster since I made it ;-)
Other than that I fully agree on this rule for conventional sites. BTW I got valuable hints from the Yslow tool as well thx for that ...

Posted by: Frank Thürigen at July 28, 2007 10:02 AM

Brian and Alexander: Use "link" to include stylesheets, not "@import". The problem is if you use "@import" IE downloads them later and progressive rendering is delayed.

Steve & glen: If you provide the URL I can check.

Jordan: I recommend you read the book. There's 10 pages on this subject that go beyond this short blog. David Hyatt has a great explanation for why browsers do this in his Surfin' Safari blog (http://weblogs.mozillazine.org/hyatt/archives/2004_05.html#005496).

Posted by: Steve Souders at July 28, 2007 11:08 AM

I have the same get a B problem as Steve and Glen:
1 external stylesheets were found outside the document HEAD.

* [HTTP headers] http://static.removed.ca/staticsResponder.php?a=GetCSS

this link is found in the homepage of the URL provided.

Posted by: bernie at July 28, 2007 1:48 PM

I see myself obsessing over a perfect score on this. We have a "widget" system with each widget containing its own CSS links. We've made sure that the widgets load after the framework and after the page is ready. It makes for a faster-feeling.

I've used jQuery to append ($('head').append('link to css here')) the CSS reference in but ySlow still gives me an F. In the spirit of the rule ("load CSS first") the rating is true but in the context of our app. the rating doesn't make much sense.

I was just wondering how ySlow is detecting where CSS is being loaded. Is the DOM being monitored for CSS links?

I'm pretty sure what we are doing is OK and in this context the ySlow rating is not relevant, but I'm still a bit obsessive :)

Posted by: Paul M. Watson at July 31, 2007 6:18 AM

I'm being picked up on this rule because of Firebug CSS through Chrome:
chrome://firebug/content/highlighter.css

Is it possible to alter this rule to exclude chrome objects?

Posted by: Dan Atkinson at August 8, 2007 7:16 AM

Does anyone know how browsers handle print CSS. Are they downloaded along with the screen CSS files, just for the odd occaision that someone will want to print? Or are they only downloaded when printing is requested?

Posted by: Steven Tew at August 17, 2007 5:35 AM

Is it only in the absence of a LINK element in the HEAD that IE blocks progressive rendering?

Posted by: Brendyn A at August 19, 2007 4:54 PM

I have all (6) external stylesheet in the document head; but YSlow keep telling me that I have "3 external stylesheets were found outside the document HEAD." I move these stylesheet around but keep getting the same problem. They do not have either link nor @import inside.

Posted by: Pablo C at August 23, 2007 7:31 PM

Many of us had some headaches about "external stylesheets found outside the document HEAD". It looks that there is a bug in YSlow: THE CSS FILES PATHS MUST BE LOWER CASE.*
Too weird!!

Posted by: Edouard F at September 5, 2007 7:20 AM

We've filed a bug on this and will fix it in the next release.

Posted by: Steve Souders at September 5, 2007 10:31 AM

Well the bug hasn't been solved properly in the 0.9.2 release. Following stylesheet URL of my website www.deafzone.ch is still marked as "outside of HEAD" by YSlow:

http://www.deafzone.ch/r/s/themes/standard.php?language=de&media=print

You see, it is all written in lower case. But it still does not work. Maybe the special signs like ? or = or & make trouble?

Any hints, bugfixes?

Posted by: Michael Heuberger at January 21, 2008 10:58 PM

As Michael points out, it is the ampersand (&) sign that triggers the issue in YSlow. It doesn't matter if you use & or &.

YSlow team, please fix the ampersand bug. It's a fantastic tool, but this bug is really annoying.

Posted by: Mads Kristensen at July 6, 2008 9:53 AM

I also got a "B" grade for "Put CSS at the top" obviously this is a bug in YSlow.

The interesting thing I found is that it was using '&' to represent the '&' in the CSS file's URL that was causing it.

here's my link tag for clarity:

the alternative is to ommit the html entity and just use & in your link tag but I prefer to be XHTML compliant rather than get brownie points for something I was already doing!

of course I could find another way of getting that info to my cssconcat script but why should I?

hope this helps someone who might be desperate for approval from YSlow or maybe their boss or something :)

Posted by: Bestie at August 12, 2008 6:19 AM

Looks like we're not allowed html entities in posts which makes my previous post a little difficult to understand.

to clarify I found it's the & a m p ; in the page that causes the behaviour

Posted by: Bestie at August 12, 2008 6:23 AM

Yes, it appears @import rules are treated as "OUTSIDE THE HEAD" -- I suspect this is a bug, perhaps an "unknown" in their "where is it loaded from?" algorithm...

Posted by: chovy at October 31, 2008 2:21 AM

it seems the ampersand bug is not fixed yet -- i am using a php script to minify, gzip and cash my css, so that it always serves the smallest and if not changed cashed version of it, but yslow is telling me that the css is outside of head, which it isn't

Posted by: tench at November 22, 2008 1:01 AM

" />

If I remove the ?23492083490 then I get grade "A". Otherwise, I receive a C. This "bug" apparently doesn't like question marks either.

Posted by: Michael Hradek at December 4, 2008 6:15 PM

I noticed a grade "B" (Put CSS at the top) for a css file reference inside an iframe.

for example:

If i have html with an iframe (down below is a compiled format)






The rule "Put CSS at the top" complains that "external stylesheets were found outside the document HEAD." and its actulally pointing to the style sheet reference inside the iframe.

is this a performance hindrance.?


Posted by: Jay at December 19, 2008 11:31 AM

I realise this is a bit old now, but still seems to be the most relevant information I could find.

I too would like to know about print style sheets. As far as I can tell they are always downloaded, so I think they should go at the bottom of the page under the same logic as the javascript. However this won't validate (although it does work fine...) as link tags are only allowed in the head.

Any suggestions?

Posted by: Peter at November 4, 2009 4:33 AM

Post a comment

Comment Policy: We encourage comments and look forward to hearing from you. Please note that Yahoo! may, in our sole discretion, remove comments if they are off topic, inappropriate, or otherwise violate our Terms of Service. Fields marked with asterisk '*' are required.

Remember Me?

Subscribe

YDN Blog: Get Yahoo! Developer Network Blog on your personalized My Yahoo! home page.

Add To My RSS Feed

YDN Link Blog: Get Yahoo! Developer Network Linkblog on your personalized My Yahoo! home page.

Add To My RSS Feed

Recent Readers

Copyright © 2010 Yahoo! Inc. All rights reserved. Copyright | Privacy Policy

Help us continue to improve the Yahoo! Developer Network: Send Your Suggestions