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>
| Part | Purpose |
|---|---|
<!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 tagclass="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 -->
Links
<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>© 2025 My Website</p>
</footer>
| Element | Use 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.nameattributes identify form data when submitted.- We will handle form submission with JavaScript in the Events chapter.
Common input types
| Type | Renders as |
|---|---|
text | Single-line text field |
email | Text field with email validation |
password | Masked text field |
number | Numeric input with up/down arrows |
checkbox | Toggle on/off |
radio | Select one from a group |
date | Date picker |
file | File upload |
hidden | Invisible (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:
| Selector | Specificity | Example |
|---|---|---|
| Element | Lowest | p { } |
| Class | Medium | .card { } |
| ID | High | #header { } |
| Inline style | Highest | style="..." |
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
| Unit | Meaning |
|---|---|
px | Fixed pixels |
% | Relative to parent |
em | Relative to parent font size |
rem | Relative to root (<html>) font size |
vw / vh | Percentage of viewport width / height |
fr | Fraction 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>© 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.