The browser reads HTML sequentially from top to bottom, building the DOM tree. This process can be blocked by certain resources.
🔗 Example - Shows how HTML parsing continues while content loads, with gradual rendering
- All CSS in
<head>
blocks the first paint/render - The browser won't display content until CSS is processed
- Creates the CSSOM (CSS Object Model) before rendering
🔗 Example - Demonstrates how external CSS blocks the first paint
🔗 Example - Shows immediate rendering with inline CSS
🔗 Example - Optimal approach with critical CSS inline
This is the most important blocking behavior that's often overlooked:
- JavaScript execution is blocked by any pending CSS downloads/processing
- Even
async
anddefer
scripts wait for CSS to complete before executing - Inline scripts are also blocked by CSS loading
- This prevents JavaScript from accessing computed styles before CSS is ready
🔗 Example - Key example showing how slow CSS blocks all JavaScript execution
<script src="script.js"></script>
- Blocks DOM parsing until downloaded and executed
- Blocked by CSS loading - waits for all pending CSS
- Execute in document order
- Can prevent page display entirely
🔗 Example - Shows how regular scripts halt DOM parsing
<script async src="script.js"></script>
- Download parallel to DOM parsing (non-blocking download)
- Still blocked by CSS loading during execution phase
- Execute immediately when both script AND CSS are ready
- Execute in download completion order, not document order
🔗 Example - Shows async scripts still waiting for CSS
<script defer src="script.js"></script>
- Download parallel to DOM parsing (non-blocking download)
- Blocked by CSS loading until CSS completes
- Execute after DOM parsing completes AND CSS is ready
- Execute in document order
- The examples show deferred scripts maintaining order despite different download times
🔗 Example - Demonstrates defer behavior with CSS interaction
var script = document.createElement("script");
script.src = "script.js";
document.body.append(script);
- Behave as async by default
- Still blocked by CSS when they're ready to execute
- Can be made synchronous with
script.async = false
🔗 Example - JavaScript-created scripts and their behavior
🔗 Example - How to bypass CSS blocking for inline scripts
The examples demonstrate this critical sequence:
- CSS starts loading (render-blocking)
- JavaScript discovers CSS is loading
- JavaScript execution pauses (even async/defer scripts)
- CSS finishes loading and parsing
- JavaScript can now execute
- Rendering can proceed
Based in the throttled examples:
- HTML parsing begins
- CSS discovered and requested (blocks rendering AND script execution)
- Scripts discovered and requested (download in parallel)
- CSS completes → JavaScript can execute
- DOM parsing completes
- Render tree creation (DOM + CSSOM)
- Layout and paint
- Slow CSS blocks everything: the throttled CSS examples show how slow stylesheets delay all JavaScript execution
- JavaScript dependency chain: Scripts can't run until CSS is ready, creating cascading delays
- Critical path optimization: CSS should be minimal and fast, as it's the bottleneck for both rendering and script execution
- Loading strategy matters: Even with async/defer, CSS remains the gatekeeper
The examples demonstrate that CSS is the critical bottleneck in page loading - it doesn't just block rendering, it blocks JavaScript execution, making it the most important resource to optimize for page load performance.