Go beyond the basics — master SEO metadata, script loading strategies, native dialogs, Web Components, SVG, responsive images, and browser security.
1<head>2 <!-- Core SEO -->3 <title>Learn HTML5 | Skill-Forge (55 chars max)</title>4 <meta name="description" content="Master HTML5 from basics to advanced techniques with real code examples. Free and open source." />5 <link rel="canonical" href="https://skill-forge.dev/notes/html" />6 7 <!-- Open Graph -->8 <meta property="og:title" content="Learn HTML5 | Skill-Forge" />9 <meta property="og:description" content="Master HTML5 with real code examples." />10 <meta property="og:image" content="https://skill-forge.dev/og-html.png" />11 <meta property="og:url" content="https://skill-forge.dev/notes/html" />12 <meta property="og:type" content="article" />13 14 <!-- Twitter Card -->15 <meta name="twitter:card" content="summary_large_image" />16 <meta name="twitter:title" content="Learn HTML5 | Skill-Forge" />17 18 <!-- Resource Hints -->19 <link rel="preconnect" href="https://fonts.googleapis.com" />20 <link rel="preload" href="/fonts/inter.woff2" as="font" type="font/woff2" crossorigin />21 <link rel="prefetch" href="/notes/css" />22</head>1<!-- ❌ Blocking — freezes the parser -->2<script src="app.js"></script>3 4<!-- ✅ async — parallel fetch, runs immediately when ready -->5<!-- Use for: analytics, ads, independent widgets -->6<script async src="analytics.js"></script>7 8<!-- ✅ defer — parallel fetch, runs after DOM is parsed, in order -->9<!-- Use for: your main application scripts -->10<script defer src="app.js"></script>11<script defer src="components.js"></script> <!-- runs after app.js -->12 13<!-- ✅ module — auto-deferred, supports import/export -->14<script type="module">15 import { initApp } from './app.js';16 initApp();17</script>1<form>2 <!-- Colour picker -->3 <label for="theme">Theme colour</label>4 <input type="color" id="theme" name="theme" value="#e34f26" />5 6 <!-- Range with live output -->7 <label for="vol">8 Volume: <output for="vol" id="volOut">50</output>9 </label>10 <input type="range" id="vol" name="vol" min="0" max="100" value="50"11 oninput="volOut.value = this.value" />12 13 <!-- Date + time picker -->14 <label for="meeting">Schedule meeting</label>15 <input type="datetime-local" id="meeting" name="meeting" />16 17 <!-- Autocomplete with datalist -->18 <label for="lang">Language</label>19 <input type="text" id="lang" name="lang" list="langs" />20 <datalist id="langs">21 <option value="HTML5" />22 <option value="CSS3" />23 <option value="JavaScript" />24 <option value="TypeScript" />25 </datalist>26 27 <!-- Multi-file upload -->28 <label for="files">Upload files</label>29 <input type="file" id="files" name="files" multiple accept=".pdf,.docx" />30</form>1<button onclick="confirmDialog.showModal()">Delete Account</button>2 3<dialog id="confirmDialog">4 <h2>Confirm Deletion</h2>5 <p>This action is irreversible. Are you sure?</p>6 7 <!-- method="dialog" closes the dialog on submit -->8 <!-- button value becomes dialog.returnValue -->9 <form method="dialog">10 <button value="cancel">Cancel</button>11 <button value="confirm">Yes, delete</button>12 </form>13</dialog>14 15<script>16 confirmDialog.addEventListener('close', () => {17 if (confirmDialog.returnValue === 'confirm') {18 console.log('User confirmed deletion');19 }20 });21</script>1<!-- 1. Define the template -->2<template id="badge-template">3 <style>4 :host { display: inline-block; }5 .badge {6 padding: 4px 12px;7 border-radius: 999px;8 background: #e34f26;9 color: white;10 font-size: 0.75rem;11 }12 </style>13 <span class="badge"><slot>Badge</slot></span>14</template>15 16<!-- 2. Use the custom element -->17<skill-badge>HTML5</skill-badge>18<skill-badge>Advanced</skill-badge>19 20<!-- 3. Register the custom element -->21<script>22 class SkillBadge extends HTMLElement {23 constructor() {24 super();25 const shadow = this.attachShadow({ mode: 'open' });26 const tpl = document.getElementById('badge-template');27 shadow.appendChild(tpl.content.cloneNode(true));28 }29 }30 customElements.define('skill-badge', SkillBadge);31</script>1<!-- SVG — inline in HTML, CSS styleable -->2<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg">3 <circle cx="50" cy="50" r="40" fill="#e34f26" />4 <text x="50" y="55" text-anchor="middle" fill="white" font-size="14">5 HTML6 </text>7</svg>8 9<!-- Canvas — JavaScript draws the pixels -->10<canvas id="myCanvas" width="200" height="100"></canvas>11<script>12 const canvas = document.getElementById('myCanvas');13 const ctx = canvas.getContext('2d');14 15 // Draw a filled rectangle16 ctx.fillStyle = '#3b82f6';17 ctx.fillRect(10, 10, 180, 80);18 19 // Draw text20 ctx.fillStyle = 'white';21 ctx.font = '20px Arial';22 ctx.fillText('Canvas!', 60, 55);23</script>1<!-- Art direction: different images at different breakpoints -->2<picture>3 <source media="(min-width: 1024px)" srcset="hero-desktop.webp" />4 <source media="(min-width: 600px)" srcset="hero-tablet.webp" />5 <img src="hero-mobile.jpg" alt="Team working together" loading="lazy" />6</picture>7 8<!-- Responsive images with srcset -->9<img10 src="photo-400.jpg"11 srcset="photo-400.jpg 400w, photo-800.jpg 800w, photo-1200.jpg 1200w"12 sizes="(max-width: 600px) 100vw, 50vw"13 alt="Mountain landscape"14 loading="lazy"15/>16 17<!-- Sandboxed YouTube embed -->18<iframe19 width="560"20 height="315"21 src="https://www.youtube.com/embed/VIDEO_ID"22 title="HTML5 Tutorial"23 loading="lazy"24 sandbox="allow-scripts allow-same-origin allow-presentation"25 referrerpolicy="strict-origin-when-cross-origin"26 allowfullscreen27></iframe>1<!-- contenteditable — make any element editable -->2<div contenteditable="true" style="border: 1px solid #ccc; padding: 8px;">3 Click here to edit this content directly.4</div>5 6<!-- data-* attributes -->7<button8 data-user-id="42"9 data-action="delete"10 onclick="handleClick(this)"11>12 Delete User13</button>14 15<script>16 function handleClick(btn) {17 const userId = btn.dataset.userId; // "42"18 const action = btn.dataset.action; // "delete"19 console.log(`${action} user ${userId}`);20 }21</script>22 23<!-- tabindex for custom focus order -->24<div tabindex="0" role="button" onkeydown="if(event.key==='Enter')this.click()">25 Keyboard-accessible div26</div>1<!-- CSP via meta tag (fallback — use HTTP header in production) -->2<meta3 http-equiv="Content-Security-Policy"4 content="default-src 'self';5 script-src 'self';6 style-src 'self' 'unsafe-inline';7 img-src https://* data:;8 font-src 'self' https://fonts.gstatic.com;9 connect-src 'self' https://api.skill-forge.dev"10/>11 12<!-- ❌ XSS vulnerability -->13<script>14 // NEVER do this with user input!15 document.getElementById('output').innerHTML = location.search;16</script>17 18<!-- ✅ Safe alternative -->19<script>20 // Use textContent — it never executes HTML/scripts21 document.getElementById('output').textContent = location.search;22 23 // OR sanitise HTML before injection24 // import DOMPurify from 'dompurify';25 // el.innerHTML = DOMPurify.sanitize(userHtml);26</script>