You’ve probably seen this before: you open your web app, and the page feels sluggish. Maybe the text takes a moment to appear, images pop in late, or fonts swap unexpectedly. It’s tempting to blame slow networks or big files. But sometimes, the culprit is how the browser decides which resources to load first.
I ran into this when debugging a client’s page that stubbornly refused to show meaningful content quickly, even though the payload sizes were tiny. The problem wasn’t what was loading, but when it loaded.
Let’s unpack how browsers juggle scripts, styles, images, and fonts during page load. Understanding this can help you get your page’s main content on screen faster and avoid those annoying flickers and delays.
The Critical Rendering Path: Your Page’s Loading Highway
The critical rendering path (CRP) is the sequence of steps a browser takes to turn HTML, CSS, and JavaScript into pixels on your screen. It involves:
- Parsing HTML to build the DOM (Document Object Model)
- Parsing CSS to build the CSSOM (CSS Object Model)
- Running JavaScript which may modify the DOM or CSSOM
- Combining these to create a render tree
- Painting pixels
But here’s the catch: resources like scripts, styles, images, and fonts don’t all arrive in the order you list them in your HTML. Browsers assign priorities to these resources based on what’s critical for rendering.
How Browsers Decide What Loads First
Browsers use complex heuristics to prioritize resource loading, but here’s the gist from what I’ve seen and tested:
1. Stylesheets block rendering and get highest priority
When the browser encounters a <link rel="stylesheet">, it must fetch and parse those styles before it can render the page. Styles can change layout, so the browser pauses painting until CSSOM is ready.
This means stylesheets get a high fetch priority. The browser also delays downloading non-critical resources if CSSOM isn’t ready, to avoid unnecessary work.
2. Scripts block HTML parsing, but priority depends on attributes
Scripts can stop HTML parsing because they can modify the DOM or styles. Here’s how:
- Classic scripts (no
async or defer) block parsing and delay other downloads until executed.
defer scripts download in parallel but execute after parsing completes.
async scripts download in parallel and execute as soon as ready, possibly interrupting parsing.
Because scripts can affect the DOM, browsers prioritize classic scripts highly but try to avoid blocking the page unnecessarily by downloading async and defer scripts with lower priority.
3. Fonts get special treatment to avoid invisible text
Fonts are tricky because the browser wants to avoid the dreaded "flash of invisible text" (FOIT). It prioritizes font loading, but sometimes delays text rendering until fonts arrive or fallbacks kick in.
Browsers use a font-display strategy to decide:
- block: hide text until font loads (up to a timeout)
- swap: show fallback immediately, swap when font loads
- optional: show fallback and don’t swap if slow
Fonts often have a medium to high priority but won’t block styles or scripts.
4. Images and other media load with lower priority
Images and videos usually have lower priority because they don’t block rendering of text and layout. The browser downloads them opportunistically once critical styles and scripts are underway.
Lazy loading images further lowers their priority, deferring network requests until needed.
Why This Matters for First Contentful Paint (FCP) and Largest Contentful Paint (LCP)
FCP measures when the browser paints any content (like text or an image). LCP focuses on the largest visible content element.
If stylesheets or critical scripts load slowly, the browser delays painting, hurting FCP. If fonts load late, you get invisible text or re-layouts. If images are low priority or lazy-loaded, LCP gets pushed back.
By knowing how browsers prioritize, you can tweak your resource loading to push key assets earlier.
Debugging with DevTools: Spotting Resource Priorities
Open Chrome DevTools, go to the Network tab, and look for the Priority column. You’ll see values like "High", "Medium", "Low" for each resource.
Try this:
- Reload your page with the Network tab open.
- Find your CSS files, they should have High priority.
- Look at scripts: classic scripts are high priority and block parsing; async and defer scripts usually have lower priority.
- Fonts often show as Medium or High priority.
- Images are usually Low priority unless marked critical.
In the Performance tab, record a reload and watch how resources load relative to paint events. This helps you correlate resource fetching with the visible page load.
Practical Tips to Influence Loading Priority
- Inline critical CSS to avoid blocking on external stylesheets.
- Use
<link rel="preload" as="style"> or <link rel="preload" as="script"> to hint the browser to prioritize resources.
- Move non-critical scripts to
defer or async to avoid blocking parsing.
- Use
font-display: swap in your @font-face rules to avoid invisible text.
- Defer or lazy load images below the fold.
A Real-World Surprise: Why Your Script Order Can Backfire
I once shuffled script tags to load a critical analytics script earlier, hoping it’d start tracking sooner. But the page’s FCP got worse.
Turns out, that script was a classic blocking script with no async or defer. By moving it earlier, it blocked parsing of stylesheets and delayed rendering.
The fix? Marking that script with defer so it downloaded early but executed after parsing, letting styles load and paint happen sooner.
Wrapping Up
Browsers don’t just throw resources at the network all at once. They carefully prioritize loading stylesheets, scripts, fonts, and images based on how crucial each is to rendering your page.
By understanding these priorities, you can structure your HTML and resource hints to get pixels on screen faster, improve user experience, and nail those Core Web Vitals.
Next time your page feels slow, dive into DevTools to check resource priorities. Sometimes, reordering your tags or tweaking attributes is all you need to speed things up.
And if you want a deeper look at what’s happening under the hood during your page load, stick around , there’s a whole world of browser loading internals waiting to be explored.