March 23, 2010

Optimizing Gradients

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!

March 4, 2010

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

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!

December 7, 2009

Browser Performance Problem with CSS "print" Media Type

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!