Skip to main content

HTML & CSS Essentials

Before we can manipulate web pages with JavaScript, we need to understand how they are built. This chapter covers enough HTML and CSS to build real pages. It is not a comprehensive reference -- it is the working knowledge you need for the rest of this guide.

HTML: the structure

HTML (HyperText Markup Language) defines the structure of a web page using elements (tags).

A minimal HTML page

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My Page</title>
</head>
<body>
<h1>Hello, World!</h1>
<p>This is a paragraph.</p>
</body>
</html>
PartPurpose
<!DOCTYPE html>Tells the browser this is an HTML5 document
<html lang="en">Root element; lang helps screen readers and search engines
<head>Metadata -- not displayed on the page
<meta charset="UTF-8">Character encoding (supports all languages)
<meta name="viewport" ...>Makes the page responsive on mobile devices
<title>Browser tab title
<body>All visible content goes here

Elements and attributes

An HTML element has an opening tag, optional content, and a closing tag:

<p class="intro">This is a paragraph.</p>
  • <p> -- opening tag
  • class="intro" -- attribute (key-value pair on the tag)
  • This is a paragraph. -- content
  • </p> -- closing tag

Some elements are self-closing (no content):

<img src="photo.jpg" alt="A photo">
<br>
<hr>
<input type="text">

Common HTML elements

Headings

Six levels, <h1> (most important) through <h6> (least):

<h1>Main Title</h1>
<h2>Section Heading</h2>
<h3>Subsection</h3>

Use headings in order -- do not skip levels. A page should have exactly one <h1>.

Paragraphs and text

<p>A paragraph of text.</p>
<strong>Bold (important)</strong>
<em>Italic (emphasis)</em>
<code>Inline code</code>
<br> <!-- Line break -->
<hr> <!-- Horizontal rule -->
<a href="https://example.com">Visit Example</a>
<a href="/about">About Page</a>
<a href="#section2">Jump to Section 2</a>
<a href="https://example.com" target="_blank" rel="noopener noreferrer">Opens in new tab</a>

Always include rel="noopener noreferrer" when using target="_blank" -- it prevents the linked page from accessing your page's window.opener.

Images

<img src="photo.jpg" alt="Description of the photo" width="400" height="300">

The alt attribute is required for accessibility -- it describes the image to screen readers and displays if the image fails to load.

Lists

<!-- Unordered list (bullets) -->
<ul>
<li>Apple</li>
<li>Banana</li>
<li>Cherry</li>
</ul>

<!-- Ordered list (numbers) -->
<ol>
<li>First step</li>
<li>Second step</li>
<li>Third step</li>
</ol>

Tables

<table>
<thead>
<tr>
<th>Name</th>
<th>Age</th>
</tr>
</thead>
<tbody>
<tr>
<td>Ada</td>
<td>36</td>
</tr>
<tr>
<td>Bob</td>
<td>25</td>
</tr>
</tbody>
</table>

Divs and spans

Generic containers:

<!-- Block-level container (takes full width) -->
<div class="card">
<h2>Card Title</h2>
<p>Card content.</p>
</div>

<!-- Inline container (flows with text) -->
<p>The price is <span class="price">$9.99</span></p>

Semantic HTML

Semantic elements describe their meaning, not just their appearance. Use them instead of generic <div> elements:

<header>
<nav>
<a href="/">Home</a>
<a href="/about">About</a>
</nav>
</header>

<main>
<article>
<h2>Article Title</h2>
<p>Article content...</p>
</article>

<aside>
<h3>Related Links</h3>
<ul>
<li><a href="#">Link 1</a></li>
</ul>
</aside>
</main>

<footer>
<p>&copy; 2025 My Website</p>
</footer>
ElementUse for
<header>Page or section header
<nav>Navigation links
<main>Primary page content (one per page)
<article>Self-contained content (blog post, news article)
<section>Thematic grouping of content
<aside>Sidebar, related content
<footer>Page or section footer

Semantic HTML improves accessibility (screen readers understand the structure), SEO (search engines rank it better), and maintainability.

Forms

Forms collect user input. They are essential for interactive web pages:

<form id="signup-form">
<div>
<label for="username">Username:</label>
<input type="text" id="username" name="username" required>
</div>

<div>
<label for="email">Email:</label>
<input type="email" id="email" name="email" required>
</div>

<div>
<label for="password">Password:</label>
<input type="password" id="password" name="password" minlength="8" required>
</div>

<div>
<label for="role">Role:</label>
<select id="role" name="role">
<option value="user">User</option>
<option value="admin">Admin</option>
</select>
</div>

<div>
<label>
<input type="checkbox" name="terms" required>
I agree to the terms
</label>
</div>

<div>
<label>Preference:</label>
<label><input type="radio" name="pref" value="light"> Light</label>
<label><input type="radio" name="pref" value="dark" checked> Dark</label>
</div>

<div>
<label for="bio">Bio:</label>
<textarea id="bio" name="bio" rows="4"></textarea>
</div>

<button type="submit">Sign Up</button>
</form>

Key points:

  • <label for="id"> links a label to an input -- clicking the label focuses the input.
  • required, minlength, type="email" provide built-in validation.
  • name attributes identify form data when submitted.
  • We will handle form submission with JavaScript in the Events chapter.

Common input types

TypeRenders as
textSingle-line text field
emailText field with email validation
passwordMasked text field
numberNumeric input with up/down arrows
checkboxToggle on/off
radioSelect one from a group
dateDate picker
fileFile upload
hiddenInvisible (for sending data)

CSS: the presentation

CSS (Cascading Style Sheets) controls how HTML elements look.

Adding CSS

Three ways to add CSS (in order of preference):

1. External stylesheet (best practice):

<head>
<link rel="stylesheet" href="styles.css">
</head>

2. <style> tag in <head>:

<head>
<style>
body { font-family: sans-serif; }
</style>
</head>

3. Inline styles (avoid):

<p style="color: red;">Red text</p>

Always use external stylesheets for real projects. They can be cached, shared across pages, and are easier to maintain.

CSS selectors

Selectors target which elements to style:

/* Element selector -- all <p> elements */
p {
color: #333;
}

/* Class selector -- elements with class="card" */
.card {
border: 1px solid #ddd;
padding: 16px;
}

/* ID selector -- the element with id="header" */
#header {
background: #f0f0f0;
}

/* Descendant -- <a> inside <nav> */
nav a {
text-decoration: none;
}

/* Direct child -- <li> that is a direct child of <ul> */
ul > li {
list-style: disc;
}

/* Multiple selectors */
h1, h2, h3 {
font-family: Georgia, serif;
}

/* Attribute selector */
input[type="text"] {
border: 1px solid #ccc;
}

/* Pseudo-classes */
a:hover {
color: blue;
}

button:disabled {
opacity: 0.5;
}

li:first-child {
font-weight: bold;
}

Specificity

When multiple rules target the same element, specificity determines which wins:

SelectorSpecificityExample
ElementLowestp { }
ClassMedium.card { }
IDHigh#header { }
Inline styleHigheststyle="..."

When specificity is equal, the last rule wins. Prefer classes over IDs for styling.

The box model

Every HTML element is a rectangular box with four layers:

┌─────────────────────────── Margin ───────────────────────────┐
│ ┌──────────────────────── Border ────────────────────────┐ │
│ │ ┌───────────────────── Padding ────────────────────┐ │ │
│ │ │ │ │ │
│ │ │ Content │ │ │
│ │ │ │ │ │
│ │ └──────────────────────────────────────────────────┘ │ │
│ └────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────┘
.box {
width: 200px; /* content width */
padding: 20px; /* space inside the border */
border: 2px solid #333;
margin: 16px; /* space outside the border */
}

box-sizing: border-box

By default, width sets only the content width. With border-box, width includes padding and border:

/* Apply to everything -- do this in every project */
*, *::before, *::after {
box-sizing: border-box;
}

With border-box: a width: 200px element with padding: 20px and border: 2px is 200px total, not 244px.

Display and positioning

Display values

/* Block -- takes full width, stacks vertically */
div { display: block; }

/* Inline -- flows with text, width/height ignored */
span { display: inline; }

/* Inline-block -- flows with text but respects width/height */
.badge { display: inline-block; }

/* None -- removes from the page */
.hidden { display: none; }

Position

/* Static -- default, follows normal flow */
.static { position: static; }

/* Relative -- offset from its normal position */
.relative {
position: relative;
top: 10px;
left: 20px;
}

/* Absolute -- positioned relative to nearest positioned ancestor */
.absolute {
position: absolute;
top: 0;
right: 0;
}

/* Fixed -- positioned relative to the viewport (stays on scroll) */
.fixed-header {
position: fixed;
top: 0;
left: 0;
width: 100%;
}

/* Sticky -- switches from relative to fixed at a threshold */
.sticky-nav {
position: sticky;
top: 0;
}

Flexbox

Flexbox is the modern way to create layouts. It handles alignment and distribution of space.

Basic flex layout

.container {
display: flex;
gap: 16px; /* space between children */
}
<div class="container">
<div>Item 1</div>
<div>Item 2</div>
<div>Item 3</div>
</div>

This places items in a row by default.

Direction

.row { flex-direction: row; }        /* default: left to right */
.column { flex-direction: column; } /* top to bottom */

Alignment

.container {
display: flex;
/* Main axis (horizontal in row, vertical in column) */
justify-content: center; /* center, flex-start, flex-end, space-between, space-around, space-evenly */
/* Cross axis (vertical in row, horizontal in column) */
align-items: center; /* center, flex-start, flex-end, stretch, baseline */
}

Common patterns

Centering an element:

.center {
display: flex;
justify-content: center;
align-items: center;
height: 100vh; /* full viewport height */
}

Navigation bar:

.nav {
display: flex;
justify-content: space-between;
align-items: center;
padding: 16px;
}

Card grid:

.grid {
display: flex;
flex-wrap: wrap;
gap: 16px;
}

.card {
flex: 1 1 300px; /* grow, shrink, base width */
}

Flex item properties

.item {
flex-grow: 1; /* how much extra space to take */
flex-shrink: 0; /* whether to shrink below basis */
flex-basis: 200px; /* starting size before grow/shrink */
}

/* Shorthand */
.item { flex: 1 0 200px; }

/* Common shortcuts */
.fill { flex: 1; } /* grow to fill space */
.fixed { flex: 0 0 200px; } /* fixed 200px, no grow/shrink */

Responsive design

Make your page work on all screen sizes.

The viewport meta tag

Already in our HTML boilerplate:

<meta name="viewport" content="width=device-width, initial-scale=1.0">

Without this, mobile browsers zoom out to fit the desktop layout.

Media queries

Apply CSS rules based on screen size:

/* Base styles (mobile first) */
.container {
padding: 16px;
}

.grid {
display: flex;
flex-direction: column;
gap: 16px;
}

/* Tablet and up (768px) */
@media (min-width: 768px) {
.grid {
flex-direction: row;
flex-wrap: wrap;
}

.card {
flex: 1 1 calc(50% - 16px);
}
}

/* Desktop (1024px) */
@media (min-width: 1024px) {
.container {
max-width: 1200px;
margin: 0 auto;
}

.card {
flex: 1 1 calc(33.333% - 16px);
}
}

Responsive units

UnitMeaning
pxFixed pixels
%Relative to parent
emRelative to parent font size
remRelative to root (<html>) font size
vw / vhPercentage of viewport width / height
frFraction of available space (CSS Grid)

Prefer rem for font sizes and spacing -- it respects user zoom preferences.

Responsive images

img {
max-width: 100%;
height: auto;
}

This prevents images from overflowing their container.

A complete example

Here is a small, responsive page with everything covered so far:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My First Page</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<header>
<nav class="nav">
<a href="/" class="logo">MySite</a>
<div class="nav-links">
<a href="#about">About</a>
<a href="#projects">Projects</a>
<a href="#contact">Contact</a>
</div>
</nav>
</header>

<main>
<section id="about" class="section">
<h1>Welcome to My Site</h1>
<p>I am learning JavaScript and building things for the web.</p>
</section>

<section id="projects" class="section">
<h2>Projects</h2>
<div class="grid">
<div class="card">
<h3>Project One</h3>
<p>A calculator built with vanilla JavaScript.</p>
</div>
<div class="card">
<h3>Project Two</h3>
<p>A weather app using the Fetch API.</p>
</div>
<div class="card">
<h3>Project Three</h3>
<p>A to-do list with local storage.</p>
</div>
</div>
</section>

<section id="contact" class="section">
<h2>Contact</h2>
<form id="contact-form">
<label for="name">Name:</label>
<input type="text" id="name" name="name" required>

<label for="message">Message:</label>
<textarea id="message" name="message" rows="4" required></textarea>

<button type="submit">Send</button>
</form>
</section>
</main>

<footer>
<p>&copy; 2025 My Site. Built with HTML, CSS, and JavaScript.</p>
</footer>
</body>
</html>
/* styles.css */

*, *::before, *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}

body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
line-height: 1.6;
color: #333;
}

a {
color: #0066cc;
text-decoration: none;
}

a:hover {
text-decoration: underline;
}

/* Navigation */
.nav {
display: flex;
justify-content: space-between;
align-items: center;
padding: 16px 24px;
background: #f8f9fa;
border-bottom: 1px solid #e9ecef;
}

.logo {
font-size: 1.25rem;
font-weight: bold;
color: #333;
}

.nav-links {
display: flex;
gap: 24px;
}

/* Sections */
.section {
padding: 48px 24px;
max-width: 1000px;
margin: 0 auto;
}

/* Cards */
.grid {
display: flex;
flex-wrap: wrap;
gap: 16px;
margin-top: 24px;
}

.card {
flex: 1 1 250px;
padding: 24px;
border: 1px solid #e9ecef;
border-radius: 8px;
background: #fff;
}

.card h3 {
margin-bottom: 8px;
}

/* Form */
form {
display: flex;
flex-direction: column;
gap: 12px;
max-width: 500px;
}

input, textarea {
padding: 8px 12px;
border: 1px solid #ccc;
border-radius: 4px;
font-size: 1rem;
}

button {
padding: 10px 20px;
background: #0066cc;
color: #fff;
border: none;
border-radius: 4px;
font-size: 1rem;
cursor: pointer;
}

button:hover {
background: #0052a3;
}

/* Footer */
footer {
text-align: center;
padding: 24px;
background: #f8f9fa;
border-top: 1px solid #e9ecef;
margin-top: 48px;
}

/* Responsive */
@media (max-width: 600px) {
.nav {
flex-direction: column;
gap: 12px;
}

.nav-links {
gap: 16px;
}
}

Save both files in the same folder, open index.html in a browser, and resize the window to see the responsive behavior.

Summary

  • HTML defines page structure with semantic elements.
  • Use <header>, <nav>, <main>, <article>, <footer> instead of generic <div> elements.
  • Forms collect user input with built-in validation attributes.
  • CSS controls appearance -- use external stylesheets.
  • Box model: content + padding + border + margin. Always set box-sizing: border-box.
  • Flexbox handles layout: display: flex, justify-content, align-items, gap.
  • Media queries make pages responsive -- design mobile-first, then add breakpoints.

Next up: The DOM -- using JavaScript to read and change the page.