Why is it generally a good idea to position CSS `<link>`s between `<head></head>` and JS `<script>`s just before `</body>`?
Do you know any exceptions?TL;DR
Put render-blocking stylesheets in <head> so the browser discovers them early and can render styled content without a flash of unstyled content. The old advice to put every script just before </body> avoids parser blocking, but modern pages usually put application scripts in <head> with defer or type="module"; they download while HTML is parsed and execute after parsing. Use async only for independent scripts whose execution order does not matter.
<head><link rel="stylesheet" href="/styles.css" /><script src="/app.js" defer></script><script type="module" src="/features.js"></script></head>
Why is it generally a good idea to position CSS <link>s between <head></head> and JS <script>s just before </body>?
The placement controls when the browser discovers a resource and whether fetching or executing it delays HTML parsing or rendering.
Put required stylesheets in <head>
The browser can parse HTML and fetch external CSS concurrently, but it normally waits for required stylesheets before painting content that depends on them. Discovering CSS in <head> starts that request early and reduces the chance of rendering unstyled content and repainting it later.
CSS that is not needed for the initial view can be loaded conditionally, split by route, or guarded by an appropriate media attribute. Inline only genuinely critical CSS: inlining too much prevents caching and makes the HTML larger.
Choose the script behavior explicitly
The important distinction is not simply “head versus body”; it is the script's loading mode.
| Script | Fetching and execution behavior | Appropriate use |
|---|---|---|
Classic <script src> | Fetches and executes immediately, blocking the HTML parser | Rare scripts that must run at that exact parser position |
<script defer> | Fetches in parallel, executes in document order after parsing, before DOMContentLoaded | Most classic application scripts |
<script type="module"> | Fetches the module graph and defers execution by default | Modern module-based applications |
<script async> | Fetches in parallel and executes as soon as ready; order is not guaranteed | Independent analytics or advertising scripts |
Script before </body> | Is discovered late but does not block most document parsing | Legacy pages that cannot use defer |
A deferred script can safely query elements parsed from the document without waiting for load. The load event waits for additional resources such as images and is usually later than necessary.
Exceptions and tradeoffs
- A tiny inline bootstrap may need to run early, for example to set a theme class before the first paint. Keep it small and compatible with the site's Content Security Policy.
- A third-party script that is independent of application code can use
async, but its cost should still be measured. - A script whose output must appear at a particular parser position is inherently parser-blocking. Prefer DOM APIs and templates over
document.write(). - Omitting optional
<head>or<body>tags does not create a meaningful performance optimization and usually makes source markup harder to inspect.
Use the Network and Performance panels to verify discovery time, parser blocking, render-blocking resources, and actual paint timings rather than assuming one placement is fastest for every page.