Complete Guide

Web
Basics

The guide that teaches you to build solid websites, from your first HTML tag to secure deployment

8
Structured
Chapters
48
Fundamentals
Explained
100+
Code
Examples
HTML · CSS · JavaScript · Responsive · Accessibility · SEO · Tools · Security

Table of Contents

01 HTML — Structure
01Give your page a solid structureStructurep.4
02Give meaning to your tagsSemanticsp.4
03Create working formsFormsp.5
04Organize your data in tablesTablesp.5
05Integrate images, videos and audioMultimediap.6
06Link your pages togetherLinksp.6
02 CSS — Styling
07Target exactly what you want to styleSelectorsp.7
08Master the space around each elementBox Modelp.7
09Align your elements in a lineFlexboxp.8
10Create grid-based layoutsGridp.8
11Centralize your colors and valuesVariablesp.9
12Add movement to your elementsTransitionsp.9
13Adapt your design to every screenResponsivep.10
03 JavaScript — Interactivity
14Store and manipulate your dataVariablesp.11
15Select and modify your page in real timeDOMp.11
16React to user actionsEventsp.12
17Exchange data with a serverFetch/APIp.12
18Save data in the browserlocalStoragep.13
19Write modern, readable JavaScriptES6+p.13
04 Responsive — Adaptation
20Configure the mobile viewportViewportp.14
21Design mobile-firstMobile-firstp.14
22Define your breakpointsBreakpointsp.15
23Adapt your images to every screenImagesp.15
24Make your touch buttons comfortableTouchp.16
25Test on real devicesTestingp.16
05 Accessibility — Inclusion
26Make your page readable by everyoneSemantic HTMLp.17
27Enhance accessibility with ARIAARIAp.17
28Choose readable colorsWCAG Contrastp.18
29Make everything keyboard accessibleKeyboardp.18
30Communicate with screen readersScreen readersp.19
31Respect user preferencesPreferencesp.19
06 SEO & Performance — Visibility
32Help Google understand your pageMeta tagsp.20
33Structure your headings logicallyHeadingsp.20
34Get a good performance scoreCore Web Vitalsp.21
35Speed up your image loadingImage optimizationp.21
36Preload the right resourcesPreload/Prefetchp.22
37Reduce your code weightMinificationp.22
07 Tools — Productivity
38Configure your code editorVS Codep.23
39Save every version of your codeGitp.23
40Inspect and debug in the browserDevToolsp.24
41Put your site online for freeDeploymentp.24
42Choose your domain name and hostingDomain/Hostingp.25
08 Security — Protection
43Encrypt exchanges with HTTPSHTTPS/SSLp.26
44Control what your page can loadCSPp.26
45Prevent malicious code injectionXSSp.27
46Protect your forms against fake submissionsCSRFp.27
47Never trust user dataSanitizationp.28
48Add browser-side shieldsSecurity headersp.28

This guide is made for you

🚀

From zero to a live website

Each chapter helps you progress step by step, from raw HTML to production deployment.

💡

Understand, not just copy

An "In plain terms" block explains each concept with everyday analogies.

Customize it

Each topic tells you which values to change and what it actually does.

Tip

No need to read it all at once. Essential = must know. Important = strongly recommended. Useful = to go further.

01

HTML — Structure

6 fundamentals for building solid, well-organized pages

01
HTML · Structure
Give your page a solid structure
Essential
In plain terms: An HTML page is like a building. First you lay the foundation (<html>), then the roof (<head>) containing invisible info, and finally the rooms (<body>) where visible content lives. Without this structure, the browser doesn't know what to display or how.
<!DOCTYPE html> <!-- tells the browser: "this is HTML5" --> <html lang="fr"> <!-- page language --> <head> <meta charset="UTF-8"> <!-- accents and special characters --> <title>Ma page</title> <!-- title in the browser tab --> </head> <body> <h1>Welcome</h1> <!-- visible page content --> </body> </html>
Customize it
  • Change lang="fr" based on your content language (en, es, etc.)
  • Add <meta name="viewport"> so mobile displays correctly
  • The <title> appears in Google: make it count
My notes
02
HTML · Semantique
Give meaning to your tags
Essential
In plain terms: Using <div> everywhere is like writing a book without chapters or paragraphs. The text is there, but nobody can navigate it. Semantic tags (<header>, <nav>, <main>, <footer>) give each zone a role. Google and screen readers understand your page without seeing it.
<header> <!-- header: logo, site title --> <nav> <!-- navigation: menu links --> </header> <main> <!-- main content (one per page) --> <article> <!-- standalone content: article, post --> <section> <!-- thematic group with a heading --> <aside> <!-- related content: sidebar, inset --> </main> <footer> <!-- footer: legal, links -->
Customize it
  • Replace your <div> tags with the semantic tag that matches the role
  • Only one <main> per page, that's the rule
  • Each <section> must contain a heading (<h2>, <h3>...)
My notes
03
HTML · Forms
Create working forms
Essential
In plain terms: A form is a dialogue between your site and the visitor. Each field (<input>) is a question, and the <label> is the tag that tells what the field is for. Without a label, it's like a paper form with no heading: the visitor doesn't know what to write where. The field type (email, tel) even adapts the keyboard on mobile.
<form action="/submit" method="POST"> <label for="email">Your email</label> <!-- clickable label --> <input type="email" <!-- email keyboard on mobile --> id="email" <!-- linked to label by for --> required <!-- required field --> placeholder="name@example.com"> <!-- gray helper text --> <button type="submit">Submit</button> </form>
Customize it
  • Change the type based on the field: text, email, tel, password, number
  • Add required to mandatory fields
  • The placeholder guides, but never replaces the label
My notes
04
HTML · Tableaux
Organize your data in tables
Important
In plain terms: An HTML table is like an Excel spreadsheet. You have rows (<tr>), header cells (<th>) and data cells (<td>). <thead> and <tbody> separate the header from the content, like the frozen first row in a spreadsheet. Use tables for data, never for layout.
<table> <thead> <!-- table header --> <tr> <th>Nom</th> <!-- header cell (bold) --> <th>Prix</th> </tr> </thead> <tbody> <!-- table body --> <tr><td>Widget</td><td>9,90 EUR</td></tr> </tbody> </table>
Customize it
  • Add border-collapse: collapse in CSS to remove double borders
  • Use <caption> to give the table an accessible title
  • Never use <table> to align elements: that's Flexbox or Grid's job
My notes
05
HTML · Multimedia
Integrate images, videos and audio
Important
In plain terms: Each media type has its dedicated tag. <img> for images, <video> for videos, <audio> for audio. It's like plugging the right cable into the right device. The alt attribute on an image is the description for those who can't see it (visually impaired, slow connection). And width/height reserves space to prevent layout shifts during loading.
<!-- Image with description and reserved dimensions --> <img src="photo.webp" alt="Sunset over the sea" width="800" height="450" loading="lazy"> <!-- Video with controls and subtitles --> <video controls width="640"> <source src="demo.mp4" type="video/mp4"> <track src="sous-titres.vtt" kind="subtitles" srclang="fr"> </video>
Customize it
  • Use the WebP format for images (lighter than JPEG/PNG)
  • Add loading="lazy" to images below the fold
  • Always add a descriptive alt, never empty except for decorative images
My notes
06
HTML · Liens
Link your pages together
Essential
In plain terms: Links (<a>) are the doors between rooms on your site. An internal link leads to another page on your site, an external link leads elsewhere on the web. The href attribute is the destination address. And target="_blank" opens the door in a new tab, so the visitor doesn't leave your page.
<!-- Internal link (same site) --> <a href="/contact">Contact us</a> <!-- External link (other site) — secured --> <a href="https://example.com" target="_blank" <!-- new tab --> rel="noopener noreferrer"> <!-- security: prevents access to your page --> Visit site </a> <!-- Anchor (link to a section of the same page) --> <a href="#tarifs">View pricing</a>
Customize it
  • Always add rel="noopener noreferrer" to target="_blank" links
  • Use descriptive link text: "View pricing" rather than "Click here"
  • Anchors (#section) require an id="section" on the target element
My notes
02

CSS — Styling

7 fundamentals for styling and laying out your HTML content

07
CSS · Selecteurs
Target exactly what you want to style
Essential
In plain terms: A CSS selector is your element's postal address. The more precise you are, the better you target the right mailbox. p targets all paragraphs. .intro targets elements with the class "intro". #hero targets the unique element with that ID. You can combine them for pinpoint accuracy.
p { color: gray; } /* all paragraphs */ .intro { font-size: 1.2rem; } /* elements with class="intro" */ #hero { background: #6366f1; } /* the element with id="hero" */ .card h2 { color: navy; } /* h2s inside a .card */ .btn:hover { opacity: 0.8; } /* on mouse hover */ input:focus { outline: 2px solid blue; } /* when the field is active */
Customize it
  • Prefer classes (.nom) over IDs (#nom) for reusability
  • Avoid overly long selectors (div.main ul li a): simpler is better
  • Pseudo-classes :hover, :focus, :first-child avoid adding unnecessary classes
My notes
08
CSS · Box Model
Master the space around each element
Essential
In plain terms: Every HTML element is like a package. There's the content (the item), the padding (bubble wrap around the item), the border (the box), and the margin (space between packages on the shelf). By default, the browser adds padding and border on top of the size. With box-sizing: border-box, everything is included in the size you define.
/* Essential: includes padding and border in the size */ * { box-sizing: border-box; } .carte { width: 300px; /* total width = 300px, period */ padding: 20px; /* inner space (bubble wrap) */ border: 2px solid #ddd; /* border (cardboard) */ margin: 16px; /* outer space (between packages) */ }
Customize it
  • Always put * { box-sizing: border-box; } at the top of your CSS
  • Use padding for inner space, margin for outer space
  • Tip: margin: 0 auto horizontally centers an element with a fixed width
My notes
09
CSS · Flexbox
Align your elements in a line
Essential
In plain terms: Imagine a shelf. You place items on it and decide: push them left, center them, or space them evenly. Flexbox does the same with your HTML elements. You tell the parent "become a shelf" with display: flex, then choose how to distribute children with justify-content (horizontal) and align-items (vertical).
.menu { display: flex; /* activates the shelf */ justify-content: space-between; /* equal space between elements */ align-items: center; /* vertically aligns to center */ gap: 16px; /* fixed space between each element */ } /* Valeurs courantes de justify-content : flex-start | center | flex-end | space-between | space-around */
Customize it
  • Change justify-content: center to center, space-between to space out
  • Add flex-wrap: wrap so elements wrap to the next line when space runs out
  • Use gap instead of margins on children: cleaner and more predictable
My notes
10
CSS · Grid
Create grid-based layouts
Essential
In plain terms: If Flexbox is a shelf (one dimension), Grid is a chessboard (two dimensions). You define columns and rows, then place your elements in the cells. It's like an architect's blueprint: you draw the grid first, then place the furniture. Ideal for complex layouts with header, sidebar, content, and footer.
.page { display: grid; /* 3 columns : the 2nd takes remaining space */ grid-template-columns: 250px 1fr 250px; gap: 20px; /* space between cells */ } /* 1fr = 1 fraction de l'espace restant */ /* repeat(3, 1fr) = 3 columns egales */
Customize it
  • Change the number of columns: repeat(3, 1fr) for 3 equal columns
  • Use minmax(250px, 1fr) for flexible columns with a minimum size
  • For galleries: grid-template-columns: repeat(auto-fill, minmax(200px, 1fr))
My notes
11
CSS · Variables
Centralize your colors and values
Important
In plain terms: Imagine painting an apartment. If you write the color reference on each wall, changing your mind means repainting everything. But if you label a can "primary color" and everyone dips into it, just change the can. CSS variables (--nom) work the same way: one value defined once, used everywhere.
/* We define the "paint cans" once */ :root { --color: #6366f1; /* purple — change here, it changes everywhere */ --text: #1a1a2e; /* text color */ --radius: 12px; /* rounded corners */ --spacing: 16px; /* standard spacing */ } .button { background: var(--color); border-radius: var(--radius); }
Customize it
  • Replace hardcoded values with var(--nom) throughout your CSS
  • Create variables for: colors, spacing, border-radius, shadows
  • For dark mode, redeclare the variables in @media (prefers-color-scheme: dark)
My notes
12
CSS · Transitions
Add movement to your elements
Important
In plain terms: Without transition, a style change is instant: the button is blue, then suddenly it's purple. With transition, you add a fade between two states. It's like a dimmer switch instead of an on/off switch. You choose what changes, how long it takes, and the rhythm (slow at start, fast at end, etc.).
.button { background: #6366f1; color: white; /* transition: what | duration | easing */ transition: background 0.3s ease, transform 0.3s ease; } .button:hover { background: #4f46e5; /* darker purple */ transform: translateY(-2px); /* moves slightly up */ }
Customize it
  • Change the duration: 0.2s for fast, 0.5s for slow and elegant
  • Use ease-out for natural animations (fast at start, slow at end)
  • Only animate transform and opacity for optimal performance
My notes
13
CSS · Responsive
Adapt your design to every screen
Essential
In plain terms: A responsive site is like modular furniture that adapts to the room size. Media queries (@media) are conditional rules: "if the screen is less than 768px, stack the columns." You write the mobile design first (smallest), then add rules for larger screens. That's the "mobile first" principle.
/* Base = mobile (small screen) */ .grille { display: grid; grid-template-columns: 1fr; /* 1 column on mobile */ gap: 16px; } /* Tablet: from 768px */ @media (min-width: 768px) { .grille { grid-template-columns: 1fr 1fr; } /* 2 columns */ } /* Desktop: from 1024px */ @media (min-width: 1024px) { .grille { grid-template-columns: repeat(3, 1fr); } /* 3 columns */ }
Customize it
  • Common breakpoints: 640px (mobile), 768px (tablet), 1024px (desktop)
  • Use min-width (mobile first) rather than max-width
  • Always test in DevTools (F12) by resizing the window
My notes
03

JavaScript — Interactivity

6 fundamentals for making your pages dynamic and interactive

14
JavaScript · Variables
Store and manipulate your data
Essential
In plain terms: A variable is a labeled box. You store a value in it (a name, a number, a list). let creates a modifiable box. const creates a locked box. Types (text, number, boolean) define what the box can hold. Without variables, your program can't remember anything.
const nom = "Alice"; // text (string) — won't change let age = 25; // number — can change let estConnecte = true; // boolean (true/false) const fruits = ["pomme", "poire"]; // array const user = { nom: "Alice", age: 25 }; // object age = 26; // let allows you to change the value console.log(user.nom); // displays "Alice" in the console
Customize it
  • Use const by default, let only if the value needs to change
  • Name your variables clearly: totalPrice rather than x
  • Avoid var: it's the old syntax, less reliable than let/const
My notes
15
JavaScript · DOM
Select and modify your page in real time
Essential
In plain terms: Your HTML page is a tree. Each branch is an element. This tree is called the DOM (Document Object Model — the in-memory version of your page). JavaScript can shake this tree: add branches, cut some, change leaves. That's DOM manipulation. You select an element with querySelector, then modify its text, style, or attributes. Everything happens live, without reloading the page.
// Select an element const titre = document.querySelector('.titre'); // by class const btn = document.querySelector('#valider'); // by ID // Modify content and style titre.textContent = "Nouveau titre"; // changes the text titre.style.color = "#6366f1"; // changes the color titre.classList.add("visible"); // adds a CSS class
Customize it
  • Prefer querySelector (CSS selector) over getElementById
  • Use textContent (secure) instead of innerHTML (XSS risk)
  • Manipulate classes with classList.add/remove/toggle instead of inline styles
My notes
16
JavaScript · Events
React to user actions
Essential
In plain terms: An event is something that happens: a click, a key press, a scroll. addEventListener tells JavaScript: "when this happens, execute this action." It's like a motion detector: you place it, and it reacts automatically when someone passes by. Without events, your page is a static poster.
const btn = document.querySelector('#submit'); // Listen for button click btn.addEventListener('click', () => { alert('Form submitted!'); // action triggered on click }); // Listen for a keyboard key (on the whole page) document.addEventListener('keydown', (e) => { console.log('Key:', e.key); // displays the pressed key });
Customize it
  • Common events: click, submit, input, keydown, scroll
  • Use addEventListener (clean) instead of onclick in HTML
  • Add e.preventDefault() to prevent the default behavior (e.g., form submission)
My notes
17
JavaScript · Fetch/API
Exchange data with a server
Important
In plain terms: fetch is your site's mailman. It goes to get data from a server via an API (a data counter on a server) and brings it back. The response arrives in JSON format: structured text that JavaScript natively understands. That's how your site displays the weather, loads articles, or sends a form without reloading the page.
// Retrieve data from an API const response = await fetch('https://api.exemple.fr/users'); const users = await response.json(); // converts JSON to JS object console.log(users); // [{nom: "Alice"}, ...] // Send data (POST) await fetch('/api/contact', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ nom: "Alice" }) // object JS → texte JSON });
Customize it
  • Always check response.ok before reading data (error handling)
  • Use async/await (readable) instead of .then() (chaining)
  • Test your APIs with DevTools (Network tab) to see requests
My notes
18
JavaScript · localStorage
Save data in the browser
Useful
In plain terms: It's a drawer in the browser. You store info in it (dark theme, cart, preferences). It persists even after closing the browser. Unlike cookies, this data never goes to the server. It's local storage, simple and free. Perfect for remembering visitor choices without a database.
// Save a value localStorage.setItem('theme', 'sombre'); // key → value (text) // Read a value const theme = localStorage.getItem('theme'); // returns "dark" // Store an object (convert to JSON first) const prefs = { theme: 'sombre', lang: 'fr' }; localStorage.setItem('prefs', JSON.stringify(prefs)); // Relire l'object const saved = JSON.parse(localStorage.getItem('prefs'));
Customize it
  • Limit: ~5 MB per domain. Don't store heavy files
  • Use sessionStorage if you want data to disappear when the tab closes
  • Never store passwords or sensitive tokens in localStorage
My notes
19
JavaScript · ES6+
Write modern, readable JavaScript
Important
In plain terms: ES6 is the modern version of JavaScript (released in 2015). Before, code was verbose and hard to read. Arrow functions (=>) shorten functions. Destructuring extracts values from an object in one line. Template literals (`...`) let you insert variables into text. It's cleaner, shorter, more readable.
// Arrow function (instead of function) const saluer = (nom) => `Salut ${nom} !`; // template literal // Destructuring: extract values const { nom, age } = user; // instead of user.nom, user.age // Spread: merge objects/arrays const newUser = { ...user, role: "admin" }; // copy + add // Optional chaining: avoid errors const ville = user?.adresse?.ville; // undefined if missing
Customize it
  • Adopt arrows => for short callbacks (map, filter, forEach)
  • Use backticks `text ${variable}` instead of concatenation +
  • ?. (optional chaining) prevents crashes when data is missing
My notes
04

Responsive & Mobile — Adaptation

6 fundamentals for making your site display perfectly on all screens

20
Responsive · Viewport
Configure the mobile viewport
Essential
In plain terms: The viewport is the visible screen size. Without this meta tag, mobile displays your page as a miniature desktop version. Unreadable. This single line tells the browser: "adapt the width to the phone screen." It's the very first thing to put in the <head> of every page. Without it, no responsive design works.
<!-- In the <head> of EVERY HTML page --> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- width=device-width → width = real screen --> <!-- initial-scale=1.0 → no initial zoom --> <!-- WITHOUT this tag: mobile displays 980px wide --> <!-- WITH this tag: mobile displays 375px (its real size) -->
Customize it
  • Never add maximum-scale=1: it prevents accessibility zoom
  • Place this tag right after <meta charset="UTF-8">
  • Check in DevTools (responsive mode) that your page adapts properly
My notes
21
Responsive · Mobile-first
Design mobile-first
Essential
In plain terms: Mobile-first means building your house starting with the studio apartment. You design for the smallest screen first (mobile), then add space and columns for larger screens. It's simpler than the reverse: adding is easy, removing is painful. And 60% of web traffic is mobile today.
/* Base CSS = mobile (no media query) */ .container { padding: 16px; font-size: 14px; /* readable size on small screen */ } /* We ADD rules for larger screens */ @media (min-width: 768px) { /* tablet and up */ .container { max-width: 720px; margin: 0 auto; } }
Customize it
  • Always write mobile CSS first (outside media queries)
  • Use min-width to progressively add (not max-width)
  • Test by shrinking the window: if it breaks, it's not mobile-first
My notes
22
Responsive · Breakpoints
Define your breakpoints
Important
In plain terms: A breakpoint is the screen size where your design changes shape. Like a folding door: from a certain width, it unfolds. You don't need 15 breakpoints. Three are enough: mobile, tablet, desktop. Choose them based on your content, not a specific phone model.
/* 3 breakpoints are enough for 95% of sites */ /* Mobile: 0 - 639px (no media query = base CSS) */ /* Tablet: from 640px */ @media (min-width: 640px) { .grid { grid-template-columns: 1fr 1fr; } } /* Desktop: from 1024px */ @media (min-width: 1024px) { .grid { grid-template-columns: repeat(3, 1fr); } }
Customize it
  • Classic breakpoints: 640px, 768px, 1024px, 1280px
  • Add a breakpoint only when the content requires it (not systematically)
  • Use DevTools to find where your design "breaks" naturally
My notes
23
Responsive · Images
Adapt your images to every screen
Important
In plain terms: Sending a 4K image to a phone is like delivering a couch by helicopter. It works, but it's wasteful. srcset gives the browser a list of sizes. It picks the best one for the screen. WebP format is 30% lighter than JPEG. Result: faster pages, especially on 4G.
<!-- The browser chooses the image based on screen width --> <img src="photo-800.webp" srcset="photo-400.webp 400w, photo-800.webp 800w, photo-1200.webp 1200w" sizes="(max-width: 640px) 100vw, 50vw" alt="Photo description" loading="lazy"> <!-- loads the image only when visible -->
Customize it
  • Generate 3 sizes per image: 400px, 800px, 1200px wide
  • Use WebP (or AVIF) format for 30-50% lighter files
  • Add loading="lazy" to all images below the fold
My notes
24
Responsive · Touch
Make your touch buttons comfortable
Useful
In plain terms: On a phone, you tap with your finger, not with a pixel-precise mouse cursor. A 20px button is too small: you miss one out of two. The rule: minimum 44x44 pixels for every clickable area. That's the size of a fingertip. Also think about spacing between buttons to avoid accidental taps.
/* Minimum recommended size for touch */ .btn { min-height: 44px; /* Apple/Google standard */ min-width: 44px; padding: 12px 24px; /* comfortable area */ } /* Spacing between buttons to avoid errors */ .btn + .btn { margin-left: 12px; /* space between two buttons */ }
Customize it
  • Minimum 44px for links, buttons, checkboxes, and clickable icons
  • Add padding rather than margin to enlarge the click area
  • Test on a real phone: if you miss the button, it's too small
My notes
25
Responsive · Testing
Test on real devices
Essential
In plain terms: DevTools' responsive mode is a simulation. Not reality. A real phone has a different screen, different browser, different bandwidth. If you don't test on a real device, you'll discover bugs in production. Test at minimum on an iPhone and an Android. Use your phone's Wi-Fi to see your local site.
<!-- 1. Find your computer's local IP --> <!-- Mac : ifconfig | grep "inet " --> <!-- Windows : ipconfig | findstr IPv4 --> <!-- 2. Start a local server --> <!-- python3 -m http.server 8080 --> <!-- 3. On your phone (same Wi-Fi), open: --> <!-- http://192.168.1.42:8080 --> <!-- 4. Test: scroll, tap, forms, rotation -->
Customize it
  • Test on at least 3 devices: small phone, large phone, tablet
  • Check rotation (portrait/landscape) on each device
  • Use BrowserStack or LambdaTest if you don't have multiple devices
My notes
05

Accessibility — Inclusion

6 fundamentals for making your site usable by everyone

26
Accessibility · Semantic HTML
Make your page readable by everyone
Essential
In plain terms: A screen reader doesn't see your page. It reads it. If you use <div> everywhere, it doesn't know where the menu is, where the content is. Semantic tags (<nav>, <main>, <button>) are signposts for blind users, visually impaired users, and bots. A <button> is keyboard-clickable. A <div> is not.
<!-- BAD: all divs, nothing is accessible --> <div onclick="menu()">Menu</div> <div class="title">My article</div> <!-- GOOD: semantic tags, natively accessible --> <button type="button">Menu</button> <!-- focusable + keyboard-activable --> <h1>My article</h1> <!-- recognized as main heading --> <nav aria-label="Main menu"> <!-- identifies navigation --> <a href="/home">Home</a> </nav>
Customize it
  • Replace every <div onclick> with a real <button>
  • Structure your headings hierarchically: h1 > h2 > h3 (don't skip levels)
  • Add aria-label to <nav> when you have multiple ones
My notes
27
Accessibility · ARIA
Enhance accessibility with ARIA
Important
In plain terms: ARIA is a translator for screen readers. When HTML alone isn't enough (a menu that opens, an active tab, a loading spinner), ARIA adds invisible information. aria-expanded tells if a menu is open or closed. role="alert" announces an important message. But the golden rule: if a native HTML tag is enough, use it. ARIA is a complement, not a replacement.
<!-- Dropdown menu: indicate open/closed state --> <button aria-expanded="false" aria-controls="menu">Menu</button> <ul id="menu" hidden>...</ul> <!-- Alert message announced automatically --> <div role="alert">Error: invalid email</div> <!-- Loading zone --> <div aria-busy="true" aria-live="polite"> Loading... </div>
Customize it
  • First ARIA rule: only use ARIA if native HTML isn't enough
  • Update aria-expanded in JavaScript when the menu opens/closes
  • Use aria-live="polite" for dynamically changing areas
My notes
28
Accessibility · WCAG Contrast
Choose readable colors
Essential
In plain terms: Imagine reading light gray text on a white background in bright sunlight. Impossible. The 4.5:1 ratio guarantees everyone can read, even in poor conditions. This ratio compares text brightness with background brightness. Tools calculate it for you. If it's below 4.5, change your color. It's a legal requirement in many countries.
/* BAD contrast: light gray on white (ratio ~2:1) */ .texte-illisible { color: #b0b0b0; /* too light on white background */ background: #ffffff; } /* GOOD contrast: ratio 7:1+ (AAA level) */ .texte-lisible { color: #1a1a2e; /* dark on light background */ background: #ffffff; /* ratio 15.4:1 */ }
Customize it
  • Normal text: minimum ratio 4.5:1 (AA). Large text (18px+): 3:1
  • Free tool: webaim.org/resources/contrastchecker
  • Also check buttons, links, and placeholders (often too light)
My notes
29
Accessibility · Keyboard
Make everything keyboard accessible
Essential
In plain terms: Some people don't use a mouse. They navigate with Tab (next element), Shift+Tab (previous) and Enter (activate). If your site only works with a mouse, you're excluding these users. Visible focus (the blue outline) is essential: it's the keyboard version of the cursor arrow. Never hide it. If you create a clickable element, it must be focusable.
/* NEVER: don't hide visible focus */ *:focus { outline: none; } /* forbidden! */ /* GOOD: customize it nicely */ :focus-visible { outline: 2px solid #6366f1; /* visible and aesthetic */ outline-offset: 2px; /* small gap around */ } /* :focus-visible = keyboard only (not on mouse click) */
Customize it
  • Test by navigating with Tab: every interactive element should receive focus
  • Use :focus-visible (not :focus) to target keyboard navigation only
  • Add tabindex="0" to custom clickable elements (if you can't use <button>)
My notes
30
Accessibility · Screen readers
Communicate with screen readers
Important
In plain terms: A screen reader (VoiceOver, NVDA) reads your page aloud. It announces headings, links, buttons, images. If an image has no alt, it just says "image" with no explanation. If a button has no text, it just says "button." Every interactive element must have a name that makes sense when heard. Think: "does this make sense if I hear it without seeing it?"
<!-- Informative image: describe the content --> <img src="graph.png" alt="Sales up 25% in March"> <!-- Decorative image: empty alt (reader ignores it) --> <img src="deco.svg" alt=""> <!-- Button with icon only: aria-label required --> <button aria-label="Close">&times;</button> <!-- Content visible only to screen readers --> <span class="sr-only">Open menu</span>
Customize it
  • Every <img> must have an alt: descriptive (informative) or empty (decorative)
  • Test with VoiceOver (Mac: Cmd+F5) or NVDA (Windows, free)
  • The .sr-only class hides visually but remains readable by screen readers
My notes
31
Accessibility · Preferences
Respect user preferences
Useful
In plain terms: Your visitor may have enabled dark mode, reduced animations, or enlarged text in their system settings. CSS can detect these preferences and adapt automatically. prefers-color-scheme detects dark mode. prefers-reduced-motion detects people sensitive to animations. Respecting these choices is digital courtesy.
/* Detect system dark mode */ @media (prefers-color-scheme: dark) { body { background: #0a0a0f; color: #e4e4e7; } } /* Reduce animations if the user requests it */ @media (prefers-reduced-motion: reduce) { * { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; } }
Customize it
  • Use CSS variables (--bg, --text) to switch colors easily
  • Test: Mac > Settings > Appearance > Dark. Windows > Settings > Colors
  • Add prefers-contrast: high for users who force high contrast
My notes
06

SEO & Performance — Visibility

6 fundamentals for getting found by Google and loading fast

32
SEO · Meta tags
Help Google understand your page
Essential
In plain terms: Google doesn't see your page like you do. It reads the source code. Meta tags are your ID card for search engines. The <title> is the name on your mailbox. The meta description is the note stuck on it. Without them, Google makes up a summary on its own. And it's rarely pretty.
<head> <!-- Title: 50-60 characters, main keyword first --> <title>Recettes faciles | MonSite</title> <!-- Description: 150-160 characters, makes you want to click --> <meta name="description" content="Decouvre 50 recettes faciles a preparer en 15 min."> <!-- Indicates the official URL (avoids duplicate content) --> <link rel="canonical" href="https://monsite.fr/recettes"> </head>
Customize it
  • Every page must have a unique <title> and meta description
  • Place your main keyword at the beginning of the title, not the end
  • Add Open Graph tags (og:title, og:image) for a nice preview on social media
My notes
33
SEO · Headings
Structure your headings logically
Essential
In plain terms: H1 to H6 headings are your page's table of contents. Google reads it to understand the topic. One H1 per page (the main title). Then H2s for sections, H3s for subsections. Like a book: one cover title, multiple chapters, multiple paragraphs per chapter. Never skip levels (no H1 then H4).
<!-- GOOD: logical hierarchy, one H1 --> <h1>Gardening guide</h1> <!-- unique title --> <h2>Essential tools</h2> <!-- section --> <h3>Pruning shears</h3> <!-- subsection --> <h3>The spade</h3> <!-- subsection --> <h2>Planter ses legumes</h2> <!-- new section --> <!-- BAD: duplicate H1, skipped levels --> <h1>Jardinage</h1> <h1>Outils</h1> <h4>Beche</h4>
Customize it
  • One <h1> per page. It's the main title, not the logo
  • Don't choose a heading level for text size. Use CSS for that
  • Check your hierarchy with the "HeadingsMap" Chrome extension
My notes
34
SEO · Core Web Vitals
Get a good performance score
Essential
In plain terms: Google measures 3 things on your page. LCP: how long before the largest element appears (your hero image, for example). FID: how long before the site responds to the first click. CLS: does the page shift by itself during loading. It's like a restaurant: the dish arrives fast (LCP), the waiter responds fast (FID), and the table doesn't move (CLS).
<!-- LCP: load the main image with priority --> <img src="hero.webp" fetchpriority="high" alt="Hero"> <!-- CLS: reserve space for images --> <img src="photo.webp" width="800" height="450" alt="Photo"> <!-- FID: load heavy JS deferred --> <script src="app.js" defer></script> /* Objectifs : LCP < 2.5s | FID < 100ms | CLS < 0.1 */
Customize it
  • Test with PageSpeed Insights (web.dev/measure) to see your scores
  • Add width and height to all your images to prevent layout shifts (CLS)
  • Put defer on all your non-critical scripts
My notes
35
SEO · Image optimization
Speed up your image loading
Essential
In plain terms: A 5 MB image is like sending a 10 kg package by mail for a 200 g item. WebP format compresses better than JPEG (30% lighter). Lazy loading tells the browser: "load this image only when the visitor reaches it." Less weight = faster page = happier visitors = happier Google.
<!-- Lazy loading: loads the image when it enters the viewport --> <img src="photo.webp" loading="lazy" alt="Paysage"> <!-- Modern format with JPEG fallback --> <picture> <source srcset="photo.avif" type="image/avif"> <source srcset="photo.webp" type="image/webp"> <img src="photo.jpg" alt="Paysage"> </picture>
Customize it
  • Convert all your images to WebP with Squoosh (squoosh.app, free)
  • Put loading="lazy" on all images except those visible on first screen
  • Resize before uploading: you don't need a 4000px image for an 800px display
My notes
36
SEO · Preload/Prefetch
Preload the right resources
Important
In plain terms: Imagine preparing a meal. You take out ingredients from the fridge before cooking, not at the last minute. preload tells the browser: "this resource is urgent, download it right away." prefetch says: "the visitor will probably go to this page next, prepare it in the background." Good timing makes all the difference.
<head> <!-- Preload: loads the font BEFORE it is used --> <link rel="preload" href="font.woff2" as="font" type="font/woff2" crossorigin> <!-- Prefetch: prepares the next page in the background --> <link rel="prefetch" href="/page-suivante.html"> <!-- Preconnect: opens connection to external server --> <link rel="preconnect" href="https://fonts.googleapis.com"> </head>
Customize it
  • Use preload for the main font and hero image (LCP)
  • Use preconnect for external domains (Google Fonts, API, CDN)
  • Don't overuse: too many preloads slow things down instead of speeding up (3-4 max)
My notes
37
SEO · Minification
Reduce your code weight
Important
In plain terms: Your CSS and JS code contains spaces, line breaks, comments. Useful for you, but unnecessary for the browser. Minification removes all of that. It's like compressing a suitcase: same content, less space. Result: lighter files, faster download, happier visitors.
/* BEFORE minification (readable, 120 bytes) */ .btn { background: #6366f1; padding: 12px 24px; border-radius: 8px; } /* AFTER minification (unreadable, 52 bytes) */ .btn{background:#6366f1;padding:12px 24px;border-radius:8px}
Customize it
  • Use cssnano (CSS) and Terser (JS) to minify automatically
  • Always keep the original file (style.css) and the minified file (style.min.css)
  • In production, link the .min.css file. In dev, the normal file
My notes
07

Tools & Workflow — Productivity

5 fundamentals for working fast, well, and stress-free

38
Tools · VS Code
Configure your code editor
Essential
In plain terms: A code editor is your workshop. VS Code is free, lightweight, and ultra-popular. It colors your code, completes your tags, detects errors in real time. It's the difference between writing by hand on blank paper and writing with a pen that corrects spelling. Install the right extensions and you save hours every week.
// Essential extensions for VS Code: // 1. Live Server — reloads the page on every save // 2. Prettier — formats your code automatically // 3. ESLint — detects JavaScript errors // 4. Auto Rename Tag — renames the closing tag // Magic shortcut: Ctrl+Shift+P (command palette) // Type "format" to format your file in 1 second
Customize it
  • Enable "Format on Save" in settings (no need to think about it)
  • Type ! then Tab in an HTML file: VS Code generates the complete skeleton
  • Use Emmet: ul>li*5 + Tab creates a list of 5 items at once
My notes
39
Tools · Git
Save every version of your code
Essential
In plain terms: Git is a supercharged Ctrl+Z for your project. Each "commit" is a snapshot of your code at a moment in time. You can go back, compare versions, work with others without overwriting each other's work. Without Git, a file deleted by mistake is lost forever. With Git, you travel back in time with one command.
# Initialize Git in your project git init # Add all modified files git add . # Save with a clear message git commit -m "Added contact page" # View your save history git log --oneline
Customize it
  • Make a commit at each functional milestone ("contact page OK", "mobile menu OK")
  • Use GitHub (free) to store your code online (cloud backup)
  • VS Code integrates Git: you can commit, push, and view diffs without leaving the editor
My notes
40
Tools · DevTools
Inspect and debug in the browser
Essential
In plain terms: DevTools is an X-ray for your web page. You see the bones (HTML), the clothes (CSS), the reflexes (JS). You click an element, you see its code, styles, margins. You modify live to test. Nothing is saved: it's a sandbox. All browsers have it. Shortcut: F12 or right-click > Inspect.
/* Essential DevTools tabs */ // Elements: view and modify HTML/CSS live // Console: display JS errors and test code // Network: see every downloaded file (size, time) // Lighthouse: run a full audit (perf, SEO, a11y) // Tip: in Console, type document.title // to display the current page title
Customize it
  • Shortcut: Ctrl+Shift+C (Windows) or Cmd+Shift+C (Mac) to inspect an element
  • Network tab > check "Disable cache" during dev (avoids stale files)
  • Use Responsive mode (smartphone icon) to simulate a mobile without having one
My notes
41
Tools · Deployment
Put your site online for free
Important
In plain terms: Your site works on your computer. Great. But nobody else can see it. Deployment is moving your site from your PC to a server accessible to all. Free services like Netlify or Vercel do it in 2 minutes. You connect your GitHub repo, and on every push, the site updates automatically. Zero config, zero stress.
# Method 1: Netlify (drag and drop) # → Go to app.netlify.com # → Drag your project folder onto the page # → Your site is online in 30 seconds # Method 2: Vercel (via GitHub) # → Connect your GitHub repo on vercel.com # → Every git push updates the site # → Free URL: myproject.vercel.app
Customize it
  • Netlify : ideal for static sites (HTML/CSS/JS). Drop & deploy
  • Vercel : ideal if you use a framework (Next.js, SvelteKit)
  • GitHub Pages : also free, perfect for a portfolio or documentation
My notes
42
Tools · Domain/Hosting
Choose your domain name and hosting
Useful
In plain terms: A domain name is your house address (mysite.com). Hosting is the land your house is built on. Without a domain, people type a cryptic IP. Without hosting, your house doesn't exist anywhere. A domain costs 5-15 euros/year. Basic hosting, 3-5 euros/month. It's the price of a coffee to be visible on the Internet.
/* Choosing a good domain name */ // Short: mysite.com (not my-super-recipes-site-2026.com) // Memorable: easy to spell over the phone // Extension: .fr for France, .com for international /* Recommended hosts (beginner) */ // OVH — French, domain + hosting, ~3 EUR/mois // Hostinger — affordable, simple interface, ~2 EUR/mois // Infomaniak — Swiss, eco-friendly, good support
Customize it
  • Check your domain availability on namecheap.com or ovh.com
  • Get the .fr AND .com if possible (prevents someone else from taking it)
  • Free hosting (Netlify, Vercel) is enough to start. Switch to paid when you have traffic
My notes
08

Web Security — Protection

6 fundamentals for protecting your site and visitors from attacks

43
Security · HTTPS/SSL
Encrypt exchanges with HTTPS
Essential
In plain terms: It's the padlock in your address bar. Without it, everything your visitor types (password, email) travels in plain text over the network. Like a postcard everyone can read. With HTTPS, data is encrypted: even if someone intercepts the message, they only see gibberish. Google penalizes sites without HTTPS. Browsers display "Not secure."
<!-- Force HTTPS in HTML --> <meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests"> # Force HTTPS in .htaccess (Apache) RewriteEngine On RewriteCond %{HTTPS} off RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301] # Free certificate: Let's Encrypt (automatic)
Customize it
  • Most hosts offer a free SSL certificate (Let's Encrypt)
  • Make sure ALL your resources (images, scripts) are also served over HTTPS
  • Test with SSL Labs (ssllabs.com) to verify your certificate is correct
My notes
44
Security · CSP
Control what your page can load
Important
In plain terms: It's the guest list for your party. Only authorized scripts can enter. Others are blocked at the door. CSP (Content Security Policy) tells the browser: "accept scripts from my domain and Google Fonts, but block everything else." If a hacker injects a malicious script, the browser refuses it because it's not on the list.
<!-- CSP in HTML (meta tag) --> <meta http-equiv="Content-Security-Policy" content=" default-src 'self'; script-src 'self' https://cdn.exemple.com; style-src 'self' https://fonts.googleapis.com; img-src 'self' data: https://stats.optimetier.fr https:; font-src 'self' https://fonts.gstatic.com; ">
Customize it
  • 'self' = your own domain. Add the external CDNs you use
  • Start strict, then allow case by case (better than opening everything)
  • Test with the Console tab in DevTools: CSP violations are displayed there
My notes
45
Security · XSS
Prevent malicious code injection
Essential
In plain terms: Imagine someone sticking a fake sign on your storefront. Visitors believe it's real. XSS is the same: fake code injected into your page. A hacker writes JavaScript in a form field. If you display that text as-is, the code executes for all visitors. It can steal cookies, redirect to a fake site, or display misleading content.
// DANGER: injecting raw text into HTML element.innerHTML = texteUtilisateur; // XSS possible! // SECURE: use textContent (no HTML interpreted) element.textContent = texteUtilisateur; // If you must display HTML, escape the characters function escape(str) { return str.replace(/&/g, '&amp;') .replace(/</g, '&lt;') .replace(/>/g, '&gt;'); }
Customize it
  • Golden rule: never use innerHTML with user data
  • Prefer textContent (plain text) or createElement (clean DOM)
  • Server-side too: escape with htmlspecialchars() in PHP
My notes
46
Security · CSRF
Protect your forms against fake submissions
Important
In plain terms: Imagine a trap site sends a form to your bank on your behalf, without you knowing. CSRF (Cross-Site Request Forgery) is exactly that: a fake order sent with your credentials. The solution: a unique, secret token in every form. The server verifies the token is valid. If someone submits the form from another site, they don't have the token. Request denied.
<!-- The server generates a unique token per session --> <form method="POST" action="/transfert"> <input type="hidden" name="csrf_token" value="a8f3b9e1c7d2..."> <input type="text" name="montant"> <button type="submit">Submit</button> </form> <!-- The server verifies: received token == session token -->
Customize it
  • Generate a random token for each session (never the same twice)
  • Also check the Origin header to confirm the request comes from your site
  • Modern frameworks (Laravel, Django, Express) handle CSRF automatically
My notes
47
Security · Sanitization
Never trust user data
Essential
In plain terms: Every form field is an entry point. A visitor can type anything: code, commands, weird characters. Sanitization is the guard searching bags at the entrance. You clean every piece of data before using it. You strip HTML tags, limit length, verify the format. Client-side AND server-side. Always both.
// Client-side: validate BEFORE sending const email = input.value.trim(); if (!email.includes('@')) { alert('Invalid email'); } // Server-side (PHP): ALWAYS re-verify $email = filter_var($_POST['email'], FILTER_SANITIZE_EMAIL); $nom = htmlspecialchars($_POST['nom'], ENT_QUOTES); // strip_tags() removes all HTML tags
Customize it
  • Client-side validation is for comfort. Server-side validation is for security
  • Use HTML attributes: type="email", required, maxlength, pattern
  • Never make SQL queries with raw data. Use prepared statements
My notes
48
Security · Security headers
Add browser-side shields
Important
In plain terms: Security headers are instructions your server gives to the browser. "Don't embed my page in an iframe" (clickjacking). "Don't send the full referrer" (privacy). "Force HTTPS for 1 year" (HSTS). It's like putting an alarm, a lock, and a camera on your house. Each header blocks a specific type of attack.
# Security headers (.htaccess Apache) # Prevents display in an iframe (anti-clickjacking) Header set X-Frame-Options "DENY" # Forces HTTPS for 1 year Header set Strict-Transport-Security "max-age=31536000" # Prevents MIME type sniffing Header set X-Content-Type-Options "nosniff" # Limits info sent to other sites Header set Referrer-Policy "strict-origin-when-cross-origin"
Customize it
  • Test your headers on securityheaders.com (goal: A or A+ grade)
  • Add Permissions-Policy to block camera, microphone, geolocation if you don't need them
  • Combine with CSP (topic 44) for maximum protection
My notes

Checklist before publishing

Check each item before putting your site online. 48 fundamentals summarized in 48 checkboxes.

01 — HTML
02 — CSS
03 — JavaScript
04 — Responsive
05 — Accessibility
06 — SEO & Performance
07 — Tools
08 — Security

Thanks for downloading
this guide!

You now have the 48 fundamentals for building solid, fast, and secure websites. Here is a summary of the 8 chapters:

# Chapter Topics
01HTML — Structure01-06
02CSS — Styling07-13
03JavaScript — Interactivity14-19
04Responsive — Adaptation20-25
05Accessibility — Inclusion26-31
06SEO & Performance — Visibility32-37
07Tools & Workflow — Productivity38-42
08Web Security — Protection43-48
Discover Effect.Labs — 664 effects | 26 templates | 20 categories

Premium CSS & JS effects library to speed up your web projects

Effect.Labs — 2026 — All rights reserved

This guide is free. Share it freely.