Front-end Optimization from the Get-go, Part 2

Tweet

In the second installment of optimizing your website, we’ll cover handling your CSS and squeezing every ounce of performance from it. Please have a read of part 1 if you missed it.In any web page, the order that your browser downloads your content is simple: it retrieves the HTML, which tells it the other files to request from your server, while your CSS provides all the styling to make it display as needed.Improving front-end performance is shown to have an impact on overall conversion, including click-through rates, average time on site, sales, and even Google rankings.

Reducing Requests

Even Darth Vader reduces requests.

I like to have my CSS in lots of files. Files just for the header of my pages, or for the footer, for the home page–for each section of my site. This, of course, means that if I was to include them in the head of the document, there’d be a huge number of requests. So, the easiest way to deal with this is to concatenate the files.There are many applications for this: Turbine (seems much like CSScaffold), Juicer (have heard good things, but yet to try it), and my favorite, CSScaffold (currently offline, but created by Anthony Short).These concatenate your CSS into fewer files (one file, if that suits your setup), which means you have fewer requests to make.

Minification and Gzipping

Minification can yield some large savings. It compresses your CSS by removing all unnecessary white spaces and line breaks, and reducing your code into as few lines as possible. This is usually done just as you’re making your code live, because minified code is extremely difficult to work with.Gzipping is server-side compression that can bring about massive savings. It’s supported by all the modern browsers, and although it can take a bit of time setting up to run nicely, it’s well worth it.The applications listed above will usually have minification and Gzipping as options to further reduce file sizes.

Put Style Sheets at the Top

This is an obvious one that most of you will already be doing. By having the style sheets linked from the head of your HTML, your users’ browsers will start styling the page as soon as it can, making the web page appear to be loading. This stops your users from thinking that nothing is happening, growing frustrated, and leaving, as they’re assured that the browser is responding.

Use link Tag instead of @import

Some performance improvements aren’t actually making websites faster; they’re merely making the website seem faster to your end user.The link tag (<link href="styles.css" type="text/css" />) should be used instead of the @import (<style type="text/css">@import url("styles.css");</style>) for using styles. They’re identical, but the link tag will display the CSS as soon as possible, while the @import will wait until the page is fully downloaded before displaying in some browsers.

Avoid Inline Styles

It has been suggested that you include some (or all) of your CSS inline in your HTML, thereby reducing the number of requests altogether. This sounds like a good idea, and there are times when it’s handy; however, HTML isn’t cached when handled this way. By having it in an external file, the user’s browser will save it so that when the user returns, and it hasn’t changed, it’ll use that file instead of downloading another copy of the file.

Specificity

CSS specificity is an odd topic to cover in an optimization discussion. Specificity is how strong a certain style is; an element (anchor, paragraph, or form, for example) is overridden by a class ( “.post“) which in turn is trumped by an ID (“#header“). Andy Clarke put it beautifully when he came up with the CSS: Specificity Wars image explaining the concept using three Star Wars-themed tiers: Sith Lords represent IDs (and are worth 100 points), Darth Vaders are classes (10 points), and Storm Troopers are elements (1 point).All that aside, specificity (or more importantly, how specific you tend to write your classes) can make a real difference in file sizes!We’ve all done it: written CSS that’s included two or three IDs, maybe a class or two, and then an element, all just to style a block on the page. In an ideal world, 90% of styles should consist of only an ID, a class, and maybe an element. Even this has a specificity score of 111, which still should be strong enough to hold up against other styles.For example, #container #content #header h1.logo has a strength of 311, but in terms of file size it’s 35 characters long. It could be easily reduced to #header h1 (101 points), which brings it down to ten characters, as there should only be one h1 element. Even under HTML5 where you can have multiple h1 elements, a header with multiple h1 elements would make little sense.You may ask, so what? We’ve saved 25 whole characters. But extend that to a style sheet of two or three thousand characters (which most big sites grow to eventually, even if it’s split across multiple files). It can be a real size saving waiting to happen. And, like all legacy code, it can only be done right once–else it becomes a nightmare. The trick is to write styles that use less points worth of specificity across the entire style sheet, so that you need less strength in an individual style to use it.

Conclusion

I’ve discussed most of the rules that will make your CSS go faster. Most of these are easy to implement, and you’ll notice a difference with your pages loading faster. In the next few posts, I’ll cover the handling of JavaScript and images, so stay tuned.

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • http://seriocomic.com seriocomic

    Awesome article Mark. I have been using the Minify code (http://code.google.com/p/minify/) to achieve concatenation of not only my CSS files, but also my JS files as well. The bonus of this method is that it offers GZIPping included.

    Another trick I learnt to reduce the number of requests with CSS that you can’t normally do with concatenation is using the ‘@media all’ and ‘@media print’ to include the print styles in the same CSS file.

    In this way I have reduced the number of requests from 11 to 2 (1 JS and 1 CSS), and reduced total overall size by over 200kb.

    • Mark Cipolla

      Great tip on the @media all / print.

      Every request counts!

  • Jon

    I thought Darth Vader was a Sith Lord :/

  • Schepp

    For CSS and JS optimization, I ‘d like to point to the CSS-JS-Booster, located at http://wiki.github.com/Schepp/CSS-JS-Booster/, which is a PHP5-library that does all the dirty work for you:

    – combining multiple files
    – minification
    – replacing image resources with dataURI
    – gzipping the output
    – invoking client browser caching

    Should be easy to include in your PHP-projects or PHP-aware templating systems (à la Smarty).

    • Mark Cipolla

      The CSS-JS Booster seems to be a very handy tool. (for those of you playing at home, I recommend having a look!)

      I must be honest and say I’m not a fan of data-URI / MHTML images. It feels a bit dirty; content, albeit images, getting removed from the page. But there are definitely uses where it wouldn’t detract from the semantic meaning (a background on a list, I guess).

      Also, do you have any stats handy if splitting the CSS into two even files for parallel downloading provides benefits over concatenating it into a single file? There would always be other requests to fill that request…

  • http://neighborwebmaster.com Kepler Gelotte

    I would also like to mention my tool written in PHP for apache servers. It works by extending the CSS syntax to allow for server-side combining of files using @include. It also minifies and delivers CSS using gzip. It supports IF/THEN/ELSE logic and variables also.
    No modification is necessary to your current CSS files unless you want to take advantage of the extensions. Minification (and caching to improve speed) are automatic. Just add the files to any folder that contains CSS.
    You can read more about it here: http://www.coolphptools.com/dynamic_css/doc
    and download it here: http://www.coolphptools.com/dynamic_css
    It is free to use and modify. Feedback is appreciated if you find the tool helpful or not.

    • Schepp

      Nice!

      • http://neighborwebmaster.com Kepler Gelotte

        Thanks :) and thanks for clearing up the @import/@include confusion below.
        I plan on writing an article on my web site soon about how CSS variables can allow for object-oriented-like frameworks. I converted the 960 grid system to use only CSS variables as an example. Imagine not having to add “alpha”, “omega”, etc. to your HTML markup.
        Fell free to incorporate any of my code into your project if you find it useful.
        Thanks again.

  • Schepp

    Hi Mark,

    dataURI-techniques are nothing dirty at all. They follow specs:
    http://en.wikipedia.org/wiki/Data_URI_scheme
    and
    http://www.w3.org/TR/1999/REC-html401-19991224/struct/objects.html#h-13.3.1

    And in addition CSS-JS-Booster will only apply them on stylesheet-resources, not on HTML-inlined images. Why using them? Think of them like spriting but with the advantage of no complex sprite-layout-work/-headaches and The possibility to mix JPG and PNG-24 into the same file (which is the stylesheet itself or an MHTML-file for IE6 and 7).
    The base64-overhead is combatted with gzipping everything afterwards back to the resources former sizes.

    Regarding your question on loading time benefits when splitting CSS, I can only point you to a German presentation on Slideshare, still the interesting part is completely understandable:
    http://www.slideshare.net/dmacx/performance-optimierung-barrierefreiheit-beginnt-mit-ladezeiten
    There, move forward until slide 19.

    Sure, it depends on how many other resources you load on top, but considering 4 to 6 possible parallel HTTP-1.1-connects (slide 15) and a well done overall HTTP-request-optimization (like with lazy loading), it is not such a bad idea to spread CSS across 2 or more parts.

    JavaScript on the other hand absolutely needs to be one single file, as it blocks further parsing as long at it does not make use of “defer” or “async”-attributes.

    • Mark Cipolla

      I agree wholeheartedly on one JS file. Avoiding blocking parallel downloads is the way to go. Just not 100% sold on splitting the CSS. Not all browsers can grab more than two downloads parallel.

      I’m in Australia, so servers in the USA are ~250-400 ms ping, so that’s moderately expensive. But I can see your point.

      As for data-URI encoding images, it’s just a new(ish) approach. It would be great to see some statistics before and after using the app!

      • Schepp

        With CSS-JS-Booster you are not forced to split CSS – it’s just the preset. You can configure it to no splitting at all (see the advanced usage section).

        But I am pretty sure, that every browser can download multiple CSS in parallel, as long as the request-list is not already blocked by other resources (which also need must be located in the HTML head then) or something special like fonts or conditional comments. As pointed out in the presentation, current browser support 4-6 parallel file downloads, just the older IEs only support 2 (which is spec-standard). And no matter what your roundtrip-time to the server is, it will not add with two files, instead this will just cut payload-transfer-time in half.

        data-URI results are absolutely spectacular! If you want to do a quick test, I have published a WordPress-plugin on the official plugin-repository (also named “CSS-JS-Booster”), that wraps around my library.
        I admit, it does not work in every WP-constellation, but that is due to my basic understanding of the the WordPress-universe (and the quality of other plugins). Still, most of the time it just works.

        The better test though is one with only the genuine PHP-library in some of your projects. Be it a custom project, or a CMS.
        I know of people that integrated it into Magento, or TikiWiki and had their site rising into the high 90ies in Google Pagespeed.

  • Justen

    You should only ever have to have one ID selector in a rule unless that ID may have different parents situationally and should by styled differently accordingly. 99% of the time though if you are using multiple ID selectors it’s a waste of bytes. Another thing that helps is to look for common styles across many different elements and just use one master selector to apply that style. For instance if you have many different elements with color:blue, font-weight:bold,font-family:Sans Serif, select them all at once with as little specificity as possible (if your selectors are longer than your instructions for each element you won’t have saved any space). It also makes the stylesheet much more maintainable. In general refactoring once you’ve finished the stylesheet can cut the thing in half and save a lot of headaches down the road.

  • Justen

    Another point about use of @include is that it can’t be concurrently downloaded. With multiple link tags the client can download as many at one time as its max connections parameter, while files embedded with @link will first have to wait for their parent sheet to finish being interpreted, then will be downloaded one at a time in most cases.

    I wouldn’t rule out that some browsers have fixed this since last I looked into it, but one way or other you still have to wait for the interpreter to finish on each sheet with @include before their linked sheets get pulled down. If for organizational reasons you choose @include anyway, make one top-level stylesheet which only contains @include rules and don’t use them anywhere else.

    • Mark Cipolla

      Agreed. I’m against using @include, but in the server-side CSS apps (like those mentioned in the post above), they use the @include to concatenate the files together.

      Normal CSS files would make additional requests to the @include’d files, whilst the app will return a CSS file that has all the @include’d files concatenated into a single file.

      I like to have lots of files, for each section of my page. So I’ll make a css file that @includes all the other files, and am happy with it as the application will sort out the concatenation for me.

      • Schepp

        You both mistook @include for @import :)
        @include is a child of Keppler’s coolphptools’es syntax above…

  • exis7

    Another point worth making is that the more items in your selector, the longer it takes to parse the CSS. Using an ID is the quickest to parse, classes slower, and elements the slowest.

    The benefit may only be marginal but it all mounts up and for users of older browsers, such things can make a worthwhile difference. Not only that, but it promotes cleaner markup which is easier to work with :)