Skip to content
Core Web Vitals specialists

Front-end optimisation

How fast a page really feels is decided in the browser. This category collects articles on the front-end side of optimisation: image formats and responsive sizes, web fonts and their loading behaviour, CSS delivery and critical styles, JavaScript bundles and how to split them, deferred loading, third-party scripts and their side effects. We explain how layout shifts occur and how reserved space prevents them, why interactivity suffers under long tasks and which techniques reduce the main work in the browser. Every article describes measurement before and after the change, so the effect of a measure can be quantified rather than assumed. We also cover collaboration: which requirements for design and editing prevent every new page from degrading loading time again.

content-visibility: limit rendering work to the viewportLong listing page (scroll axis)Hero area (LCP)renderedIntro and filtersrenderedProduct grid AskippedProduct grid BskippedFAQ sectionskippedFooter areaskippedViewport edge - below this the browser skipscontent-visibility: auto + contain-intrinsic-size: auto 480pxRendering time on initial load (web.dev demo)Default232 mscontent-visibility30 msweb.dev expects at least 50 percent less rendering costFour containment promises to the browserlayoutInner layout staysinside the boxpaintContent stays withinthe box boundssizeSize known withoutreading childrenstyleCounters and quotesstay in the subtreeWhere content-visibility has the biggest effect30 msrendering time instead of 232 mson initial load (web.dev)50 %expected minimum cut inrendering cost (web.dev)77 / 97 %good INP on mobile vs desktop(HTTP Archive Web Almanac 2025)

content-visibility: Skip Rendering Work on Long Pages

content-visibility and CSS containment limit the rendering work of long pages to the visible area - with placeholder heights that avoid new layout shifts.

13 min read
Shared Dictionaries: Shipping Bundles as DeltasHow a delta response flows1 - Browser has app.v1.js cachedfrom the last deploy, flagged as a dictionary2 - Request announces the dictionaryAvailable-Dictionary: :sha-256 hash:3 - Server compresses the deltaContent-Encoding: dcb or dcz4 - Browser rebuilds app.v2.jsfull bundle, only the delta crossed the wireNo match: plain Brotli responseWhat the new bundle version costs (WICG examples)Brotli alone344 KBdcb against v1128 KB-63 %Front-end bundle of a news portal, 1.5 MB uncompressedDictionary = the previous version of the same fileSource: WICG compression-dictionary-transportGoogle Search with a static dictionary (Chrome for Developers)23 %smaller HTML responsethan with Brotli alone1.7 %better LCPacross all Chrome usersup to 9 %better LCPon slow networksStatic dictionary built from a sample of real result pagesNegotiation, support and fallback layerAccept-Encoding: dcb, dcz, br, gzip -> server checks Available-Dictionary -> delta or plain responseChrome 130+Edge 130+Firefox / Safari: fallback69 % global (Can I use)

Shared Dictionaries: Ship Bundles as Deltas

Compression dictionary transport per RFC 9842: how browsers and servers ship bundles as deltas against the previous version - patterns, configuration, fallback.

12 min read
Back/Forward Cache: instant back-navigationThe browser freezes the whole page and restores it almost instantly on the back clickWithout bfcachefull reloadConnectHTMLCSS + JSRender~1200 msWith bfcachefrom memorya few milliseconds - the page is instantly thereTypical blockers of restorationThese factors stop Chrome from restoring the page from memoryunload handlerslegacy unloadWebSocket / WebRTCopen connectionCookie changeevicts no-store pageCache-Controlno-store (partly)54%bfcache hit rate, up from just0.04 % in the Yahoo Japan News test(web.dev)6.77%of all page loads were servedfrom the bfcache(Chrome UX Report)100%of Chrome users: bfcache evenwith Cache-Control: no-store(Chrome for Developers)

Back/Forward Cache: Instant Browser Back-Navigation

How the back/forward cache keeps whole pages in memory and makes back navigation instant: blockers, Cache-Control: no-store and testing in DevTools.

13 min read
Speculation Rules: from hover to an instant pageThe browser prefetches or prerenders the next page -- on click it is already thereApproachuser moves towardthe linkPrerendernext page loadsin the backgroundActivationclick reveals thefinished pageInstantly visibleLCP near zeromillisecondsEagerness: when the browser speculatesFrom cautious to instant -- more speed also means more risk of wasted prerendersconservativeonly on clickWaste: nonemoderateafter 200 ms hoverWaste: loweagerafter ~10 ms hoverWaste: mediumimmediateas soon as the ruleWaste: higher25%of mobile top-10M sitesnow use Speculation Rules(Web Almanac 2025)200 mshover before the moderatelevel speculates(Chrome for Developers)Chrome 144prerender-until-script as anew level (January 2026)(Chrome for Developers)

Speculation Rules: Instant Navigation via Prerendering

How the Speculation Rules API prefetches or prerenders next pages, tunes eagerness correctly, and avoids wasted prerenders and analytics side effects.

13 min read
fetchpriority="high": load the LCP image soonerBrowser load order without and with the priority hint on the hero imageWITHOUT fetchpriorityHTML + CSSscripts (high priority)LCP image waits (low)LCP image loads lateLCP 4.2 sWITH fetchpriority="high"HTML + CSSLCP image loads at onceLCP 1.9 s-2.3secondsLCP in test(DebugBear)4.2 s to 1.9 sThree rules for the priority hint1Exactly one elementOnly the LCP image getshigh - nothing below it.More high = nothing prioritized2Never lazy-load itloading="lazy" on the LCPimage slows it down.Load the hero image eagerly3Pair it with preloadPreload finds the image,high raises its priority.srcset stays on the img tagImages start at low priority in the browser (web.dev) - the LCP image is treated like a minor one.Use of fetchpriority for the LCP image rose to 15 percent of mobile pages (Web Almanac 2024).A declarative attribute, no new infrastructure - a quick win of frontend optimization.

fetchpriority: Speed Up LCP with Priority Hints

How fetchpriority='high' loads the LCP image sooner: correct use, interplay with preload and srcset, the most common mistakes and the LCP quick win.

13 min read
Request timeline: with and without resource hintsConnection setup and load start for the LCP image and a fontWITHOUT hintsDNSTCPTLSLCP image loadslate startfont loadsWITH hintsDNSTCPTLSpreconnect: warm connectionLCP image loads earlyfont loads early100-500ms savedResource hint adoption (Web Almanac 2024)33%dns-prefetchof pages28%preconnectof pages19%preloadof pages6%prefetchof pages15%fetchpriorityfor LCP imagemobilepreconnect shortens connection setup by roughly 100 to 500 ms (web.dev) --use of fetchpriority for the LCP image rose from 0.03 to 15 percent of mobile pages (Web Almanac 2024).

Resource Hints: Using preload, prefetch and preconnect

How preload, prefetch, preconnect, dns-prefetch and priority hints shorten connection setup, speed up the LCP image and fonts -- and where over-loading hurts.

14 min read
Loading Timeline: Monolithic Bundle vs. On-Demand ChunksWithout SplittingWith Lazy Loading and Code Splittingapp.bundle.js -- 880 KB (blocks main thread)Parse and compileExecuteFirst Paintlate interactivityEverything loads upfront -- even code for pagesthe user never visits.core.js -- 140 KBParseExec.Paintearly interactivityroute: product.js 28 KBroute: checkout.js 34 KBchat-widget.js (click)image (viewport)On demandOnly the critical path starts immediately.Chunks follow on navigation or interaction.Initial JavaScript (compressed)before880 KBafter140 KB44%JS unused at median34%sites using lazy loadingplus 8.4%conversions per 0.1 s2.5 sLCP targetAt the median, 44 percent of delivered JavaScript is unused during load (Web Almanac 2024) --a 0.1 s faster mobile load lifted retail conversions by 8.4 percent (Google/Deloitte).

Lazy Loading and Code Splitting Done Right in 2026

Lazy loading for images and components, route-based code splitting and dynamic imports cut initial JavaScript and improve Core Web Vitals on every page.

14 min read
Web Font Loading Chain: FOIT, FOUT and the Optimized StrategyUnoptimized: FOIT + Layout ShiftHTML loaded - text invisible (FOIT)fonts.googleapis.com - DNS + connect (3rd party)Download font (TTF 280 KB, no subset)blocked 2.1sCLS: 0.18 (font swap)Text jumps on font swap - poor CLSOptimized: font-display + preloadPreload WOFF2 (self-hosted, 22 KB subset)rel=preload as=font crossorigin in HTML headfont-display: swap + size-adjust fallbackFallback metrics matched: barely visible swapCLS: 0.01Instantly readable text, stable layoutResult: no FOIT, CLS below 0.1, font data ~75% smaller1. Self-HostingServe fonts locallyinstead of 3rd partyGDPR + 1 fewer roundtrip2. WOFF2 + subsetCompression + onlyneeded glyphsup to 70% smaller3. font-displayswap or optionalavoid FOITtext visible instantly4. Fallback matchmatch size-adjust,ascent, line-gapCLS toward 0font-display strategiesswapfallback first, then swapoptionalno swap after 100ms - CLS 0fallbackshort block, then swap windowauto / blockFOIT risk - avoidFormat comparison (same font)TTF / OTF~100%WOFF~60%WOFF2~30%

Web Font Performance: Cut Load Time With Fonts

Web fonts cost load time and cause layout shifts. Learn how to optimize fonts with font-display, preload, subsetting and WOFF2 for fast pages.

13 min read
Video Performance: the load path under controlPoster as LCP candidate, lean preload, modern codec - the video does not slow the page downPoster as LCP candidatePoster (WebP) first, video streams afterLCP 1.2 s instead of 1.55 s (DebugBear)Choose preload sparinglypreload=none0 bytes upfrontpreload=metadatametadata onlyautoplayloads at once · 23%autoplay takes precedence over preload (MDN)Codec + container: smaller file3.7 MBGIF551 KBMP4341 KBWebMWebM ~91% smaller than the GIF (web.dev)Video as a load-time driver - in numbers23 %start via autoplay and load at once(HTTP Archive Web Almanac)91 %smaller than GIF: WebM over animation(web.dev)3 %of video elements use a poster(HTTP Archive Web Almanac)Illustrative values; real load times depend on setup, network and video.

Video Performance: Keeping Load Times Under Control

Video as an underrated load-time driver: poster as LCP candidate, lean preload, modern codecs and facades for embedded players - so no video slows the page.

13 min read
Jank-free at 60 fps - the 16.7 ms frame budgetOne frame: from JavaScript to the finished pixelJavaScriptStyleLayoutPaintCompositeBrowser reserve ~6 ms10 ms safe budget16.7 ms = 1 frameWhich CSS property triggers which workCheap: compositing onlytransform, opacityStyleLayoutPaintCompositeno layout, no paint - stable at 60 fpswork only on the compositor threadExpensive: full pipelinetop, left, width, height, box-shadowStyleLayoutPaintCompositeevery change: layout + paint + compositeeasily misses the 16.7 ms budgetEven frames (60 fps) versus jank (dropped frames)60 fpsJankFour levers against jankwill-change with intent | read then write | requestAnimationFrame | DevTools performance panel

Smooth Animations: Stopping Jank in the Frontend

Smooth animations without jank: the 16.7 ms frame budget, why only transform and opacity stay cheap, and how to hunt down frontend jank in the DevTools.

12 min read