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 void elements (no content and no closing tag):

<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 to describe the page hierarchy - avoid skipping levels. Most pages should have one <h1> for the main title.

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. Use meaningful text for informative images, or alt="" for decorative images that screen readers should skip. The text also 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), can help search engines understand the content, and improves 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>

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

<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.
  • <fieldset> and <legend> group related controls, such as radio buttons.
  • 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 the user's root font-size 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.