don’t use @import
In Chapter 5 of Web 2.0 Expo, creating several test pages and HTTP waterfall charts, all shown below. The bottomline is: use LINK instead of @import if you want stylesheets to download in parallel resulting in a faster page.
LINK vs. @import
There are two ways to include a stylesheet in your web page. You can use the LINK tag:
<link rel='stylesheet' href='a.css'>
Or you can use the @import rule:
<style> @import url('a.css'); </style>
I prefer using LINK for simplicity—you have to remember to put @import at the top of the style block or else it won’t work. It turns out that avoiding @import is better for performance, too.
@import @import
I’m going to walk through the different ways LINK and @import can be used. In these examples, there are two stylesheets: a.css and b.css. Each stylesheet is configured to take two seconds to download to make it easier to see the performance impact. The first example uses @import to pull in these two stylesheets. In this example, called @import @import, the HTML document contains the following style block:
<style> @import url('a.css'); @import url('b.css'); </style>
If you always use @import in this way, there are no performance problems, although we’ll see below it could result in JavaScript errors due to race conditions. The two stylesheets are downloaded in parallel, as shown in Figure 1. (The first tiny request is the HTML document.) The problems arise when @import is embedded in other stylesheets or is used in combination with LINK.

Figure 1. always using @import is okay
LINK @import
The LINK @import example uses LINK for a.css, and @import for b.css:
<link rel='stylesheet' type='text/css' href='a.css'> <style> @import url('b.css'); </style>
In IE (tested on 6, 7, and 8), this causes the stylesheets to be downloaded sequentially, as shown in Figure 2. Downloading resources in parallel is key to a faster page. As shown here, this behavior in IE causes the page to take a longer time to finish.

Figure 2. link mixed with @import breaks parallel downloads in IE
LINK with @import
In the LINK with @import example, a.css is inserted using LINK, and a.css has an @import rule to pull in b.css:
<link rel='stylesheet' type='text/css' href='a.css'>
@import url('b.css');
This pattern also prevents the stylesheets from loading in parallel, but this time it happens on all browsers. When we stop and think about it, we shouldn’t be too surprised. The browser has to download a.css and parse it. At that point, the browser sees the @import rule and starts to fetch b.css.

Figure 3. using @import from within a LINKed stylesheet breaks parallel downloads in all browsers
LINK blocks @import
A slight variation on the previous example with surprising results in IE: LINK is used for a.css and for a new stylesheet called proxy.css. proxy.css is configured to return immediately; it contains an @import rule for b.css.
<link rel='stylesheet' type='text/css' href='a.css'> <link rel='stylesheet' type='text/css' href='proxy.css'>
@import url('b.css');
The results of this example in IE, LINK blocks @import, are shown in Figure 4. The first request is the HTML document. The second request is a.css (two seconds). The third (tiny) request is proxy.css. The fourth request is b.css (two seconds). Surprisingly, IE won’t start downloading b.css until a.css finishes. In all other browsers, this blocking issue doesn’t occur, resulting in a faster page as shown in Figure 5.

Figure 4. LINK blocks @import embedded in other stylesheets in IE

Figure 5. LINK doesn't block @import embedded stylesheets in browsers other than IE
many @imports
The many @imports example shows that using @import in IE causes resources to be downloaded in a different order than specified. This example has six stylesheets (each takes two seconds to download) followed by a script (a four second download).
<style> @import url('a.css'); @import url('b.css'); @import url('c.css'); @import url('d.css'); @import url('e.css'); @import url('f.css'); </style> <script src='one.js' type='text/javascript'></script>
Looking at Figure 6, the longest bar is the four second script. Even though it was listed last, it gets downloaded first in IE. If the script contains code that depends on the styles applied from the stylesheets (a la getElementsByClassName, etc.), then unexpected results may occur because the script is loaded before the stylesheets, despite the developer listing it last.

Figure 6. @import causes resources to be downloaded out-of-order in IE
LINK LINK
It’s simpler and safer to use LINK to pull in stylesheets:
<link rel='stylesheet' type='text/css' href='a.css'> <link rel='stylesheet' type='text/css' href='b.css'>
Using LINK ensures that stylesheets will be downloaded in parallel across all browsers. The LINK LINK example demonstrates this, as shown in Figure 7. Using LINK also guarantees resources are downloaded in the order specified by the developer.

Figure 7. using link ensures parallel downloads across all browsers
These issues need to be addressed in IE. It’s especially bad that resources can end up getting downloaded in a different order. All browsers should implement a small lookahead when downloading stylesheets to extract any @import rules and start those downloads immediately. Until browsers make these changes, I recommend avoiding @import and instead using LINK for inserting stylesheets.
Update: April 10, 2009 1:07 PM
Based on questions from the comments, I added two more tests: Many LINKs has four LINK tags in the HTML document to pull in the four stylesheets (my recommended approach). The HTTP waterfall charts are shown in Figure 8 and Figure 9.

Figure 8. LINK with @imports

Figure 9. Many LINKs
Looking at Many LINKs starts downloading the stylesheets immediately.
The second problem is that IE changes the download order. I added a 10 second script (the really long bar) at the very bottom of the page. In all other browsers, the @import stylesheets (from proxy.css) get downloaded first, and the script is last, exactly the order specified. In IE, however, the script gets inserted before the @import stylesheets, as shown by Many LINKs in Figure 9. Thus, the page renders in 4 seconds.
The load times of these resources are exaggerated to make it easy to see what’s happening. But for people with slow connections, especially those in some of the world’s emerging markets, these response times may not be that far from reality. The takeaways are:
- Using @import within a stylesheet adds one more roundtrip to the overall download time of the page.
- Using @import in IE causes the download order to be altered. This may cause stylesheets to take longer to download, which hinders progress rendering making the page feel slower.
Will Peavy | 09-Apr-09 at 7:05 am | Permalink |
Thanks for posting this! I’ve been in favor of link over @import for a while. Now there’s an article from an authoritative source to back up usage of link.
david g | 09-Apr-09 at 7:08 am | Permalink |
irregardless of the performance considerations of import/link usage. it’s my belief that @import best usage is as a means of overriding existing styles logically in an existing framework or application.
Take for instance these directions: http://www.redmine.org/wiki/redmine/HowTo_create_a_custom_Redmine_theme
other CMS’s such as Drupal (drupal.org) simply [link] all css sheets needed from all modules in a page.
my only point that i think i’m trying to make is that i agree towards the usage of [link] tags vs @import directives for all normal cases — unless its towards a means of CSS overrides and the underlying framework is looking for a single file called application.css (as Ruby on Rails does, which Redmine is developed with).
thank you for the informative article.
Nacho Plaza | 09-Apr-09 at 11:03 am | Permalink |
Thanks for this information and the tests. It is always a good idea to improve performance on our web sites.
Linked from “Weterede!”
Justin Garfield | 09-Apr-09 at 12:43 pm | Permalink |
Very good article! I’ve always wondered this myself, because I found some other issues with @import in Internet Explorer as well. I was also glad to see that you tested 6, 7, and 8, and not just 7 like lots of sites seem to do now.
With the theme of @import and IE going on, I’d also like to share this article I wrote a while back on limitations it has with @import as well. http://tinyurl.com/d4uvgr
Again, thanks for the excellent article! :-)
Permalink |
Finally, I have something to show my co-workers when I make my argument – again.
Thanks for the details on this. Much appreciated!
Permalink |
All right, i won’t use it anymore.
Permalink |
Steve, all examples that you use in your post make no sense.
What I’m trying to say is I have never seen somebody using the link and @import at the same time. And I’ve seen many source codes in my life. That is not like everyday situation, more like an exeption.
Why would anybody do such a thing?
Next, you didnt give an example of the only way I used to use @import, and many other people that I know. And that is:
@import url(‘a.css’);
and ONLY that, no link and no combination of them. I put all my css rules in one css file.
IF there are many lines of code, and if it makes sense, then I broke it into several other CSS files.
From a.css I call other files with @import.
Antti | 10-Apr-09 at 3:26 am | Permalink |
How about linking to a one proxy.css, and @importing from there? The @imports download in parallel in all browsers, right?
That way we would only have one in our , seems cleaner.
Antti | 10-Apr-09 at 3:26 am | Permalink |
That way we would only have one link-tag in our head, seems cleaner.
Dave McFarland | 10-Apr-09 at 8:03 am | Permalink |
Did you test the setup Antti is talking about? I’ve seen sites use a single link-tag to load a stylesheet that then uses multiple @imports for different stylesheets. How do stylesheets load in this condition–in parallel or sequentially?
Josh | 10-Apr-09 at 11:45 am | Permalink |
Not sure if this has already been said, but you left out a key example.
If you only have one tag, and it contains nothing but @import rules, the CSS files are downloaded in parallel as soon as the single ‘d CSS file is downloaded, at least as far as I can tell.
Can you update your post with this test? Thanks!
Josh | 10-Apr-09 at 11:47 am | Permalink |
My comment lost its markup, let’s try this:
Not sure if this has already been said, but you left out a key example.
If you only have one <link$gt; tag, and it contains nothing but @import rules, the CSS files are downloaded in parallel as soon as the single <link$gt;‘d CSS file is downloaded, at least as far as I can tell.
Can you update your post with this test? Thanks!
TOTU | 10-Apr-09 at 1:39 pm | Permalink |
@import may load everything succinctly, ie all-in-one heap, but causes most browsers to pause at least 2 second before each download
Josh | 10-Apr-09 at 3:27 pm | Permalink |
Thank you very much for the updated tests!
Permalink |
Hi there Steve.
You raise some interesting issues here. How would you tackle the accessibility issues that your methods create? If @import was not required for this purpose I would drop all styling rules into one (statically or dynamically) arranged and compressed file for maximum efficiency. As far as I know this is not possible whilst remaining accessible and DRY. If you have discovered the magic bullet I would love to hear about it!
Permalink |
Thank you, Steve! I knew of some of these issues, but having all of these use cases organized and visualized is extremely helpful, useful, and practical. Keep up the good work!
Permalink |
hi,
GREAT post – thanks for that!
Is it possible that alternate stylesheets are always loaded sequential in IE – even if no @imports are there?
and that @import only influences the stylesheets following the @import-statement, i.e. if there are s first and some @import’s in the end, there’s no problem?
again – thanks a lot!
Permalink |
Wow! I am in the habit of separating my css into many files each with specific purpose, sometimes up to 10 files. All using @import from a LINK “proxy”.css
My site was feeling slower than it should have. After changing them all to LINK, the difference was DRAMATIC!
Not as “pretty” in the source code, but performance trumps all.
Iain | 07-May-09 at 8:08 pm | Permalink |
It seems that most of this affects IE only. I typically use link, because it is easier to track, and, as I have read before slower.
But this analysis of the link mixed with @imports is very interesting.
By now, I’m sure the amount of bugs in IE far outweighs the features…
Andrew | 19-May-09 at 8:32 am | Permalink |
@John
I have to agree with that, don’t use IE 8-) However, I did find the theorem very intriguing.
Murray | 27-May-09 at 9:52 am | Permalink |
Steve,
I’ve also heard that when using @import, browsers may not cache the css files, unlike with a . But I haven’t been able to verify this. Are you aware if it actually matters from a caching perspective? If so, it might be another reason to avoid @import.
Permalink |
Steve, I’m testing your example LINK LINK in IE6 and what can I see:
Are you shure you not wrong with “Using LINK ensures that stylesheets will be downloaded in parallel across all browsers”?
Permalink |
@Vadim: Yes, I’m sure it works that way in IE6. The most likely explanation for what you’re experiencing is that you have an IE plugin that blocks stylesheets from loading in parallel. These types of plugins are using the Async Pluggable Protocol. Examples include the RealPlayer uploader, Sophos, and many others. Try disabling all your plugins. If you still have problems, send me an email via my contact page.
Permalink |
This article is only for IE 6+ users. The tag is for CSS1 which old browsers can understand. If you use CSS2/CSS3 such as shorthand property, you have to use @import to exclude the old browsers. Otherwise the old browsers do not understand shorthand and will mess up the layout or cause error.
If you do not mix LINK and @import, it does not hurt. Also, The tag should have a type attribute with the MIME type “text/css” attribute for fast load. Always add “/” after url for quicker load.
Anyway, the CSS files load much faster than the images so not a big deal.
Willabee | 19-Jul-09 at 11:34 am | Permalink |
I use multiple @imports which, as you say, do not get penalised unless followed by a script. If you are following best practise of placing your script file/s at the bottom of the page, thus avoiding the need to use window onload and on DOM ready type events because the DOM is ready at this stage, does this still lead to the script blocking the @import downloads?
Permalink |
Hi,
Was wondering if you can help. When I view the page source on my website the external files are linked!!! Dont know why but I certainly dont want them to be linked so others can view. any advise on how to get rid of the links?
Permalink |
so what are the benefits then?
I guess its browser issue not the syntax issue.
John Albin | 18-Jan-10 at 8:34 pm | Permalink |
Stylesheets Not Loading? 31 Reasons to Hate Internet Explorer
http://john.albin.net/css/ie-stylesheets-not-loading
yeni oyunlar | 19-Jan-10 at 5:32 am | Permalink |
not loading on ie :/
Robocat | 09-Mar-10 at 3:35 pm | Permalink |
A fantastic free tool instead of HttpWatch is http://fiddlertool.com – it is a proxy for recording all activity, but it also does waterfall charts (amongst other great features!).
mike foskett | 30-Mar-10 at 3:50 am | Permalink |
A while ago I ran tests on link vs import and came to the conclusion that IEv6 treats link in the same way as script. That is it prevented further parallel downloads until completion.
I therefore concluded, perhaps true for only that specific case, using import was a more efficient solution.
Reading the above article and it’s conclusion doesn’t appear to countermand that decision.
To conclude: Nothing beats real world testing.
Permalink |
I created a dynamic CSS library that will let you @include CSS files on the server instead of @import on the client. It also compresses and caches for performance. It’s a free download at http://www.coolphptools.com/dynamic_css
niquola | 02-Apr-10 at 9:00 pm | Permalink |
@import is basic dependency management for big projects
U can use some build script for production, which internalize your @imports
Permalink |
@ridgerunner: JS running after the load event will avoid any race condition. Also, even if IE8 downloads the script first, it holds off on executing it until after all the stylesheets are done, thus avoiding the race condition. I haven’t tested IE6&7. Use this Cuzillion test page and tell me what you see on other browsers. If the script execution time is after 2000ms, then the race condition is a non-issue.
But this out-of-order is still a problem worth avoiding. I modified the many @imports test to put an image last. Because it gets downloaded and rendered first, there’s a flash-of-unstyled-content once the stylesheets arrive – something most (all?) developers wouldn’t have expected.
Permalink |
@donquixote: 1) It would be better to work on a way to not have 31 stylesheets in Drupal. Regardless, I don’t have best practices for a page like that. 2) There are multiple issues that affect all browsers. Search above for “all browsers” to see the specific issues.
Permalink |
We have also started to change our @import > Link, because based on our test link really load faster.
Permalink |
@Ncage: IE9 behaves the same as IE8.
Permalink |
There is a simple concluusion to what happens if You want to download externla ressources in parallel. One point is that there ist limited number of request that run parallel. Even if there is no browser limitation on that maybe the server has one. Another point is, that for each download a single request is done with all its overhead regarding IO.
So maybe another appoach might be to concatenate the ressources on the server side (where You can easily manage the dependencies), pack them and deliver them in one respones to one request to client. This works fine for all server side progarmming languages.
Matt Wrock | 20-Nov-11 at 7:33 am | Permalink |
I’ve been working on an OSS project https://github.com/mwrock/RequestReduce that among other things, combines and minifies css for .net web apps. One feature I implemented fairly recently is the ability to recursively automatically expand @imports. This has proven to takes the bite out of @import perf yet allows web dev/designers to keep them.
Permalink |
@ShaunR: I’ve written 3 blog posts about fonts. Here’s a good place to start: Frontend SPOF.
Permalink |
@Shanimal: I agree that @import helps with dependency management. If that’s important to the dev team I recommend a build process or other tool to flatten the @import dependencies in production. (Mod_pagespeed just announced flattening of @imports.) Whenever there’s a tradeoff of making it better for developers or better for users, I feel programmers should favor their users, esp. if the pareto optimal solution is possible with infrastructure enhancements.
@tansel: Yes, if the JS is delayed until after all the CSS is loaded then there is no race condition.
@Catspaw: Cuzillion is a great tool to be familiar with for answering questions like this. Here’s a test page that has an inline @import followed by a link’ed stylesheet. In Chrome 18 & Firefox 11 they load in parallel.
Catspaw | 09-Apr-12 at 12:53 pm | Permalink |
Ok Steve, I’ve tested a simple setup in your Cuzillion (dead nice!): one import followed by two links (each 4 secs so we see what’s going on). In a windows environment in IE6, 7 and 8, Opera, and Safari, they all appear to load in parallel (just over 5 secs in total). But of course if you use scripts as well you are still likely to mess it up with white screens or FOUS. So maybe sticking with many links is still the best bet. Does IE8 still limit concurrent downloads to 2 files by the way, and how about IE9?
Catspaw | 09-Apr-12 at 1:45 pm | Permalink |
Steve ignore my last point, can’t apply if all files were downloaded concurrently – duh! (unless I’ve done something wrong). I’ve expanded the test to include 3 imports (4 secs each) followed by 2 links (4 secs each) and get some interesting results. In IE6-8 you get a wide variation in download time, mostly around 12 secs but can be as little as 9 but once actually took 18secs. Opera responded similarly (although didn’t get the upper value repeated). Safari had the best result, just over 5 secs! While FF came in at a respectable 7 secs or so. Looks like this has finally hit the last nail in for me, using multi imports followed by links obviously causes all sorts of stuff to go haywire.
Patrick Heller | 17-Apr-12 at 7:58 am | Permalink |
I have one problem with the link-solution: IE has a limit on how many links you can have in a page, 31 to be precise. In our platform we have already reached that number. IE does not have a limit on how many imports you can do.
The problem with the links is that it’s not always obvious which css file IE decides not to load. We e.g. use Telerik controls, which automagically create their own links through javascript. When that happens, it could be that one of our own stylesheets is dropped out of the load. Nasty!
Permalink |
@bilgi: @import has no effect on caching.
Marc Stalfoort | 31-Oct-12 at 7:21 am | Permalink |
Hey Steve
I was wondering if the rules as you’ve investigated and tested thoroughly still apply with the latest browsers. The use case I’m referring to is as follows:
@import url(“a.css”);
within the a.css several @import rules are used.
I know this should not be used in this way, but I’m very interested in your vision about this case.
Marc Stalfoort | 31-Oct-12 at 7:23 am | Permalink |
… the @import is used in a style element in the head
Permalink |
Romit: The caching of a stylesheet is based on its response headers. Whether @import or link is used does not affect caching.
Permalink |
when I use the instead of @import, my parent CSS sheet isn’t properly being imported and by styling breaks. Can you advise ont he best way to import my parent sheet into the child theme sheet?
this is the parent i am trying to import: