Friday 6 September 2013

Performance & Organization - Part 2

Reusable Code

One of the largest performance drawbacks comes with bloated file sizes and unnecessary browser rendering. One quick way to help largely cut down on CSS file sizes is to reuse styles as much as possible. Any repeating styles or interface patterns should be combined, allowing code to be shared. If two modules share a background, rounded corners, and a box shadow there is no reason to explicitly state those same styles twice. Instead they can be combined, within a single class, allowing the styles to be written once and then shared.
Reusing code doesn’t have to come at the cost of semantics either. One technique would be to pair selectors together, separating them with a comma, allowing the same styles to be inherited across two selectors. Another approach, often seen within the OOCSS and SMACSS methodologies previously mentioned, includes binding styles to one class, then using multiple classes on the same element.
  1. <!-- Bad -->
  2. .news {
  3. background: #eee;
  4. border-radius: 5px;
  5. box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.25);
  6. }
  7. .social {
  8. background: #eee;
  9. border-radius: 5px;
  10. box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.25);
  11. }
  12. <!-- Good -->
  13. .news, .social {
  14. background: #eee;
  15. border-radius: 5px;
  16. box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.25);
  17. }
  18. <!-- Even Better -->
  19. .modal {
  20. background: #eee;
  21. border-radius: 5px;
  22. box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.25);
  23. }
Which approach you take doesn’t make a huge difference, so long as code is being shared and reused, and the overall file size is reduced.

Minify & Compress Files

Simply removing duplicate and unnecessary code is the best way to cut down on file size, however there are additional ways. One way includes minifying and compressing files, such as HTML, CSS, and JavaScript files. Additionally, images may be compressed, removing any unnecessary comments and color profiles.

gzip Compression

One of the more popular types of file compression is called gzip. gzip compression takes common files, including HTML, CSS, JavaScript, and so forth, and identifies similar strings to compress down. The more matching strings identified, the smaller the file can be compressed, thus sending a smaller file from the server to the browser.
Setting up gzip is fairly painless, and the HTML5 Boilerplate has done a great job of getting this going. To gzip files an.htaccess file needs to be added to the root directory of the web server, labeling the specific files to be gzipped. The dot at the beginning of the file name is correct, as the .htaccess file is a hidden file.
Within the HTML5 Boilerplate, part of the .htaccess file is earmarked for gzip compression. Reusing all or part of the.htaccess file within your own server will help set up gzip compression. Additionally, it is worth noting that.htaccess files only work on Apache web servers, which need to have the following modules enabled.
  • mod_setenvif.c
  • mod_headers.c
  • mod_deflate.c
  • mod_filter.c
  • mod_expires.c
  • mod_rewrite.c
Generally speaking this isn’t an issue, and some web servers may even set up compression for you. After all, it is in the web server’s best interest to compress files too.

Measuring Compression

Within the Google Chrome web browser the web inspector gives a plethora of data around performance, particularly within the Network tab. Additionally, there are a few websites that help identify if gzip compression is enabled.
gzip Overview Screenshot
Fig. 1.01The Network tab identifies each file loaded within the browser and displays the file size and load time. Notice how gzipping has reduced the file sizes by around 60%.
gzip Detail Screenshot
Fig. 1.02
Looking at a file specifically identifies what type of compression encoding the browser supports. In this case gzip, deflate, and sdch are all supported as noted within the request headers.
Looking at the response headers identifies that the file was sent using the gzip compression encoding.

Image Compression

Cutting down the size of a text file helps, but you get even better results by compressing the file size of images. The total file size of all the images across a website can quickly add up, and compressing images will greatly help keep the file size under control.
Many people steer away from compressing images in fear that compression involves reducing the quality of the image itself. For the most part this is incorrect, and images can be compressed in a lossless fashion, allowing unnecessary color profiles and comments to be removed from the image without changing the quality of the image at all.
There are a handful of tools to help compress images, two of the best are ImageOptim for Mac and PNGGauntlet for Windows. Both of these services compress the most commonly used image formats, specifically JPG and PNG files.

Image Compression Demo

UNCOMPRESSED, 455KB
Uncompressed Ocean Picture
COMPRESSED, 401KB
Compressed Ocean Picture
ImageOptim Screenshot
Fig. 1.03Using ImageOptim the above image was reduced over 14% without any reduction or loss in quality.
It should also be noted, setting an image’s dimensions in HTML by way of the height and width attributes does helprender the page quicker, setting aside the appropriate space for the image. Understand, these attributes are to only be used to identify the exact image dimensions and not to shrink an image. Using a larger image, then scaling it down with the height and width attributes is bad practice as it loads more data than necessary.
  1. <img src="ocean.jpg" height="440" width="660" alt="Oceanview">

Reduce HTTP Requests

Next to file size, the number of HTTP requests a website makes is one of the largest performance pitfalls. Each time a request is made to the server the page load time increases. Some request have to finish before others can start, and too many request can bloat the server.

Combine Like Files

One way, and perhaps the easiest way, to reduce the number of HTTP requests is to combine like files. Specifically, combine all of the CSS files into one and all of the JavaScript files into one. Combining these files then compressing them creates one, hopefully small, HTTP request.
  1. <!-- Bad -->
  2. <link href="css/reset.css" rel="stylesheet">
  3. <link href="css/base.css" rel="stylesheet">
  4. <link href="css/site.css" rel="stylesheet">
  5. <!-- Good -->
  6. <link href="css/styles.css" rel="stylesheet">
In general, the CSS for a web page should be loaded at the beginning of the document within the head, while the JavaScript for a web page should be loaded at the end, just before the closing body tag. The reason for these unique placements is because CSS can be loaded while the rest of the website is being loaded as well. JavaScript, on the other hand, can only render one file at a time, thus prohibiting anything else from loading. One caveat here is when JavaScript files are asynchronously loaded after the page itself is done rendering. Another caveat is when JavaScript is needed in helping render the page, as such the case with the HTML5 shiv.

Image Sprites

The practice of spriting images within CSS includes using one background image across multiple elements. The goal here is to cut down the number of HTTP requests made by using multiple background images.
To create a sprite take a handful of background images, ones that are commonly used, and arrange them into one single image. Then using CSS add the sprite as a background image to an element, and use the background-positionproperty to display the correct background image.
Think of the background image sliding around behind elements, only to expose the proper background image on a given element. For example, if an element is 16 pixels wide by 16 pixels tall it can only expose a background image of 16pixels by 16 pixels, with the rest of the background image being hidden.
Menu Sprite
Fig. 1.04Here is a sprite for a text editor menu, outlined with guides for reference of how the images background position will change.
Using the image sprite above, a menu can be created by using the image sprite as a background on the span element. Then, using classes to change the background position of the image sprite, different icons can be shown accordingly.
HTML
  1. <ul>
  2. <li><a href="#"><span class="bold">Bold Text</span></a></li>
  3. <li><a href="#"><span class="italic">Italicize Text</span></a></li>
  4. <li><a href="#"><span class="underline">Underline Text</span></a></li>
  5. <li><a href="#"><span class="size">Size Text</span></a></li>
  6. <li><a href="#"><span class="bullet">Bullet Text</span></a></li>
  7. <li><a href="#"><span class="number">Number Text</span></a></li>
  8. <li><a href="#"><span class="quote">Quote Text</span></a></li>
  9. <li><a href="#"><span class="left">Left Align Text</span></a></li>
  10. <li><a href="#"><span class="center">Center Align Text</span></a></li>
  11. <li><a href="#"><span class="right">Right Align Text</span></a></li>
  12. </ul>
CSS
  1. li {
  2. float: left;
  3. list-style: none;
  4. margin: 0 2px;
  5. }
  6. li a {
  7. background: linear-gradient(#fff, #eee);
  8. border: 1px solid #ccc;
  9. border-radius: 3px;
  10. display: block;
  11. padding: 3px;
  12. }
  13. li a:hover {
  14. border-color: #999;
  15. }
  16. li span {
  17. background: url("sprite.png") 0 0 no-repeat;
  18. color: transparent;
  19. display: block;
  20. font: 0/0 a;
  21. height: 16px;
  22. width: 16px;
  23. }
  24. .italic {
  25. background-position: -16px 0;
  26. }
  27. .underline {
  28. background-position: -32px 0;
  29. }
  30. .size {
  31. background-position: -48px 0;
  32. }
  33. .bullet {
  34. background-position: -64px 0;
  35. }
  36. .number {
  37. background-position: -80px 0;
  38. }
  39. .quote {
  40. background-position: -96px 0;
  41. }
  42. .left {
  43. background-position: -112px 0;
  44. }
  45. .center {
  46. background-position: -128px 0;
  47. }
  48. .right {
  49. background-position: -144px 0;
  50. }

Image Data URI

Additionally, instead of spriting images, the encoded data for an image can be included within HTML and CSS directly by way of the data URI, removing the need for a HTTP request all together. Using the image data URI works great for small images, likely to never change, and where the HTML and CSS can be heavily cached. There are, however, a couple of problems with data URIs. They can be difficult to change and maintain, leading to having to generate another encoding. And, they don’t work in older browsers, specifically Internet Explorer 7 and below.
If using data URIs helps cut down a few HTTP requests, and the HTML or CSS can be heavily cached, the benefits tend to outweigh the risk. A few tools to help generate data URIs include converters and pattern generators. Be careful though, and always double check to see that the actual data URI is less weight than the actual image.
HTML
  1. <img height="100" width="660" alt="Rigged Pattern"
  2. src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAICAYAAADA
  3. +m62AAAAPUlEQVQYV2NkQAN9x+z/F1kdZEQXRxGAKcKmGK4QXRKdD1aIyzpkcUZcimB
  4. uhMljOBrdEzAbiVIIUky0QgBkMCabd5DVAwAAAABJRU5ErkJggg==">
CSS
  1. div {
  2. background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAICAYAAADA
  3. +m62AAAAPUlEQVQYV2NkQAN9x+z/F1kdZEQXRxGAKcKmGK4QXRKdD1aIyzpkcUZcimB
  4. uhMljOBrdEzAbiVIIUky0QgBkMCabd5DVAwAAAABJRU5ErkJggg==") repeat;
  5. }

Image Data URI Demo

Cache Common Files

Another way to help cut down HTTP requests, and to serve up pages faster, is to cache common files. When a page loads for the first time specific files may then be cached. Now the browser doesn’t have to request the same files again on repeating visits for quite some time. How long a period of time is up to you, all depending on how long you would like users to hold on to specific file types.
As with gzipping files, setting the expires headers for caching files can be set within the .htaccess file. And again, the HTML5 Boilerplate is one step ahead of us. In their .htaccess file there is a section earmarked for expires headers.
Images, videos, web fonts, and common media types are often cached for a month, while CSS and JavaScript files are often cached for a year. Should the CSS, or any other file, change more often than once each year the file name will need to be changed, preferably versioned, in order to be loaded. Alternatively, the expires headers can be changed to a smaller period of time.
  1. ExpiresByType text/css "access plus 1 year"
  2. ExpiresByType application/javascript "access plus 1 year"
Changing the "access plus 1 year" value to "access plus 1 week" is better suited for CSS and JavaScript files that are changing weekly but are not version controlled with separate file names. For accepted expires header values reference the mod_expires syntax.