Benefits: reducing network latency, enhancing compression, and faster browser loading and execution.
Combining external scripts into as few files as possible cuts down on round-trip time (RTT) and delays in downloading other resources.
With the advent of HTTP 2.0 protocol, this process will have to be reversed for optimization because of request-response multiplexing.
Compressing resources with gzip
or deflate
can reduce the number of bytes sent over the network. Most modern browsers support data compression for HTML, CSS, and JavaScript files.
Don't use gzip for image or other binary files: Image file formats supported by the web, as well as videos, PDFs and other binary formats, are already compressed; using gzip on them won't provide any additional benefit, and can actually make them larger.
Benefits: decreased latency, increased parallelism, better caching, high availability and scalability.
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script> <script>window.jQuery || document.write('<script src="/js/jquery-1.11.0.min.js"><\/script>')</script>
If you do have some critical JavaScript code to modify DOM initially (not very common) or if you have a lazy loading code, inline the JavaScript at the bottom of your page to avoid some round-trip time (RTT).
Deferring loading of JavaScript functions that are not called at startup reduces the initial download size, allowing other resources to be downloaded in parallel, and speeding up execution and rendering time. Here are a few options to defer the loading of JavaScript on your page:
defer
attribute on script
elements to indicate to a browser that the script is meant to be executed after the document has been parsed. This will not stop the browser from downloading the code, so better use the lazy loading techniques given below.
<script type="text/javascript" src="your_script.js" defer></script>
defer
attribute is only for external scripts (should only be used if the src
attribute is present).defer
attribute on core libraries like jQuery. It might cause errors if the code relying upon a core library executes before it's loaded.function loadScript(url, callback) { var script = document.createElement("script") script.type = "text/javascript"; if (script.readyState) { //IE script.onreadystatechange = function () { if (script.readyState == "loaded" || script.readyState == "complete") { script.onreadystatechange = null; callback(); } }; } else { //Others script.onload = function () { callback(); }; } script.src = url; document.getElementsByTagName("head")[0].appendChild(script); } loadScript("the-rest.js", function () { Application.init(); });
var xhr = new XMLHttpRequest(); xhr.open("get", "file1.js", true); xhr.onreadystatechange = function () { if (xhr.readyState == 4) { if (xhr.status >= 200 && xhr.status < 300 || xhr.status == 304) { var script = document.createElement("script"); script.type = "text/javascript"; script.text = xhr.responseText; document.body.appendChild(script); } } }; xhr.send(null);
// Load single or multiple JS files and execute a callback when they've all finished. LazyLoad.js(['foo.js', 'bar.js', 'baz.js'], function () { alert('all files have been loaded'); });
jQuery.getScript()
method to lazy load and execute scripts on demand.
$.getScript("foo.js") .done(function (script, textStatus) { ... }) .fail(function (jqxhr, settings, exception) { ... });
In order to load a page, the browser must parse the contents of all <script>
tags, which adds additional time to the page load. By minimizing the amount of JavaScript needed to render the page, and deferring parsing of unneeded JavaScript until it needs to be executed, you can reduce the initial load time of your page.
async
attribute on script
elements to indicate that the browser should, if possible, execute the script asynchronously.
<script type="text/javascript" src="your_script.js" async></script>
async
attribute is only for external scripts (should only be used if the src
attribute is present).eval()
method to execute it on demand. Make sure you strip out (or replace) comment blocks in your JavaScript first. The only saving here is that you are not making one extra round-trip to get the JavaScript code and on the contrary if your JavaScript code is too big, you are increasing your initial payload. You should prefer the deferred loading techniques mentioned above over this. More Info
<html> ... <script id="lazy"> /* alert("Hello World! I am feeling Lazy."); */ </script> <script> function lazyLoad(id) { var lazyElement = document.getElementById(id); var lazyElementBody = lazyElement.innerHTML; var jsCode = lazyElementBody.replace(/^[\s\xA0]+\/\*|\*\/[\s\xA0]+$/g, ""); eval(jsCode); } </script> <div onclick="lazyLoad('lazy')">Lazy Load</div> </html>
eval()
.Setting an expiry date or a maximum age in the HTTP headers for static resources instructs the browser to load previously downloaded resources from local disk rather than over the network.
Expires
and Cache-Control: max-age
. These specify the “freshness lifetime” of a resource, that is, the time period during which the browser can use the cached resource without checking to see if a new version is available from the web server.Last-Modified
and ETag
. These specify some characteristic about the resource that the browser checks to determine if the files are the same. In the Last-Modified header, this is always a date. In the ETag header, this can be any value that uniquely identifies a resource (file versions or content hashes are typical).Expires
or Cache-Control
max-age, and one of Last-Modified
or ETag
, for all cacheable resources. It is redundant to specify both Expires
and Cache-Control: max-age
, or to specify both Last-Modified
and ETag
.
Enabling public caching in the HTTP headers for static resources allows the browser to download resources from a nearby proxy server rather than from a remote origin server.
You use the Cache-control: public
header to indicate that a resource can be cached by public web proxies in addition to the browser that issued the request. With some exceptions (described below), you should configure your web server to set this header to public
for cacheable resources.
Recommendations:
Content-Encoding
response header. This can result in compressed versions being delivered to client browsers that cannot properly decompress the files.Because JavaScript code can alter the content and layout of a web page, the browser delays rendering any content that follows a script tag until that script has been downloaded, parsed and executed. It's advised to put JavaScript just before the closing </body>
tag on your page. A sample from HTML5 Boilerplate.
</body>
tag.
Use a file and module loader like RequireJS to load your script modules asynchronously with more control.
requirejs.config({ enforceDefine: true, paths: { jquery: [ '//ajax.aspnetcdn.com/ajax/jquery/jquery-1.11.0.min', //If the CDN location fails, load from this location 'js/jquery-1.11.0.min' ] } }); //Later require(['jquery'], function ($) { });
Keeping the behavior logic outside of HTML will help you optimize the deferred loading of JavaScript code.
Benefits: reducing network latency, enhancing compression, and faster browser loading and execution.
Compressing resources with gzip
or deflate
can reduce the number of bytes sent over the network. Most modern browsers support data compression for HTML, CSS, and JavaScript files.
Don't use gzip for image or other binary files: Image file formats supported by the web, as well as videos, PDFs and other binary formats, are already compressed; using gzip on them won't provide any additional benefit, and can actually make them larger.
Combining external scripts into as few files as possible cuts down on round-trip time (RTT) and delays in downloading other resources.
Try to keep only one external CSS include on a page. If your CSS code gets bigger, try the Critical CSS approach listed below and lazy-load the lower priority code.
With the advent of HTTP 2.0 protocol, this process will have to be reversed for optimization because of request-response multiplexing.
Usually you only need a small amount of CSS code for above-the-fold content or the basic structure of the page. It's always better to strip out the critical/essential CSS code and inline it in the page head and lazy load rest of the CSS. css-tricks.com has more details on this.
This is the best approach if you have single-page apps and you don't need to reload the same CSS again on a different page.
You may not want to inline all your CSS because that will increase the size of your page and you don't get the benefits of Browser and Edge Caching.
After inlining all your important CSS, you can lazy-load rest of your styles.
LazyLoad.css(['remaining-styles.css', 'extra-styles.css'], function () { alert('all CSS files have been loaded'); });
function loadCSS(href, media){ var ss = window.document.createElement('link'), ref = window.document.getElementsByTagName('head')[0]; ss.rel = 'stylesheet'; ss.href = href; // temporarily, set media to something non-matching to ensure it'll fetch without blocking render ss.media = 'only x'; ref.parentNode.insertBefore(ss, ref); setTimeout( function(){ // set media back so that the stylesheet applies once it loads ss.media = media || 'all'; }, 0); } loadCss('things.css');
Don't use different includes for media types and combine them into one script, example: screen, print or the latest CSS3 media types. Most browsers will download your CSS no matter what media type your specify. More Information
<link rel="stylesheet" href="screen-styles.css" media="screen"/> <link rel="stylesheet" href="print-styles.css" media="print"/> <!-- This CSS will load even for non-print view --> <link rel="stylesheet" href="mobile-styles.css" media="(max-width: 480px)"/> <!-- This CSS will load even for screen sizes greater than 480 -->
CSS @import allows stylesheets to import other stylesheets. When CSS @import is used from an external stylesheet, the browser is unable to download the stylesheets in parallel, which adds additional round-trip times to the overall page load. Instead of @import, use a tag for each stylesheet. This allows the browser to download stylesheets in parallel, which results in faster page load times.
Moving inline style blocks and <link>
elements from the document body to the document head improves rendering performance. It's important to put references to external stylesheets, as well as inline style blocks, in the head of the page.
Correctly ordering external stylesheets and external and inline scripts enables better parallelization of downloads and speeds up browser rendering time. Browsers delays rendering any content that follows a script tag until that script has been downloaded, parsed and executed. Stylesheets when placed before script tags will be downloaded in parallel.
Removing or deferring style rules that are not used by a document avoid downloads unnecessary bytes and allow the browser to start rendering sooner.
Properly formatting and compressing images can save many bytes of data. You can perform basic optimization with any image editing program, such as GIMP and Paint.NET.
--strip-all
option)$ jpegtran -optimize -progressive filename.jpg > filename.jpg-opt $ cp filename.jpg-opt filename.jpg $ rm filename.jpg-opt
Combining images into as few files as possible using CSS sprites reduces the number of round-trips and delays in downloading other resources, reduces request overhead, and can reduce the total number of bytes downloaded by a web page.
Lazy loading the images which are not in users viewport will help you reduce initial page load time.
<img class="lazy" src="spinner.gif" data-original="img/example.jpg" width="640" height="480">
$("img.lazy").lazyload({ threshold : 200 // causes image to load 200 pixels before it appears on viewport. });
For small images, use Data URIs to embed the image directly in CSS code.
Data URI Format:
data:[<mime type>][;charset=<charset>][;base64],<encoded data>CSS Example:
li { background-image: url(data:image/gif;base64,R0lGODlhEAAQAMQAAORHHOVSKudfOulrSOp3WOyDZu6QdvCchP...); }HTML Example:
<img width="16" height="16" alt="star" src="data:image/gif;base64,R0lGODlhEAAQAMQAAORHHOVSKudfOulrSOp3WOyDZu6QdvCchPGol..." />
Important Notes:
<?php $filePath = "../image.gif"; $mime = mime_content_type($filePath); $base64 = base64_encode(file_get_contents($filePath)); echo "data:${mime};base64,${base64}"; ?>
For loading multiple images in a dynamic environment where it's not feasable to generate CSS Sprites, you can convert the images to Data URI/Base64 encoding and transfer in a batch using text or JSON format. Live Demo
[ {"id":1, "url":"..." "base64": "data:image/gif;base64,R0lGODlhEAAQAMQAAORHHOVSK..."}, {"id":2, "url":"...", "base64": "data:image/gif;base64,ASDFSDGFERWEWFCVDFGERWEGD..."}, {"id":3, "url":"...", "base64": "data:image/gif;base64,SDFASRWEFSDFSAWRFSDGFSDDF..."} ]
To display the same image in various sizes, create thumbnails using image editing software so you can save bandwidth while serving the images.
Specifying a width and height for all images allows for faster rendering by eliminating the need for unnecessary reflows and repaints. To prevent reflows, specify the width and height of all images, either in the HTML <img>
tag, or in CSS.
Don't use a bigger image than you need just because you can set the width and height in HTML.
For every img
tag with empty src
attribute, some browsers make another request to your server. More Info
Icon fonts are the best additions to modern web design. If you are using a lot of icons on your site, this is the way to go! Icon fonts are scalable and you can easily change their colors like regular fonts on your page. Font Icon payload is very low compared to good old GIFs and PNGs.
Removing extra line breaks and comments can reduce initial page load time. For attribute values without spaces, you can skip quotes around them to save a few bytes.
Compressing resources with gzip
or deflate
can reduce the number of bytes sent over the network. Most modern browsers support data compression for HTML, CSS and JavaScript files.
Write better and more semantically correct markup. More DOM Elements means slower DOM access in JavaScript.
Keep you HTML modular and lazy-load it to minimize intial page payload. You can have empty containers like div
/iframe
and lazy-load the content via AJAX once the container comes into the viewport.
<div class="lazy" data-url="lazy.html"></div>
$('.lazy').waypoint(function() { var $this = $(this); $this.load($this.data("url")); }, { offset: '25%' }); // tells Waypoints how far from the top of the window the callback should fire
Content required for SEO should not be lazy loaded.
Optimizing the way you manipulate the DOM using JavaScript can reduce page repaint time.
Removing "broken links", or requests that result in 404/410 errors, avoids wasteful requests.
Concatenate CSS and JavaScript and use image sprites to reduce additional round-trip time (RTT).
Keeping cookies and request headers as small as possible ensures that an HTTP request can fit into a single packet.
Minimizing HTTP redirects from one URL to another cuts out additional round-trip time (RTT) and wait time for users.
For every new server the DNS resolver is contacted by the browser which returns that server's IP address. It typically takes 20-120 milliseconds for DNS to lookup the IP address for a given hostname. The browser can't download anything from this hostname until the DNS lookup is completed.
Serving resources from two different hostnames/domains increases parallelization of downloads. Doing this allows more resources to be downloaded in parallel, reducing the overall page load time. Make sure you're using not more than 2-4 domains because of the DNS lookup penalty. More Info
Cookies are sent to the server with every request you make so if you have a lot of cookies or cookies with large size, your total request size will increase. More Info
If you have data that does not change often, try caching it on the client to reduce server calls. You can use simple JavaScript object caching (good for single page apps) for dynamic apps (example: a small autocomplete list) or use HTML5 SessionStorage or LocalStorage APIs for long term storage.
When using XMLHttpRequest (AJAX), POST is implemented in the browsers as a two-step process: sending the headers first, then sending data. So it's best to use GET, which only takes one TCP packet to send (unless you have a lot of cookies). The maximum URL length in IE is 2K, so if you send more than 2K data you might not be able to use GET.
It's important to serve a resource from a unique URL, to eliminate duplicate download bytes and additional RTTs.
Optimize your back-end code to respond faster. Your server needs to begin sending the first byte of the resource within 200ms of the request being sent.
If your page has been designed with mobile devices in mind, then you should utilize the viewport meta tag so that mobile devices can render the document at the correct size.
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
Serving static resources from a cookieless domain reduces the total size of requests made for a page. In Apache you can set or unset headers before requests are answered and block any front-end cookie setters like Google Analytics. More Info
Header unset Cookie Header unset Set-Cookie
Specifying a character set in the HTTP response headers of your HTML documents allows the browser to begin parsing HTML and executing scripts immediately. Apache .htaccess setting for UTF-8:
# Use UTF-8 encoding for anything served as `text/html` or `text/plain`. AddDefaultCharset utf-8 # Force UTF-8 for certain file formats. <IfModule mod_mime.c> AddCharset utf-8 .atom .css .js .json .jsonld .rss .vtt .webapp .xml </IfModule>