Skip to content
Laviyx Learn

Try

HTML course menu

Adding CSS and JavaScript to HTML: link, style, script, defer and async

Learn the ways to add CSS to HTML (external stylesheets, style elements and inline styles) and JavaScript (external files and inline scripts), where to put script tags, and the difference between defer, async and type=module.

Intermediate6 min readUpdated
On this page

HTML provides the content, CSS the look, and JavaScript the behaviour. This lesson shows how a page loads CSS and JavaScript, and how the way you load scripts affects speed.

Three ways to add CSS#

1. An external stylesheet (best for real sites)#

HTML
<head>
  <link rel="stylesheet" href="styles.css">
</head>
styles.css (CSS)
body { font-family: system-ui, sans-serif; }
h1 { color: #2f5fe0; }

One stylesheet can style every page of a site, and the browser caches it so it downloads only once.

2. A style element#

CSS can be written inside a <style> element, usually in the head:

HTML
<style>
  h1 { color: #2f5fe0; }
  .note { background: #fff3c4; padding: 8px; }
</style>
<h1>Styled heading</h1>
<p class="note">Styled with a style element.</p>
Result

Useful for single-page demos (like many examples on this site) and small amounts of page-specific CSS.

3. Inline styles#

The style attribute applies CSS to one element:

HTML
<p style="color: crimson; font-weight: bold">Inline styles affect only this paragraph.</p>
Result

Inline styles are hard to reuse and hard to override. Use them sparingly, for example for values set by JavaScript.

Adding JavaScript#

An external file#

HTML
<script src="app.js" defer></script>

An inline script#

HTML
<p id="greeting">Hello</p>
<script>
  document.getElementById("greeting").textContent = "Hello from JavaScript!";
</script>
Result

A <script> that loads a file must be empty: <script src="app.js">code here</script> ignores the code inside.

Where to put script tags#

By default, when the browser meets a <script>, it stops building the page, downloads the script, runs it, and only then continues. That has two consequences:

  • A script in the head that is slow to download delays the whole page.
  • A script that runs before the elements it uses exist cannot find them.

The old fix was to put scripts at the end of <body>. The modern fix is defer.

defer, async and module#

HTML
<script src="app.js" defer></script>
<script src="analytics.js" async></script>
<script src="main.js" type="module"></script>
AttributeDownloadsRunsOrder kept?Use for
(none)Blocks the pageImmediatelyYesRarely needed today
deferIn parallelAfter the HTML is fully parsedYesMost of your own scripts
asyncIn parallelAs soon as it arrivesNoIndependent scripts such as analytics
type="module"In parallelAfter parsing (deferred by default)YesModern JavaScript using import and export

With defer or type="module" you can keep scripts in the <head>, the page is not blocked, and all elements exist when your code runs.

Putting it together#

index.html (HTML)
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Counter</title>
    <link rel="stylesheet" href="styles.css">
    <script src="app.js" defer></script>
  </head>
  <body>
    <h1>Counter</h1>
    <button type="button" id="add">Add one</button>
    <p>Count: <span id="count">0</span></p>
  </body>
</html>
app.js (JavaScript)
let count = 0;
document.getElementById("add").addEventListener("click", () => {
  count += 1;
  document.getElementById("count").textContent = count;
});

Here is the same page running (with the CSS and JavaScript placed inline so the preview can show it):

HTML
<h1>Counter</h1>
<button type="button" id="add">Add one</button>
<p>Count: <span id="count">0</span></p>
JavaScript
let count = 0;
document.getElementById("add").addEventListener("click", () => {
  count += 1;
  document.getElementById("count").textContent = count;
});
Result

Continue with the CSS course and the JavaScript course to learn both languages properly.

Practice#

Practice exercise

Write the head of a page that loads css/site.css, a module script js/main.js, and an independent js/chat-widget.js that should not delay the page or wait for other scripts.

Show solution
HTML
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>My Site</title>
  <link rel="stylesheet" href="css/site.css">
  <script src="js/main.js" type="module"></script>
  <script src="js/chat-widget.js" async></script>
</head>

Key takeaway#

Finished this lesson?