Inline Small Assets
Eliminate HTTP requests for small CSS, JS, and images by embedding them directly into the HTML.
Metrics
This technique can move up to 33% of LCP's share of the Lighthouse score.
This technique does not move TBT.
This technique does not move CLS.
This technique can move up to 67% of FCP's share of the Lighthouse score.
This technique can move up to 33% of SI's share of the Lighthouse score.
This technique does not move TTFB.
Overview
Every external resource — a stylesheet, a script file, a small image — requires its own HTTP request: a DNS lookup, TCP connection (on HTTP/1.1), and a full request-response cycle. For very small assets, the connection overhead can exceed the transfer time for the file itself. Inlining embeds the content directly into the HTML document, eliminating the round-trip entirely. The trade-off is that inlined content cannot be independently cached — it rides with the HTML document’s cache lifetime. This makes inlining appropriate for assets that are small, critical for initial render, and change infrequently.
Impact grade, A+ to D: how much of the Lighthouse score this technique can move. Unaffected: TBT, CLS, TTFB.
The Problem
A WordPress theme may load 3–5 small CSS files for critical above-fold styles, each 2–8 KB, each requiring a separate HTTP request. On HTTP/1.1, each request blocks the others. On HTTP/2, they can be parallelized, but each still requires a round-trip. If the combined size is under 10–15 KB, the cost of 5 round-trips outweighs the caching advantage. Similarly, a small SVG icon used site-wide, a 500-byte JavaScript snippet for feature detection, or a 1 KB CSS reset loaded from an external URL all represent opportunities to save requests at the cost of a small increase in HTML size.
Performance Impact
LCP
Indirect
faster FCP and reduced request count creates a more favorable waterfall for the LCP element
FCP
50–200ms
render-blocking CSS and critical JS available immediately with the HTML — no extra requests
SI
Moderate
fewer render-blocking requests means the visible area completes rendering sooner
Risk: Low
inlined content inflates HTML size and cannot be independently cached — limit to assets under 5–14 KB that change rarely
How it works
01
Inline small CSS with a style tag
For critical above-fold CSS under 10–14 KB, replace the
<link rel="stylesheet">tag with a<style>block containing the CSS text directly. The HTML document is now larger, but the browser can begin styling immediately upon parsing rather than waiting for an external fetch. WordPress plugins like WP Rocket and NitroPack offer automatic inlining of small stylesheets.02
Inline small JavaScript
Feature detection scripts, polyfill loaders, and configuration objects that are under 1–2 KB can be inlined as
<script>blocks. This avoids an HTTP round-trip for code that must execute synchronously during page initialization. Use sparingly — inlined JS is not cached separately and inflates every page’s HTML payload.03
Inline small images as base64 data URIs
Images under 2 KB (small icons, spacer images, decorative elements) can be embedded as
data:image/png;base64,…ordata:image/svg+xml;base64,…URIs. The image is embedded in the HTML or CSS, eliminating its HTTP request. Note that base64 encoding adds ~33% to the file size — a 1.5 KB PNG becomes ~2 KB as a data URI.04
Threshold and heuristics
A common threshold is: inline if the asset is under 2 KB for images, under 5 KB for JS, under 14 KB for CSS. Above these sizes, the HTTP/2 parallel download benefit typically exceeds the round-trip overhead, and the cache hit benefit of a separate asset URL becomes significant.
Code Example
<!-- 3 small CSS files: 3 HTTP requests, each 2–5 KB -->
<link rel="stylesheet" href="/wp-content/themes/my-theme/css/reset.css">
<link rel="stylesheet" href="/wp-content/themes/my-theme/css/base.css">
<link rel="stylesheet" href="/wp-content/themes/my-theme/css/nav.css">
<!-- Small icon image: 1 HTTP request for 800 bytes -->
<img src="/wp-content/themes/my-theme/images/checkmark.svg" alt=""><!-- All 3 CSS files inlined: 0 HTTP requests, content available immediately -->
<style>
/* reset.css */ *, *::before, *::after { box-sizing: border-box; }
/* base.css */ body { margin: 0; font-family: sans-serif; }
/* nav.css */ .nav { display: flex; gap: 1rem; }
</style>
<!-- SVG icon inlined: 0 HTTP requests -->
<svg aria-hidden="true" width="16" height="16" viewBox="0 0 16 16">
<path d="M13.5 2.5L6 10l-3.5-3.5L1 8l5 5 9-9z" fill="currentColor"/>
</svg>In WordPress, inline small stylesheets in functions.php: dequeue the external file and output the CSS via wp_head inside a <style> tag. For images, SVG inlining can be done with file_get_contents(get_theme_file_path('images/icon.svg')).
Limitations
- Inlined content is not separately cacheable. If an external CSS file is cached for 1 year and used on every page, users download it once. Inlined into every page, the same CSS bytes are downloaded on every single page visit — this makes inlining cost-effective only for very small assets.
- Base64 encoding adds ~33% to image file sizes. A 2 KB image becomes 2.7 KB as a data URI. For images used on multiple pages, consider whether an external URL with long-cache headers is more efficient.
- Inlining too much CSS (over 20–30 KB) can delay the HTML parse itself and push the document’s initial parse time past the point where external CSS would have loaded. Test with DevTools to verify the break-even point.
Common Mistakes
Inlining large CSS frameworks or full stylesheets
Inlining is for small, critical assets only. A full 80 KB Bootstrap stylesheet inlined into every page means 80 KB of non-cacheable CSS on every visit. Use inline CSS only for truly critical above-fold styles (often under 14 KB) and load the rest asynchronously.
Inlining assets that change frequently
When you inline a CSS or JS file, it loses its own cache entry. If that content changes weekly, every change invalidates the cached HTML for every page it appears on — forcing re-downloads of the full HTML. Only inline assets that are stable over long periods.