Performance aspects of Google’s HTML/CSS Style Guide

Posted: April 25, 2012 at 5:42 pm

Today Google released their HTML/CSS Style Guide. While it is full of great advice to help manage a growing code base among multiple developers, I thought it would be interested to review the web performance implications of each of its recommendations. Despite being a just style guide, nearly all of its rules had performance ramifications. For each rule I will:

  • Briefly quote Google’s style guide.
  • Link to the rule for more information
  • Discuss how the rule affects performances (either positively or negatively)
  • Mention any other related performance rules, and whether Zoompf’s free or paid offering currently detects the performance issue.

Let’s get started!

Omit the protocol from embedded resources.

Omit the protocol portion (http:, https:) from URLs pointing to images and other media files, style sheets, and scripts unless the respective files are not available over both protocols. (link)

This is a great recommendation for performance. I’ve talked about the advantages of protocol relative URLs in the past. Not only do they both reduce page size, protocol relative URLs prevent you from needlessly creating SSL connections. As an added benefit, protocol relative URLs are a bulletproof way to prevent mixed content warnings.

Applicable Zoompf Checks:

  • SSL Resource on non-SSL Page
  • Excessive Absolute URLs (Same Site)
  • Excessive Absolute URLs (External Links)

Bonus Performance Tip. While this advice is about linking resources, Zoompf recommends to you relative URLs for web content. So instead of linking to http://zoompf.com/blog/some-awesome-post you would use /blog/some-awesome-post. Not only does this reduce page size, but makes it easier to transfer content to new hostnames or restructure your site in the future.

Indent by 2 spaces at a time

Indent by 2 spaces at a time. Don’t use tabs or mix tabs and spaces for indentation. (link)

More of a style rule than performance. You should be minifying your HTML when you move it into production anyway which removes unneeded whitespace and resolves this problem.

Applicable Zoompf Checks:

  • Dynamic HTML Not Minified
  • Static HTML Not Minified

Use only lowercase

All code has to be lowercase: this applies to element names, attributes, attribute values (unless text/CDATA), selectors, properties, and property values (with the exception of strings). (link)

Using lowercase in HTML makes your pages more compressible, resulting in smaller pages.

Zoompf does not check specifically for this issue but does normalize your HTML to lowercase as part of our HTML minification analysis.

Trailing whitespace

Trailing white spaces are unnecessary and can complicate diffs. (link)

A good style rule, and since the document mentions diffs, this is mainly to make internal code management easier. As I said before, post processing your HTML, or minifying it when promoting it to the production environment resolves this issue and can slightly reduce the size of a page.

Applicable Zoompf Checks:

  • Dynamic HTML Not Minified
  • Static HTML Not Minified

Use UTF-8 (no BOM)

Make sure your editor uses UTF-8 as character encoding, without a byte order mark. Specify the encoding in HTML templates and documents via <meta charset="utf-8">. Do not specify the encoding of style sheets as these assume UTF-8. (link)

Standardizing on a single encoding is a good idea, and getting ride of the BOM saves 3 bytes. However I don’t suggest using anything inside the HTML, like <meta charset="utf-8">, to specify the charset. The Content-Type header should be the only thing you use to tell the browser about the charset. Encoding inside the document what the encoding format for a document is creates a chicken or the egg situation where the browser must parse the document to figure out how to parse the document. This creates performance problems and exposes you to XSS attacks. Google’s own documentation even references Zoompf for this.

Applicable Zoompf Checks:

  • Unnecessary <meta> Character Set (http-equiv)
  • Unnecessary <meta> Character Set (charset)

Comments

Explain code as needed, where possible. (link)

Comments are absolutely important, but they should not make it into production code. They needlessly increase the size of the resource, and often expose you to security risks.

For things like CSS and JavaScript, minification will remove the comments for your automatically. For HTML, especially dynamically generated HTML, consider using the code comments in the server-side language instead of HTML comments.

So instead of this:

    ...
    <a href="/public/">public</a>
    <!--
    Feature is not ready yet, disable until next release cycle
    <a href="/public/">public</a>
    -->
    ...

Replace it with something like this:

    ...
    <a href="/public/">public</a>
    <?php
    /*
    Feature is not ready yet, disable until next release cycle
    <a href="/public/">public</a>
    */
    ?>
    ...

Applicable Zoompf Checks:

  • Bloated HTML Tag (<comment>)
  • Excessive HTML Comments
  • Commented Out HTML
  • Dynamic HTML Not Minified
  • Static HTML Not Minified
  • JavaScript Not Minified (External File)
  • CSS Not Minified (External File)
  • JavaScript Not Minified (<script>)
  • CSS Not Minified (<style>)
  • Feed Not Minified

Action items

Highlight todos by using the keyword TODO only, not other common formats like @@. Append a contact (username or mailing list) in parentheses as with the format TODO(contact). (link)

TODOs are a quick way to remind you of additional tasks. Just make sure that TODOs are not included in content sent to the user. Since TODOs are placed inside of comments minification fixes this issue.

Zoompf does not check for TODO items specifically, but this issue will be flagged more generically by Zoompf comments and minification checks.

Use HTML5

HTML5 (HTML syntax) is preferred for all HTML documents: ‘<!DOCTYPE html>’. (It is recommended to use HTML, as ‘text/html’. Do not use XHTML. XHTML, as ‘application/xhtml+xml’, lacks both browser and infrastructure support and offers less room for optimization than HTML.) (link)

Smaller DOCTYPE means smaller bytes. XHML is also more bloated than HTML, requiring you to use closing tags and <CDATA> which [needlessly increases the size of your page](http://perfectionkills.com/optimizing-html/). Avoid XHTML, especially on mobile sites.

Zoompf does not currently check for HTML5 use, or mobile sites using XHTML.

Use HTML according to its purpose

Use elements for what they have been created for. (link)

Google’s example for this rule shows a <div> using a onclick to replicate a standard <a href=""> tag. Another common example is that developers with use an <a> tag with an empty href attribute, but use an inline onclick handler which simply navigates to a web page.Reinventing the wheel like that almost always results in larger markup, increase the size of the page.

Zoompf does not check for using elements properly.

Separate structure from presentation from behavior

Strictly keep structure (markup), presentation (styling), and behavior (scripting) apart, and try to keep the interaction between the three to an absolute minimum. (link)

Placing JavaScript and CSS into separate external files allows you to reuse common content and reduce the size of all of your pages. These external files can also be cached while HTML often cannot.

This is another good example of advice that is good for development and not good for production. Despite the guide advice, Developers can and should separate code into files as it logically makes sense, such as separating libraries. The same is true for CSS. However, you should not reference 8 JavaScript files in the HTML when the website moves to production. Those files should be combined and versioned as part of the publishing process.

Bonus Tip. Smaller files should be inlined into the document. Software like mod_pagespeed can do this automatically.

Applicable Zoompf Checks:

  • Common Style Attribute
  • Common Content (JavaScript Block)
  • Common Content (Style Block)

Do not use entity references

There is no need to use entity references like &mdash;, &rdquo;, or &#x263a;, assuming the same encoding (UTF-8) is used for files and editors as well as among teams. (link)

All of these symbols appear in UTF-8, so there is no reason to use HTML entities, reducing the size of your page.

Zoompf does not currently check for using entity references on UTF-8 encoded pages.

Omit optional tags (optional)

For file size optimization and scannability purposes, consider omitting optional tags. (link)

I disagree with this advice. While it makes sense to omit end tags of elements that have no meaningful inner HTML (<meta>, <link>, <img>, <script src="">), you are just asking for maintainence issues if you start omitting things like </p>. In fact, Google’s example of recommended HTML usage is actually a better example why this is a stupid practice.

If you truly want to do something like this, don’t try to do it in your source HTML or template files. Add these aggressive HTML minification optimizations as part of your publishing process when moving a website to a production environment.

Zoompf does not check for optional end tags being used.

Use valid CSS where possible

Unless dealing with CSS validator bugs or requiring proprietary syntax, use valid CSS code. (link)

CSS minification tools are very primitive. While JavaScript minifiers like YUI Compressor or Closure Compiler actually tokenize, parse, and build syntax trees to guide minification, CSS minifiers use regular expressions or primitive lexers. Invalid CSS often breaks these tools. Make sure your CSS is valid.

While Zoompf does not check for invalid CSS syntax, it does check to make sure that CSS resources referenced with a <link> tag or @import statement are, in fact, CSS files.

Use appropriate lengths for ID and class names

Use ID and class names that are as short as possible but as long as necessary. Try to convey what an ID or class is about while being as brief as possible. (link)

Shorter names are better than long names for performance. Zoompf does not currently check for long ID or class names.

Avoid qualifying ID and class names with type selectors

Unless necessary (for example with helper classes), do not use element names in conjunction with IDs or classes. (link)

In other words, ul#ref-list is not needed when #ref-list will do. This has three performance implications. First, simplifying how CSS selectors match speeds up rendering. Additionally, the rule is more generic, allowing it to be reused in more situtations and prevents the creation of redundant rules. Finally, smaller selectors mean smaller CSS files, which is always good for performance.

Zoompf does not currently check the specificity of CSS rules.

Omit Default or Unneeded Values

Google’s document lists a number of rules for omiting default or unneeded values from CSS. All of these rules lead to smaller CSS files, which is a good thing for performance. All of these rules can be automatically fixed with CSS minification.

Applicable Zoompf Checks:

  • CSS Not Minifed (External File)
  • CSS Not Minifed (<style>)

Conclusions

Every organization should use a style guide. For the most part, Google’s HTML/CSS Style Guide promotes good style advice that is also good performance advice, making it a good standard to use. Just remember, you should not make things easy for developers and the expense of your visitors. At the same time, don’t force a style on the developers that makes code or content harder to undestand for the sake of performance. Instead, use a build process to apply many of these optimizations automatically.

Want to see what performance problems your website has? I’ve mentioned only a few of the nearly 400 performance issues Zoompf detects when testing your web applications. You can get a free performance scan of you website now and take a look at our Zoompf WPO product at Zoompf.com today!

Optimizing Gradients

Posted: March 23, 2010 at 6:49 pm

Gradient backgrounds are a common visual element on modern websites. And while you can use browser specific CSS extensions to directly create gradient backgrounds with pure CSS the much more common method is to use an image. Traditionally, when a web designer wants to create a gradient to a webpage, they use a program like Photoshop or The Gimp to create a small image containing the gradient they want. They then use CSS to set this image as the background for a specific element and then use repeat-x or repeat-y to spread the gradient image along the entire length of the element. This provides us with the chance for a new performance optimization technique!

Consider the image above that a Sven, a long time Zoompf user, sent in. This image is 38 pixels wide and 91 pixels tall. As you can see there is a gradient that goes from dark gray at the top of the image to white at the bottom. This image is used on the website to provide a background gradient for section titles. The website’s CSS uses the repeat-x directive to fill the section title along the X-axis with the gradient. Which raises the question “Why is the image 39 pixels wide?” After all, the change in colors is along the Y-axis (from the top of the image to the bottom). The width of the image is meaningless. It adds nothing to the image. If you were to open this image in a program like Photoshop you would see that every pixel has the same color as the pixel to it’s left or right. It cannot be any other way. Otherwise when the image is repeated one after another along the X-axis you would see spots or seams where the colors were different. Since CSS is used to repeat this image in the X-axis direction, there is no reason for the image to be larger than 1 pixel wide! Converting the 38×91 pixel image to a 1×91 reduces the size of the file by over 65%!

Let’s try a real example. Consider this gradient from Yahoo. This image is actually a sprite of several different gradients! It is 5 pixels wide and 3302 pixels tall and is 3466 bytes. Again, we can confirm that the extra 4 pixels in width provide no value. All the pixels in this image have the same color value as the pixels to the right or left. Using Photoshop, we cropped the image to be 1×3302 pixels with a size of 1920 bytes. This is a savings of 45% with absolutely no loss to image quality or user experience!

We performed this optimization on a sample of 300 or so gradient images. On average we reduced file size by 30-70%. PNG images tended to see an improvement of 10-30%.

Browser Performance Impact

Are there any negative effects to using gradient images that are only 1 pixel in length along the axis they repeat? This is what Sven wanted to know when he emailed the image. Consider an image that’s 32 x 300 images. It is repeated along the X-axis using CSS and is used as a background for a <DIV> that is 96 pixels wide. To “draw” an image on the screen, the fundamental operation the browser is doing is copying the bytes of the image into the buffer of bytes that display the screen. That means to draw the gradient background the browser has to copy the bytes of the 32 x 300 pixel image into the video memory 3 times (because 3 times 32 is 96). Consider if we had a 1 x 100 pixel image. The browser has to copy the bytes of the 1 x 300 pixel image into the video memory 96 times (because 1 times 96 is 96). So, it would seem that using a 1 x 100 pixel image is 32 times slower than using a 32 x 100 pixel image. Remember we aren’t talking about browser repaint or reflow events (where the browser has to recalculate where all the text and images goes and then redraw). We are talking purely about how quickly the computer can draw an image.

It sounds like we might have a performance problem.

Only we don’t. Computers can move data around very quickly. We are talking nanoseconds (10^-9). Meanwhile, transferring data over Internet connections is typically measured in millisecond or microseconds (10 ^ -3 or 10 ^ -6). So even though smaller images may make the browser do more work, even 32 times more work, the difference is so infinitesimal that they are not noticeable to the user. The time saving you will get by reducing the amount of data you have to send over the slow network however is impactful and beneficial.

Conclusions

The fact that gradients using images rely on CSS to repeat the image allows us to reduce the width or height of the gradient image without any visual difference. Performance is improved because we have reduced the size of the image. This technique can be applied to all images that are used as gradients. If a gradient image repeats along the X-axis it should only be 1 pixel wide. If a gradient image repeats along the Y-axis it should only be 1 pixel tall. As we saw the the example gradient from Yahoo, even gradient images that are already quite small in terms of dimensions can drastically reduce their size even further by reducing the width or height to 1 pixel.

Want to see what performance problems your website has? Oversized Gradient Image is just one of the 300+ web performance issues Zoompf detects when scanning your web applications. Get your instant free web performance assessment at Zoompf.com today!

Zoompf Check #300! Or: Gateway’s got a problem…

Posted: March 4, 2010 at 3:17 pm

People often ask how we discover new performance issues. Without a doubt the #1 way we discover new issues is simply by looking at websites and seeing how they work. Not a customer engagement goes by where we don’t find at least one new web performance issue that we add to our growing database of web performance issues. This why Zoompf has added over 150 performance checks since we went public with our offerings. In this blog post we are going to give you the back story around a cool performance problem we found. In fact, it was so interesting and impact it became our 300th check in our database of web performance issues!

Picture of a cork popping out of a bottle

The Strange Case of CSS Resources

We recently made a few changes to our CSS parser and we were testing the new features against a few dozen pages to ensure we hadn’t broken anything. While testing, we noticed something odd on Gateway’s website. All of the background images in one of the style sheets for gateway.com were served over an encrypted SSL connection. In other words, the style sheet http://www.gateway.com/css/cms/styles.css is served over a plain unencrypted HTTP connection. However it includes links to background images like https://cdn.gateway.com/media/cphp/themes/default_bg.gif which are served over an encrypted SSL connection. What’s odd is the web server will serve those background images just fine if you request them using HTTP instead of HTTPs. It’s even weirder since very little of Gateway’s website even uses SSL. In fact, trying to access the root of the Gateway’s website using HTTPS will redirect you to the HTTP version.

So, certainly something weird, but is this a performance issue? After all, the developers just added a few extra “s” characters to their CSS. So what if maybe a little bit of SSL gets used. What are the performance implications of that?

Actually, they are huge!

SSL Primer

HTTPS is HTTP traffic sent over an encrypted SSL tunnel. SSL is expensive for 2 reasons (documented here and here). The first is the SSL handshake, where it is negotiated between the client and the server what protocols will be used and keys are exchanged. This involves the use of asymmetric key encryption with is extremely math heavy and quite slow. Then there is bulk data encryption, which is where the server is using symmetric key encryption. Symmetric key encryption is much faster than asymmetric key encryption, but can be much slower than sending unencrypted data. (How much slower is beyond the scope of this article. Suffice it to say that the performance impact of SSL is sufficiently large that there is an entire market for SSL acceleration products).

So what’s the impact in this situation? Well, the extremely expensive initial SSL negotiation must be done for the two initial connections to the web server. Each of these negotiations takes between 250 milliseconds to 350 milliseconds. This is in addition to the overhead of making the TCP connection and the negative impact of TCP’s Slow start and congestion control. Even reusing pre-negotiated keys a connection close is expensive, typically costing between 60 milliseconds and 100 milliseconds.

The Performance Impact

That doesn’t sound too bad but see how it affects Gateway. Examining this waterfall graph for www.gateway.com shows that 1.5 seconds, or over 25% of the page load time for Gateway.com, is due to the overhead of SSL! It’s hard to believe but the simple additional of 14 “s” characters to the page caused 1.5 seconds of delay! Further more Gateway’s web server is going to be working about twice as hard to push encrypt and serve those resources! Server load, power, cooling, and availability are all adversely affected.

(Notice there are a lot of other problems with Gateway’s website that contributed to the damage the SSL issue caused. Specifically they were not using persistent connection which caused a dozen of the smaller re-use negotiations to occur. Luckily Zoompf Check #177 and #178 detected all these closed persistent connections!).

Wow. So how did this happen? It could be for a lot of reasons, all of them fairly simple to make or innocent. It could have been a simple typo. It could have been left over from a redesign where that style sheet was used exclusively inside of the SSL portion of the site. It could be that this style sheet is used in both the SSL and non-SSL portions of the site, but to avoid a mixed content warning, the resources are referenced using SSL. The solution to this is simple. The style sheet should use protocol relative URLs to reference the images. That way if the style site is in the SSL portion of the website (and referenced using an https URL) the background images will requested using HTTPS. And when the style sheet is in the non-SSL portion of the website (and referenced using an http URL) the background images will be requested using HTTP.

It is both cool and scary that such a simple issue can have huge performance implications. And unfortunately none of the free tools like YSlow or PageSpeed would have alerted you to the issue. Until now.

It is with great pleasure and pride that we announce Zoompf Check #300: SSL Resources on Non-SSL Page. That this is such a simple issue to have and at the same time it causes such as massively negative impact makes it worthy to be our 300th check.

Want to see what performance problems your website has? Finding SSL Resource on Non-SSL pagesis just one of the 300 issues Zoompf detects when analyzing your web applications. Get your instant free mini web performance assessment at Zoompf.com today!

Browser Performance Problem with CSS "print" Media Type

Posted: December 7, 2009 at 3:02 pm

I ran across an article today that shocked me. Geert De Deckere wrote how you can save an HTTP request by combining the CSS files for the print and screen media types.

Wait, I thought. What? Why do I need to do this? What behavior is this correcting? I was very confused. Maybe you are too.

image of CSS code in an editor

CSS allows you to define styling information for different media types. CSS could tell a browser that is rendering to a TV screen to style the same content differently from a browser rendering on a mobile phone. The HTML content is all the same. Media types simply define which style rules apply for which devices. CSS also defines a print media type which is the style to use when styling a page that is being printed. Browsers should be smart about only downloading the style sheet with the media type for the device they are rendering. Firefox on my laptop is should not fetch the mobile.css style sheet whose media type is handheld. And luckily browsers are smart and don’t download CSS files for media types that they don’t support.

Except for the CSS media type print.

Geert’s article and advice were predicated on the claim that web browsers will download external style sheets with the print media type even if you don’t print the page. Is this true? To find out I built a quick test page:

<html> <head> <title>CSS Media Tests</title> <link rel="stylesheet" type="text/css" href="screen.css" media="screen" /> <link rel="stylesheet" type="text/css" href="print.css" media="print" /> </head> <p> Hello! <img src="new-logo.png"> </p> </html>

Wow! Geert’s claim was true! All major desktop browsers that I tested (Firefox 3.5, IE 7, Chrome 3.0 and Safari 4.0) will download external style sheets whose media type is print even if you don’t print the page! This is hurts performance for no good reason. Currently your browser must make one HTTP request and download screen.css. But then your browser has to make an additional HTTP request to download a file full of content that it does not need. Worst of all, the browser will not start rendering the page until it has grabbed the completely unused print.css file!

This is very silly behavior. Especially given that virtually none of your website visitors are going to print any of your web pages, unless you are a website like Google Maps. Try and remember: “when was the last time your printed a web page?” Unfortunately all 4 browser I tested all downloaded print.css even though I never printed the page. Firefox, IE, and Chrome all downloaded print.css in order as if it was a external CSS file whose media type was screen. Looking through a proxy the request order was:

  1. css-media-test.html
  2. screen.css
  3. print.css
  4. new-logo.png

Safari 4.0 however, downloaded the content in this order:

  1. css-media-test.html
  2. screen.css
  3. new-logo.png
  4. print.css

Safari was smart enough to defer downloading but did still downloaded it. I do not know if Safari delayed firing the window.onload event until after print.css downloaded or not. WebPageTest confirms that IE does not start rendering the page until print.css is downloaded. The fact that Firefox and Chrome both requested content in the same order as IE leads me to think they also delay rendering.

Possible Solution?

Geert proposed a solution to this problem. He recommends combining the two external CSS files into a single CSS file and use @media directives inside the CSS file to separate the style info for screen from the style info for print. You end up with a single CSS file that looks like this

@media screen { /* contents of screen.css here */ } @media print { /* contents of print.css here */ }

This solution does not sit well with me. Yes, by combining the two CSS files and using @media directives you can remove an HTTP request. You now only have to download a single CSS file whose size will be smaller than the sum of the two original file sizes because a single large file will compress better. However your visitors still have to download a large amount of CSS content. 30-40% of that content is printer-centric style information which no one will ever actually use anyway, and the browser will not start to render the page until all this useless data has been downloaded. (Interestingly enough Zoompf free Web Performance Scan checks style blocks and CSS files for @media directives and recommends you break them into separate style sheets to prevent unnecessary rules from being downloaded. I had to modify the check to allow @media print directives when I found this solution.)

A Different Solution

I believe there is a different and perhaps better solution. You can defer downloading print.css by using JavaScript to dynamically add a <LINK> tag pointing to the external CSS file with the print media type after the page has loaded! This solution means the browser only needs to make 1 HTTP request and less CSS content needs to be downloaded to start drawing the page. This will have a faster “Time to Render” than a single CSS file as less data is downloaded. The extremely small number of people who do print your web page will still get the style sheet necessary for them to print. You can also use a <NOSCRIPT> tag in the <HEAD> to link to print.css. This means anyone who has JavaScript turned off will the performance hit all of your visitors are currently taking and request both external style sheets. The deferring print.css solution looks like this:

<html> <head> <title>CSS Media Tests</title> <link rel="stylesheet" type="text/css" href="screen.css" media="screen" /> <noscript> <link rel="stylesheet" type="text/css" href="print.css" media="print" /> </noscript> </head> <p> Hello! <img src="new-logo.png"> </p> <script> window.onload = function() { var cssNode = document.createElement('link'); cssNode.type = 'text/css'; cssNode.rel = 'stylesheet'; cssNode.href = 'print.css'; cssNode.media = 'print'; document.getElementsByTagName("head")[0].appendChild(cssNode); } </script> </html>

You reduce initial request count and download size at the cost of greater complexity and more markup. This code could be improved. A more scalable solution would be for the JavaScript code to look in the <HEAD> and parse any <LINK> tags inside of a <NOSCRIPT> with a print media type and create new LINK elements dynamically.

Solving the problem

A summary of the problems and the two solutions appears below. This table assumes two CSS files (screen.css and print.css) each 30 kilobytes and size and a combined CSS file (all.css) whose size is 55 kilobytes.

MethodHTTP Requests before “Start Render”CSS Downloaded before “Start Rendering”# HTTP Requests after “Onload”Content Download after “Onload”
No Optimization260 Kb00 Kb
Single CSS file all.css155 Kb00 Kb
Deferring print.css130 Kb130 Kb

Which solution works best will vary with your situtation. The status quo is 2 HTTP requests to deliver 60 Kb of content before the browser can start rendering. A single CSS file reduces that to 1 HTTP requests and 55 Kb of content before the browser can start rendering. Deffering print.css also only requires 1 HTTP request before pageload but only sends 30 Kb before the browser can start rendering. If you have a small print.css file it might be better to use a single CSS file with @media directives. The overhead of serving a single larger CSS file containing unused style dat aand the delay that adds until the browser can start rendering might be so small it does not matter. However if you have a larger print.css file deferring the print.css download until after page load would provide a great performance benefit.

The moral of the story here is that the browser creators need to remove this performance defect from their code. Ideally the print CSS media type data should not be downloaded until the print dialog box appears, either from user action or using window.print() in JavaScript. Next best solution would be for the browser to automatically defer the downloading of “print” CSS media type data until after the page has downloaded. In the mean time, you can use either the single CSS file solution or the deferring print.css solution to make your web pages load faster!

Want to see what performance problems you have? An appropriately placed <LINK> tag and proper use of CSS @media directives are just two of the 200+ performance issues Zoompf detects while assessing your web applications for performance. You can sign up for a free mini web performance assessment at Zoompf.com today!