The challenges to a front-end developer can be numerous. In addition to performing our day-to-day tasks, we are often expected to know a little (or a lot) about a wide array of subjects. Graphics, languages, user experience, accessibility, source control, security, browser compatibility, content management systems, and more.
But to show off your skills in all of those areas, the user must be able to first load the page. And increasingly, users aren't willing to wait for slow experiences. Therefore, maintaining a speedy experience should be very high on a developer's checklist.
There are two divisions of speed that I'd like to cover - raw and perceived.
- Raw speed is the time it takes for computers to do their work - interpreting the programming language, transmitting files, receiving files, etc.
- Perceived speed is how "snappy" the experience feels to the user, which utilizes the ideas of UX much more heavily.
Checklist for Increasing The Raw and Perceived Speed of Web Experiences
Here's a starting checklist for both front-end and back-end developers that will increase both raw and perceived speed. In decreasing order of importance:
- Send smaller files
- Send less files
- Send minified + compressed files
- Choose optimization techniques that fit the content
- Remove or delay third-party scripts
- Send files in a certain order
- Send files from cache
- Write more performant code
- Use async or lazyloading when appropriate
- Send files from different domains
- Send files that are physically closer (CDN)
I will be addressing the first four items as part of the Resource Weight conversation. Resource Weight is quite simply, how much information the server sends to the browser. It's your first line of defense in keeping your experiences snappy.
First, let's define the "subjects" that are available for scrutiny under these maxims.
- Images
- JS
- CSS
- HTML
Interesting how these turn out to be the basic building blocks of a webpage! Despite the hullabaloo surrounding new technologies, frameworks, and workflows, the basics still matter most.
Images: #1 Culprit of Slow Web Experiences
So let's take a look at the #1 culprit of slow experiences - images. Web experiences are dominated by images. Running most top sites (try yours too!) through webpagetest.org will provide insight into the breakdown. The test I ran for The New Yorker claimed that 56.3% of the bytes sent from the server(s) were attributed to images.
So besides cutting down on the number of images in our experiences, what can we do to cut down on their load impact? First, we need to determine what flavor of image we are dealing with - raster or vector.
Reducing the Load Impact For Vector Images
There are some baseline questions to ask yourself when dealing with vectors.
- Is the image seldom or frequently used?
- Is the image single or multicolor?
- What's the complexity of the image?
- What browser features should we support?
Vector Techniques
- Inline Image (src) - one-off, content images
- Icon Font - need to change color easily, group of multiple
- SVG:inline(html) - need to change color, single
- SVG:css reference url - no need to change color, single, frequently used, needs to be separate for some reason (ie. logo)
- SVG:css data-uri - everything above, but is not very complex
- SVG:sprite - not as easy color change, multiple
Using vectors in general is a good place to start in cutting your resource weight. Typically, I've been a fan of the icon font and CSS data uris to cover my vector needs. But as the world turns, the browsers that we decide to support grow stronger.
If you still need to support IE8, I would suggest sticking with icon fonts for a nearly bulletproof solution. There are two great solutions for this - one for the more graphically inclined at IcoMoon, the other for the more seasoned developer who is familiar with grunt at Grunt Webfont.
If you can move away from IE8, then you basically have full SVG support, save a few stranger bugs with IE and using SVGs as background images. In that situation, I would encourage trying out the different SVG implementations to understand how they work. SVG sprites are a good way to go, and Chris Coyier has a primer on this at CSS-Tricks.
Lastly, there's an exciting tool from Filament Group of Respond.js, Picturefill, and one of my favorites, fixed-sticky. It's Grunticon and if used wisely, can really step your SVG game up.
Reducing the Load Impact For Raster Images
Some questions to pose for raster images:
- Is the image graphic or realistic?
- Is the intended use content (photo of a person) or decoration (background texture)
- Are there different sizes generated on the fly?
- What browser features should we support?
Raster Techniques
Raster image techniques are slightly more limited than those for vector images, although there is certainly complexity with each choice. Inline images and spriting should be in the novice developer's toolbox already, so I won't expound on those.
- Inline Image - content images, single
- Sprite - frequently used, multiple
- Compressive - content image, if it works with the technique
- Picturefill (srcset + picture element) - want to load different sizes or do art direction
For Raster Images: Compressive
Let's examine compressive. Compressive is a technique also from the Filament Group that I've been using for quite some time with success. It started out as a proof-of-concept but in the right environment, it can be a great solution.
The gist is:
Favoring large-dimension, high-compression over exact dimension with medium compression
So basically, instead of eyeballing a decent compression for the exact image size we want to display to our users, we are going to give the image extra resolution (size), and compress heavily. In practice, for modern devices and screens, this works out pretty well.
A word of warning though, this technique doesn't really help you with graphic images. Saving as a PNG with no compression is usually a better route for those.
Below, you'll see an image that I took while in Arches National Park with its associated resolution, compression level, and size before and after usingĀ ImageOptim (which I highly recommend for all images before uploading to server).
800px wide, 100%
800px wide, 50%
1600px wide, 100%
1600px wide, 50%
1600px wide, 0%
1600px wide, 10%
If you examine each image closely, you'll see the differences.
So, what? The point of the compressive image technique is that you can use a low number of generated images to suit a wide array of device sizes. With only one or two generated images, you can probably serve all devices from 320px up to 1600px wide. If cutting down on the number of generated images is useful to you, then this technique is worth considering.
One drawback of using this technique is that devices with limited memory may suffer the consequences of loading all those pixels. Just be aware of shoving 4x the amount of pixels into an older or limited mobile device.
For Raster Images: PictureFill
The next technique is called Picturefill (thanks again, Scott!). It's a way to use the img srcset attribute and/or the picture element for all browsers. I'm a fan of the picture element with source tags, but there are other ways to write your code.
Below is an example:
<picture> <source srcset="extralarge.jpg" media="(min-width: 1000px)"> <source srcset="large.jpg" media="(min-width: 800px)"> <img srcset="medium.jpg" alt="Laser-eyed dolphin"> </picture>
It becomes clear what the point of using this markup is - to only load the image that fits the media query associated with it. This is an obvious win for performance, and can be used in conjunction with many of the other techniques listed today, including the compressive technique.
Cutting down on the number and weight of your resources is a great first step in increasing raw and perceived performance. Being wise about which techniques you choose to achieve your goals is also critical. Minify and compress your final output, and you're on your way to better PageSpeed scores.
What's worked for you? What hasn't?