Optimizing Render-Blocking Resources
Render-blocking resources are CSS and JS files that browser loads before first page render. Each such resource adds time to FCP (First Contentful Paint) and LCP.
What Blocks Rendering
CSS in <head> without media query blocks rendering entirely. Browser must build CSSOM before first render. JS without async/defer stops HTML parser. Google Fonts without preconnect add extra DNS lookup.
Working with CSS
Critical CSS — embed minimal necessary styles in <style> in head, main CSS loads asynchronously:
<style>/* critical inline styles */</style>
<link rel="preload" href="styles.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="styles.css"></noscript>
Tools for critical CSS generation: critical (npm), Critters (Webpack plugin, used by Next.js), penthouse.
For non-critical styles use media trick:
<link rel="stylesheet" href="print.css" media="print">
<link rel="stylesheet" href="large.css" media="(min-width: 1200px)">
CSS split by routes — Next.js and Nuxt do this automatically via code splitting. For raw Webpack configured via MiniCssExtractPlugin with chunkFilename.
Working with JavaScript
Attribute defer — script loads parallel, executes after HTML parsing. Attribute async — loads parallel, executes as soon as loaded (may break order).
<!-- Rule: everything non-critical for first screen — defer -->
<script src="analytics.js" defer></script>
<script src="chat-widget.js" async></script>
For modules (type="module") defer applies automatically.
Dynamic import for heavy components:
// React
const HeavyChart = lazy(() => import('./HeavyChart'))
// Vue
const HeavyChart = defineAsyncComponent(() => import('./HeavyChart.vue'))
Google Fonts and Third-Party Fonts
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<!-- Self-hosting fonts eliminates problem entirely -->
Optimal solution — font-display: swap + self-hosted via fontsource or manually converted woff2.
Preload for LCP Resources
If LCP element is image or font discovered late:
<link rel="preload" as="image" href="/hero.webp" fetchpriority="high">
<link rel="preload" as="font" href="/fonts/inter.woff2" type="font/woff2" crossorigin>
Audit and Control
PageSpeed Insights and Lighthouse show list of blocking resources in "Eliminate render-blocking resources" section. Chrome DevTools → Performance → Waterfall shows exact chronology.
webpack-bundle-analyzer helps find what landed in initial chunk and should be extracted.
Typical Results
After optimization FCP drops 300–800ms on medium connections. LCP improves 15–30% with proper preload of critical resources.
Execution Time
Audit + setup critical CSS + defer/async for scripts — 1–2 business days. Full implementation with CSS split by routes — 3–5 days.







