Web Speed Checklist 2021

Let's make 2021... fast! Here’s the English translation of our frontend optimization speed checklist. It includes almost everything you need to know to ensure a speedy user experience on the web today—from metrics and tools to developer techniques.
This checklist is a translation of the Front-End Performance Checklist 2021. Thanks to Smashing Magazine.
Contents:
- Preparation: Planning and Metrics
- Setting Realistic Goals
- Defining the Development Environment
- File Optimization
- Build Optimization
- Loading Optimization
- Network and HTTP/2
- Testing and Monitoring
- Quick Wins
Preparation: Planning and Metrics
-
Cultivate a “performance culture” focused on web speed.
Web speed isn't sustainable without investment. Study common complaints to customer support and investigate how boosting speed can alleviate some of these issues. Create a case study with real data and business metrics tailored to your company. Plan the web's loading process and potential compromises right from the design stage.
-
Be 20% faster than your fastest competitor.
Gather data on the devices your website visitors use. Prioritize real devices over simulations. Choose a mobile like Moto G4/G5 Plus; a mid-range Samsung device (Galaxy A50, S8); a good mid-range device like Nexus 5X, Xiaomi Mi A3, or Xiaomi Redmi Note 7, and a slow device like Alcatel 1X or Cubot X19. Alternatively, emulate mobile OS on a desktop by testing with restricted network speed (e.g., 300 ms RTT, 1.6 Mb/s download, 0.8 Mb/s upload) with limited CPU (5× slowdown). Then switch to regular 3G, slow 4G (e.g., 170 ms RTT, 9 Mb/s download, 9 Mb/s upload), and Wi-Fi. Collect the data, create a spreadsheet, and subtract 20% from the results to set your goals (“performance budgets”).
-
Select the right metrics.
Not all metrics hold equal value in terms of optimization. Study which metrics matter most: they usually relate to how quickly the most important pixels start rendering and the speed of input response. Focus on loading the page according to your visitors' priorities. Typically, Time To Interactive (TTI), First Input Delay (FID), hero element rendering time, Largest Contentful Paint (LCP), Total Blocking Time (TBT), and Cumulative Layout Shift (CLS) are important. Not: First Meaningful Paint (FMP).
-
Set testing profiles: “clean” and “customer.”
Disable antivirus programs and CPU-intensive background tasks, stop background data transfers, and test with a “clean” user profile without browser extensions to avoid skewing results. Study which extensions your customers use and test a special “customer” profile too.
-
Share the Web Speed Checklist with your colleagues.
Ensure that every team member knows this Web Speed Checklist. Every decision impacts performance, and your project will benefit greatly if ownership is distributed across the team. Simultaneously map design decisions against the performance budget.
Setting Realistic Goals
-
Response time of 100 milliseconds, 60 frames per second.
Each animation frame should be executed within 16 milliseconds—ideally 10 milliseconds to achieve the desired 60 frames per second (1 second ÷ 60 = 16.6 milliseconds). Be optimistic and wisely use idle time; for demanding activities like animations, it’s better to do nothing else on the page. Where that's not possible, do only the absolute minimum. Estimated input latency should be less than 50 ms. Use idle time with the Idle Until Urgent approach.
-
LCP < 2.5 seconds; FID < 100 ms; CLS < 0.1; TTI < 5 seconds on 3G.
Considering a mobile device with Android around $200 on a slow 3G network, emulate at a transfer speed of 400 ms RTT and 400 kB/s, aim for TTI < 5 seconds and repeat visits under 2–3 seconds. Aim for Largest Contentful Paint < 2.5 seconds and minimize Total Blocking Time (TBT) and Cumulative Layout Shift (CLS). Strive to reduce these values to a minimum.
-
File size cap < 170 kB.
The first 14–16 kB of HTML code is the most critical—it's the only part delivered in the first network packet (“first roundtrip”). To achieve the above goals, work with file sizes of a maximum gzipped size of 170 kB (0.7 – 0.8 MB uncompressed). Ensure your speed limits change based on network conditions and hardware constraints.
Defining the Development Environment
-
Choose and set up your build tools wisely.
Don't get too caught up in whether a tool is “cool” or not. If you achieve results quickly and have no issues maintaining your build process, then all is well. Exceptions might be Webpack or Parcel, which provide valuable optimization techniques like code-splitting. If you're not using these techniques yet, look into the aforementioned code-splitting and tree-shaking.
-
Use progressive enhancement by default.
First design and create a basic interface, ensuring the site fulfills its primary function. Then enhance the interface with advanced features for different browsers, creating a robust and stable interface for diverse users with various devices. If your site runs quickly on a slow device, with a poor screen, and in a suboptimal browser on a non-optimal network, it will run even faster on a fast device, with a good browser, and on a decently fast network.
-
Set the performance bar high.
JavaScript incurs the highest cost to user experience. With a limit of 170 kB, which includes critical data and paths—HTML / CSS / JavaScript, router, state management, tools, interface, and application—thoroughly examine the time costs for network transfer, parsing, compilation, and runtime costs of the framework.
-
Evaluate every framework and dependency.
Not every project needs a framework, not every Single Page Application (SPA) needs to load a framework. Choose wisely; evaluate third-party JS by examining features, accessibility, stability, speed, package ecosystems, learning curve, documentation, tools, records, team, compatibility, and security. Next.js (React), Gatsby (React), Vuepress (Vue), and Preact CLI provide decent defaults for fast loading on average mobile hardware.
-
Choose wisely: React, Vue, Angular, Ember, and the like.
Ensure the framework of your choice provides server-side rendering (SSR) or prerendering. Before deciding, measure rendering times on mobile devices both server-side and client-side. It's important to understand the “nuts and bolts” of the framework you'll rely on. Check out the PRPL design pattern and App Shell architecture. Good choices are Preact, Inferno, Vue, Svelte, Alpine, Polymer.
-
Optimize your API performance.
APIs can easily become bottlenecks when multiple services access them simultaneously. Consider using GraphQL to run queries against a type system you define for your data. Unlike REST, GraphQL can retrieve all necessary data in a single query, without overfetching or underfetching, which often happens in RESTful architectures.
-
Consider Google AMP or Facebook Instant Articles?
You can achieve good performance without these technologies, but AMP offers a strong performance foundation and global CDN. Instant Articles help mainly with visibility on Facebook and up to 4× faster loading than regular mobile websites.
-
Choose your CDN wisely.
Consider how dependent you are on dynamic data. You can at least partially generate static content, upload to CDN, and thus avoid unnecessary database queries (JAMStack). Check if the CDN performs content compression and image conversion (e.g., optimization and resizing or format changes) and if it supports server workers.
File Optimization
-
Use Brotli for compression.
Brotli is a new lossless data format supported in all modern browsers. It’s more efficient than GZip and Deflate. Compression is slow, but decompression is fast. Precompress static assets using Brotli and Gzip at the highest level, dynamically compress HTML on the fly using Brotli (level 1-4). Also, check Brotli support on your CDN. Ensure the server handles “content negotiation” for Brotli or Gzip properly.
-
Use responsive images, AVIF, and WebP.
Whenever possible, use responsive images with properties
srcset, sizes, <picture>, and image-set.Use AVIF and WebP formats with<picture>and JPEG/PNG as fallback or detect support via the Accept header. Note: WebP reduces data volume, but JPEG can enhance perceived speed with its “progressive rendering” feature. -
Are images properly optimized?
Use mozJPEG for JPEG compression, SVGO for SVG compression, Pingo for PNG, or Squoosh for all of them (including AVIF). To check the effectiveness of your responsive markup, use the tool imaging-heap. For critical images, use progressive JPEG and blur unnecessary parts (applying Gaussian blur) and remove contrast (you can reset it using CSS filters). Make sure you have width and height attributes set for all your images. Add automatic image compression to your pull requests and explore lazy loading of less critical images.
-
Are videos properly optimized?
Instead of animated GIFs, use either animated WebP (with GIF as a fallback) or embed loops with inline HTML5 video. Ensure your MP4 files are processed with multipass-encoding, blurred using the “frei0r iirblur” effect (if available), moov atom metadata moved to the file header, and your server accepts Byte serving. Whenever possible, use video in the AV1 format, but also provide a fallback for older formats. Adjust video dimensions and use adaptive media delivery to provide visitors with content they can play on their devices without delays.
-
Are fonts optimized?
Set the font subsetting correctly. Prefer WOFF2 and use WOFF as a fallback. Display content immediately with a fallback font, load the custom font asynchronously, and then switch the font. Ideal solution: two-stage rendering, first with a small supersubset, then load the rest asynchronously later. Preload 1-2 fonts from each family. Avoid using local() in font declaration, but consider using fonts installed in the OS. Don't forget to use font-display:optional and use Font Load events for repainting. Use metrics Web Font Reflow Count and Time To Real Italics.
Build Optimization
-
Set priorities correctly.
Review all your assets (JavaScript, images, fonts, third-party scripts, “expensive” modules on the page) and group them. Define the basic experience (fully accessible basic content for older browsers), enhanced experience (enriched, full-featured for modern browsers), and add-ons (resources not strictly required and can be lazy loaded).
-
Use native JavaScript modules in production.
Support the basic experience in older browsers, full-featured only in modern browsers. For loading JavaScript, use ES2017+
<script type="module">. Modern browsers interpret the script as a JavaScript module and execute it as expected. Older browsers ignore it. -
Running JavaScript is expensive, so tame it.
In SPA applications, you need some time to initialize the application before you can render the page. Look for modules and techniques to speed up initial rendering time, such as progressive hydration and import on interaction (on older mobiles, times are 2-5× higher).
-
Use tree-shaking, scope hoisting, and code-splitting to reduce load.
Tree-shaking is a way to use only the code that is actually used during build. Code-splitting splits the code into “chunks” that are loaded on demand. Scope hoisting detects where import chaining can be served and converted into an inline function while maintaining functionality (e.g., using Webpack). Use granular chunking and move part of the rendering from the client to the server. Define splitting by tracking which CSS/JS blocks are used and which are not. Consider also code-splitting at the package level.
-
Can you move JavaScript to Web Worker or WebAssembly?
As the code evolves, performance bottlenecks in the user interface will start to show. DOM operations often run alongside your JS in the main thread. Consider moving these expensive operations to background processes running in a separate thread using web workers. A typical case: preloading data into PWA. Consider moving computationally intensive tasks to WebAssembly, which works best for demanding web applications like games.
-
Send legacy code to legacy browsers only.
Use babel-preset-env to transpile ES2017+ features unsupported by modern browsers you support. Then set up two build versions, one for modern and another for older browsers.
For lodash, use babel-plugin-lodash, which loads only the modules you use in the source code. Change generic lodash require and select only those used, preventing code duplication. Use
<link rel="modulepreloak">to initiate early (high priority) loading of modules. -
Identify and rewrite old (legacy) code with “incremental decoupling”.
Review project dependencies and assess how much time would be needed to refactor or rewrite old code. First, set metrics that track whether the legacy code call ratio remains the same or decreases. The ratio should not increase. Set team conditions that do not tolerate using additional libraries and ensure CI always notifies developers during pull requests.
-
Identify and remove unused CSS/JavaScript.
CSS and JavaScript coverage in Chrome lets you see which code was executed/used and which was not. Once you ensure unused code, find these modules and add lazy loading using import(). After modification, repeat the code coverage test and verify that less code is now sent on the first load. Use Puppeteer to automatically collect code coverage results.
-
Reduce the size of JavaScript dependencies.
There's a good chance you have entire JavaScript libraries on your projects, but you use only a fraction of the code. Consider using automatic webpack-libs-optimizations, which removes unused methods and polyfills during the build process. Add package checking to your regular workflow. Bundlephobia helps measure the performance impact of adding individual NPM packages to a project. Size-limit extends the classic package size check with the length of execution time in JavaScript. Skypack can be used as a source of packages focused on quality and performance and managed by individual community members.
-
Do you use predictive prefetch for pieces of JavaScript code?
Use your experience and intuition to determine when you will prefetch your JS. Guess.js includes tools that use Google Analytics data to determine which page the user is likely to visit next. Consider Quicklink, Instant.page, and DNStradamus. Note: You might be instructing browsers to download unnecessary data and prefetch unnecessary pages. We certainly recommend being cautious about the number of preloaded requests.
-
Optimize for your target JavaScript engines.
Use script streaming for monolithic scripts to parse them immediately after starting downloading in a separate background thread. Also engage code caching V8 engine by separating libraries from the code that uses them. Consider also JIT optimization strategies for Baseline Interpret in Firefox.
-
Find a way to combine client-side and server-side rendering.
The goal is usually to find the optimal balance between client-side and server-side rendering. Consider prerendering if your pages don’t change too often, and if possible, defer framework booting. Stream HTML chunks using server-side rendering and hydrate on display, interaction, or during idle to get the best of both worlds. (Streaming Server-Side Rendering With Progressive Hydration).
-
Consider micro-optimizations and progressive booting.
Use server-side render for quick “First Meaningful Paint” (FMP), but also include minimal JS to keep “Time to Interactive” (TTI) close to “First Meaningful Paint.” Then either on demand or as time permits, run nonessential parts of the application. Always split function execution into asynchronous tasks. If possible, use requestIdleCallback.
-
Host third-party resources yourself.
Using a public CDN is not automatically faster. Even if two sites link to the exact same URL of a third-party resource, the code is downloaded again for each domain. The cache is isolated per domain. Self-hosted resources are more likely to remain in cache than third-party resources. Self-hosting is more reliable, secure, and performant.
-
Limit the impact of third-party scripts.
Too often, a single third-party script creates that “long tail” and messes up speed. Consider using service workers to download resources with a time limit. Set a Content Security Policy (CSP) to limit the impact of third-party scripts, such as by prohibiting audio or video downloads. Embed scripts in an iframe, so scripts won’t have access to the DOM. For load testing scripts, explore the summary on the Performance tab (DevTools). Load third-party scripts only after the application is loaded. Focus on code snippets that prevent content flashing before the script loads.
-
Set HTTP cache headers correctly.
Check that expires, cache-control, max-age, and other HTTP cache headers are set correctly. Generally, resources should be cacheable either for a very short period (if they are likely to change) or indefinitely (if they are static).
Use cache-control: immutable to prevent revalidation. Verify that you’re not sending unnecessary headers (e.g., x-powered-by, pragma, x-ua-compatible, expires). Take advantage of zero RTT for repeat views via stale-while-revalidate.
Loading Optimization
-
Load JavaScript asynchronously.
Use lazy loading for all components like large JS files, videos, iframes, widgets, and also images. Use native lazy-loading (loading and importance attributes), or solutions using Intersection Observer. The latter can also be used for powerful “scrollytelling” - parallax-like effects, or ad tracking.
-
Defer rendering and decoding of large images.
With the content-visibility: auto property, we can instruct the browser to skip rendering the descendants of a given element if the element is outside the viewport. Ensure you use the contain-intrinsic-size property with an appropriately chosen placeholder to avoid worsening the Cumulative Layout Shift (CLS) metric. Use also
<img decoding="async">. The browser will then decode the image outside the main thread, reducing the CPU time required for the operation. -
Load critical CSS as quickly as possible.
Take out from CSS all styles necessary to render content visible on the page in the viewport (so-called critical CSS or CSS above the fold). Add these styles inline into the
<head>tag on the page. The golden rule is that you should not exceed a total size of 14 kB. Consider conditional CSS injection on the page. In some cases, it is more advantageous to place critical CSS in a separate file in the root of the domain. Thanks to caching, this solution may be better than inline styles. -
Experiment with rearranging CSS files/properties.
When optimizing loading, you might also consider splitting the main CSS by individual media queries. Do not place
<link rel ="stylesheet"/>before async files. If scripts don’t depend on styles, consider placing blocking scripts above blocking styles. If they do, split this JavaScript into two and load it before and after CSS files. Cache inline CSS using service workers and experiment with in-body CSS. Dynamic styles can be “expensive”: check whether CSS-in-JS optimizes execution if CSS has no dependencies on the appearance or properties of the component, do not complicate components (styled-components). -
Stream responses.
Streaming provides an interface for reading or writing asynchronous data chunks, of which a subset may be available in memory at a given time. Instead of serving an empty UI skeleton and populating content with JavaScript, use a service worker, load the skeleton from the cache, and content from the network. The HTML rendered during the initial request can then fully utilize the browser’s HTML parser.
-
Consider adjusting your components to the connection and device memory.
Use the client-hint header Save-Data and adjust your application by limiting your users (cost, performance). You can override high-DPI image requests to low-DPI ones, remove web fonts, parallax, disable video autoplay, or even change how you deliver code. Use Network Information API to deliver variants of demanding components based on connection and Device Memory API to adjust resources based on device memory.
-
Maintain a persistent connection to speed up delivery.
Save time using resource hints; dns-prefetch (background DNS lookup), preconnect (initiate connection handshake (DNS, TCP, TLS)), prefetch (resource request), preload (preload resources without executing them), and prerender (preload resources ahead without executing JS and without rendering on the page). When using preload, as must be defined, or nothing will load. Preloading fonts without a crossorigin attribute will cause double loading. There are a number of priorities when using preload, so consider inserting rel=”preload” elements into the DOM just before external blocking scripts.
-
Use service workers for caching and as a fallback in case of network outages.
If your site runs on HTTPS, store static assets in the service worker cache and save offline fallback (or even entire pages) and load them from the device, not the network. Save the application environment to the service worker cache along with several critical pages, e.g., an offline page or homepage. But, ensure there is a correct CORS response header, do not store opaque responses, and register cross-origin images in CORS mode.
-
Use a service worker on CDN/Edge (e.g., for A/B testing).
If your CDN implements service workers on the server, consider performance tuning using service workers right “on the edge.” For example, in A/B tests, when HTML needs to change its content for different users, use a CDN service worker to process the logic.
Accelerate sites using Google Fonts with stream HTML rewriting.
-
Optimize rendering performance.
If necessary, isolate expensive components using CSS containment. Ensure there is no delay during page scrolling or element animation, and that you consistently achieve 60 frames per second. If not possible, try to keep frame rates at least constant. The minimum redraw rate is generally considered to be 15 frames per second. Use CSS will-change to inform the browser which elements will change.
-
Have you optimized the rendering experience?
Do not underestimate the role of perceived speed. When loading files, try to always be one step ahead of the customer to keep the experience smooth, even when a lot is happening in the background. To engage the customer, use “skeletons” instead of loading spinners and add transitions and animations.
-
Prevent layout shifts (reflow) and repaint.
Layout shifts are commonly triggered by resizing components such as videos and images, as well as dynamically loaded web fonts, embedded ads, or dynamically loaded real content into components. Set width and height for images so modern browsers can reserve the necessary space. Use placeholder SVGs to reserve sufficient space for where images or videos will appear. Use JavaScript-based lazy-loading if a native version is not available for the component. Download JS lazy-loading really only when you use it. Identify layout shifts caused by web fonts and compare line-height and spacing using font-style-matcher. Monitor layout stability using the Layout Instability API and the Cumulative Layout Shift (CLS) metric.
Network and HTTP/2
-
Is OCSP stapling enabled?
OCSP stapling can speed up the TLS authentication process because the browser doesn't have to spend time looking up and downloading information about your domain's certificate.
-
Have you reduced the impact of SSL certificate revocation?
Extended Validation (EV) certificates are expensive and time-consuming, as a human must always verify them. Basic Domain Validation (DV) certificates are available for free (Let’s Encrypt) and can be easily automated for acquisition and renewal. EV certificates do not support OCSP stapling, so always have a DV certificate with stapling enabled.
-
Do you use IPv6?
Studies show that websites are up to 15% faster thanks to NDP (Neighbor Discovery Protocol) and route optimization. Update your DNS records for your website to be accessible via IPv6. Don't forget about existing IPv4, as the two versions are not mutually compatible.
-
Is TCP BBR used?
BBR is a relatively new TCP flow control algorithm. It responds more to actual congestion than packet loss, as TCP does. As such, it is significantly faster, with higher throughput and lower latency. Enable BBR and set tcp_notsent_lowat to 16 kB to ensure HTTP/2 prioritization works reliably on Linux kernels 4.9 and newer.
-
Always prioritize HTTP/2.
HTTP/2 is well supported and offers speed improvements. Depending on how large your mobile user base is, you may need to send users different builds (application assemblies) and can benefit from adapting different builds for different devices. (HTTP/2 is often slower in networks with noticeable packet loss.)
-
Deploy HTTP/2 correctly.
You must find a fine balance between bundling modules into one and loading many small modules in parallel. Split your entire interface into many small modules; then group, compress, and bundle them. Split at the package level or by tracking which CSS/JS blocks are unused. Separate third-party code from your own and isolate dependencies that change infrequently and often. Sending approximately 6–10 frontend element bundles seems like a reasonable compromise (and it's not bad for older browsers). Experiment and measure to find the right balance. Try to send as many elements as possible over a single HTTP/2 connection.
-
Do your servers and CDN support HTTP/2?
Various servers and CDN support HTTP/2 differently. Use tools that compare CDN (e.g., CDN Comparison) to check your options or quickly look up the level of support for various features. Enable BBR, set tcp_notsent_lowat to 16 kB for HTTP/2 prioritization.
-
Is HPACK compression used?
If you are using HTTP/2, check whether your servers implement HPACK compression for HTTP response headers to reduce unnecessary overhead. HTTP/2 servers are relatively new and may not fully support the specification, as is the case with HPACK. H2spec is a great (albeit technically detailed) tool to check this.
-
Prepare for HTTP/3.
In HTTP/2, connections share multiple requests. In HTTP/3, requests also share a connection but stream independently, so a dropped packet no longer affects all requests, only one stream. With QUIC in HTTP/3, TCP and TLS are combined and performed in a single “round trip.” From the second connection, we can already send and receive application layer data in the first “round trip” (0-RTT). Bundling frontend elements still matters, so instead of sending monolithic JS, send multiple JS files in parallel, as in HTTP/2. Expect HTTP/3 to impact loading times on mobile devices.
-
Do your servers and CDN support HTTP/3?
QUIC and HTTP/3 are better and more robust: with faster “handshakes,” better encryption, more reliable independent streams, more encrypted, and with 0-RTT if the client has previously connected to the server. However, it is quite CPU-intensive (2-3 times CPU usage for the same bandwidth). Check whether your servers or CDN support HTTP over QUIC (also known as HTTP/3) and enable it if possible.
-
Check if your server security is bulletproof.
Ensure security headers are set correctly, remove known security vulnerabilities, and check HTTPS settings. Make sure all external plugins and tracking scripts load over HTTPS, cross-site scripting is not possible, and that HTTP Strict Transport Security and Content Security Policy headers are correctly set.
Testing and Monitoring
-
Monitor mixed-content warnings.
If you recently migrated from HTTP to HTTPS, remember to monitor active and passive mixed-content warnings using tools like Report-URI.io. You can also use Mixed Content Scan to scan for mixed content on your HTTPS-enabled site.
-
Have you optimized your audit and debugging workflow?
Invest time in studying debugging and auditing techniques in your debugger, WebPageTest, Lighthouse, and expand your text editor. For example, you can run WebPageTest from a Google Sheet and integrate accessibility, performance, and SEO scores into your Travis setup using Lighthouse CI or directly into Webpack. For quick checks, use CSS Perf Diagnostic.
-
Tested on proxy and older browsers?
Testing in Chrome and Firefox isn’t enough. See how your site works in proxy browsers and older browsers (including UC Browser and Opera Mini). Measure average internet speed among your user base to avoid big surprises. Test with network throttling and emulate high-DPI devices. BrowserStack is fantastic, but also test on real devices.
-
Tested the speed of your 404 pages?
Every time a client requests a non-existent element on the web, they receive a 404 response—and this response is often huge. Don’t forget to explore and optimize the caching strategy also for your 404 pages. Ensure the browser displays HTML only if it expects an HTML response, and return an error response for all other responses.
-
Tested the impact of your GDPR consent and cookie bars?
Normally, cookie consent prompts should not impact CLS, but sometimes they can, so consider using free and open-source resources like Osano or cookie-consent-box. Consent will likely change the scripts' impact on overall performance, so set and study several different web performance test profiles for different consent types.
-
Tested accessibility impact?
Large pages and DOM manipulation with JavaScript cause delay in screen reader notifications. Fast Time to Interactive means how much time elapses before the screen reader can announce navigation to the page and the screen reader user can actually press the keyboard to interact.
-
Is continuous monitoring set up?
Good speed metrics arise from a mix of passive and active monitoring tools. A private instance of WebPageTest and using Lighthouse is always beneficial for quick tests, but also setting up continuous monitoring with RUM tools like SpeedTracker, SpeedCurve, and others. Set your own user-timing marks for measuring and monitoring metrics specific to your site.
Quick Wins
The Web Speed Checklist is quite comprehensive, and completing all optimizations can take a while. So, if you only had 1 hour to gain significant improvements, what would you do? We'll shorten it all to 18 low-hanging fruits. Of course, before you start and once you finish, measure results, including metrics like Largest Contentful Paint and Time To Interactive on 3G and cable connections.
- Measure speed among real users and set appropriate goals. Aim to be at least 20% faster than your fastest competitor. Keep Largest Contentful Paint under 2.5 s, First Input Delay under 100 ms, Time to Interactive under 5 seconds on slow 3G, and for repeat visits under 2 s. Optimize at least for First Contentful Paint and Time To Interactive.
- Optimize images using Squoosh, mozjpeg, guetzli, pingo and SVGOMG, and serve AVIF/WebP with an image CDN.
- Prepare critical CSS for your main templates and inline them into the
<head>of each. Set a budget for the size of critical CSS and JS files max. 170 kB after gzip (0.7 MB uncompressed). - Trim, optimize, defer, and lazy-load scripts. Invest in configuring your bundler to remove redundancy and look for less data-heavy alternatives.
- Always host static frontend files on your own domain. Also, prefer hosting third-party components on your own domain. Limit their impact. Use facades and placeholders, load widgets on interaction, and beware of the original version flash.
- Be discerning when choosing a framework. In Single Page Applications (SPA), identify critical pages and render them statically, or at least prerender them. Use progressive hydration at the component level and import modules on interaction.
- Client-side rendering only is not a good performance choice. Prerender if your pages don’t change much, and defer framework booting. Use server-side streaming rendering (SSR).
- Deliver legacy code only to legacy browsers using the module/nomodule pattern.
- Experiment with rearranging CSS rules and test CSS served directly in HTML.
- Add resource hints to accelerate delivery using dns-lookup, preconnect, prefetch, preload, prerender.
- Subset web fonts and load them asynchronously, use font-display in CSS for fast first rendering.
- Check if HTTP caches and security headers are correctly set.
- Enable Brotli compression on the server. (If not possible, remember to enable Gzip compression.)
- Enable TCP flow control with BBR if your server runs on Linux kernel version 4.9+.
- If possible, enable OCSP stapling and IPv6. Always serve a DV certificate with OCSP.
- Enable HPACK compression for HTTP/2 and migrate to HTTP/3 if available.
- Cache elements like fonts, styles, JavaScript, and images in the Service Worker cache.
- Explore ways to avoid rehydration, use progressive hydration and server-side streaming for your Single Page Application (SPA).
Special thanks for the review of the original article on Smashing Magazine go to Guy Podjarny, Yoav Weiss, Addy Osmani, Artem Denysov, Denys Mishunov, Ilya Pukhalski, Jeremy Wagner, Colin Bendell, Mark Zeman, Patrick Meenan, Leonardo Losoviz, Andy Davies, Rachel Andrew, Anselm Hannemann, Barry Pollard, Patrick Hamann, Gideon Pyzer, Andy Davies, Maria Prosvernina, Tim Kadlec, Rey Bango, Matthias Ott, Peter Bowyer, Phil Walton, Mariana Peralta, Pepijn Senders, Mark Nottingham, Jean Pierre Vincent, Philipp Tellis, Ryan Townsend, Ingrid Bergman, Mohamed Hussain S. H., Jacob Groß, Tim Swalling, Bob Visser, Kev Adamson, Adir Amsalem, Aleksey Kulikov, and Rodney Rehm.
Czech translation: Tomáš Hejč, Martin Brychta, Zuzana Šumlanská, Martin Michálek. (Team PageSpeed.ONE)
Jak je rychlý váš web?
Jak rychlý je váš web v porovnání s vaší konkurencí? To zjistíte
pomocí našeho online testeru.