Skip to content

HTML Spickzettel

Die Standard-Markup-Sprache zum Erstellen von Webseiten.

01

Dokumentstruktur

Basis-Seiten-Template

Jedes HTML5-Dokument startet mit <!DOCTYPE html>, gefolgt von <html> mit einem lang-Attribut für Accessibility und SEO. Der <head> enthält Metadaten (charset, viewport, title), und <body> hält sichtbaren Content. Das Viewport-Meta-Tag stellt korrektes Rendering auf mobilen Geräten sicher.

html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>My Web Page</title>
</head>
<body>
  <h1>Hello, World!</h1>
  <p>Welcome to my page.</p>
</body>
</html>

Head-Section & Metadaten

Das <head>-Element enthält maschinenlesbare Metadaten. charset deklariert Character-Encoding (UTF-8 deckt nahezu alle Zeichen ab). Das Description-Meta-Tag ist crucial für SEO — Suchmaschinen zeigen es in Ergebnissen. defer bei Scripts verwenden, um sie nach HTML-Parsing zu laden.

html
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Page Title - Site Name</title>
  <meta name="description" content="A brief description for SEO">
  <meta name="author" content="John Doe">
  <link rel="stylesheet" href="style.css">
  <script src="app.js" defer></script>
</head>

Kommentare & Conditional Comments

HTML-Kommentare starten mit <!-- und enden mit -->. Sie werden im Browser nicht angezeigt, sind aber im Seiten-Quellcode sichtbar. Kommentare sind nützlich zum Hinterlassen von Notizen, Markieren von Sections (TODO, FIXME) und Dokumentation. Conditional Comments (nur IE) sind veraltet, können aber in Legacy-Code auftauchen.

html
<!-- This is a single-line comment -->

<!--
  This is a
  multi-line comment
-->

<!-- TODO: Add form validation -->
<!-- FIXME: Fix layout on mobile -->

<!--[if lt IE 9]>
  <script src="html5shiv.js"></script>
<![endif]-->

Überschriften-Hierarchie

HTML bietet sechs Überschrifts-Level, h1 (höchste) bis h6 (niedrigste). In hierarchischer Reihenfolge ohne Level zu überspringen verwenden. Suchmaschinen verwenden Überschriften, um Seitenstruktur zu verstehen. Best Practice: eine h1 pro Seite, gefolgt von h2 für Hauptsections, h3 für Subsections usw.

html
<h1>Main Page Title</h1>
<h2>Major Section</h2>
<h3>Subsection</h3>
<h4>Sub-subsection</h4>
<h5>Minor Heading</h5>
<h6>Lowest Level Heading</h6>

<!-- Use only one h1 per page for SEO -->
<h1>Blog Post Title</h1>
<h2>Introduction</h2>
<h3>Background</h3>

Div & Span-Container

<div> ist ein Block-Level-Container, der Elemente gruppiert und Styles anwendet. <span> ist ein Inline-Container zum Stylen kleiner Textteile. Beide sind generische Elemente ohne semantische Bedeutung — semantische Tags (header, nav, main, article) bevorzugen, wenn angemessen, für bessere Accessibility und SEO.

html
<div class="container">
  <div id="header" class="header">
    <span class="logo">MySite</span>
    <span class="tagline">Best Content</span>
  </div>
  <div class="content">
    <p>Main <span class="highlight">content</span> here.</p>
  </div>
</div>
02

Textformatierung

Bold, Italic & Emphasis

<strong> zeigt wichtigen Text an (Screen-Reader betonen ihn), während <b> rein visuelles Bold ist. Ebenso zeigt <em> Stress-Emphasis an (semantisch), während <i> visuelles Italic ist. <strong> und <em> für Accessibility bevorzugen. <b> und <i> sind akzeptabel für stilistische Zwecke ohne semantische Wichtigkeit.

html
<p>This is <strong>important</strong> text.</p>
<p>This is <b>bold</b> text.</p>
<p>This is <em>emphasized</em> text.</p>
<p>This is <i>italic</i> text.</p>
<p><strong>Warning:</strong> Do not touch!</p>

Mark, Delete & Insert

<mark> hebt Text als relevant hervor (wie ein Search-Highlight). <del> markiert gelöschten Text, <ins> markiert eingefügten Text — nützlich zum Zeigen von Edits. <s> streicht veraltete Infos durch. <small> ist für Side-Comments oder Copyright. <u> sollte vorsichtig verwendet werden, da es Links ähnelt.

html
<p>Please <mark>highlight this</mark> word.</p>
<p>The price is <del>$99</del> <ins>$79</ins> now.</p>
<p><s>Old information</s> is struck through.</p>
<p>Use <u>underline</u> sparingly.</p>
<p>Small <small>print</small> for side comments.</p>

Superscript & Subscript

<sub> erstellt Subscript-Text (unter Baseline) für chemische Formeln (H2O) und mathematische Variablen. <sup> erstellt Superscript-Text (über Baseline) für Exponenten (x²), Ordnungszahlen (1st) und Fußnoten. Beide sind Inline-Elemente, die vertikale Position und Schriftgröße anpassen.

html
<p>H<sub>2</sub>O is water.</p>
<p>E = mc<sup>2</sup> is Einstein's equation.</p>
<p>1st<sup>st</sup> January 2024</p>
<p>CO<sub>2</sub> emissions are rising.</p>
<p>x<sup>2</sup> + y<sup>2</sup> = r<sup>2</sup></p>

Zitate & Citationen

<blockquote> ist für Block-Level-Zitate (eingerückt, mehrzeilig). <q> ist für Inline-Kurzzitate (fügt automatisch Anführungszeichen hinzu). Das cite-Attribut liefert die Quell-URL. <cite> taggt den Titel eines Werks oder Autorennamen. Diese Elemente verbessern semantisches Markup für zitierten Content.

html
<blockquote cite="https://example.com/source">
  <p>The best way to predict the future is to invent it.</p>
  <footer>— <cite>Alan Kay</cite></footer>
</blockquote>

<p>As <q cite="https://example.com">someone once said</q>,
knowledge is power.</p>

Code & vorformatierter Text

<code> markiert Inline-Code-Snippets (Monospace-Font). <pre> bewahrt Whitespace und Zeilenumbrüche für vorformatierten Text. Die Kombination <pre><code> zeigt Code-Blöcke mit korrekter Indentation. <kbd> repräsentiert Tastatureingabe. <samp> ist für Programm-Ausgabe, und <var> für Variablen in mathematischen Ausdrücken.

html
<p>Use the <code>console.log()</code> function.</p>
<p>Press <kbd>Ctrl</kbd> + <kbd>C</kbd> to copy.</p>

<pre><code>function hello() {
  console.log("Hello, World!");
  return true;
}</code></pre>

Zeilenumbrüche & Horizontale Linien

<br> erstellt einen Zeilenumbruch innerhalb von Text (sparsam verwenden, CSS bevorzugen). <hr> erstellt eine horizontale Linie, die einen thematischen Bruch zwischen Sections repräsentiert. <wbr> schlägt eine Zeilenumbruch-Möglichkeit für lange Wörter oder URLs vor, sodass der Browser an optimalen Punkten umbrechen kann. <br> für Spacing vermeiden — stattdessen CSS-Margins verwenden.

html
<p>First line<br>Second line<br>Third line</p>

<p>Paragraph one.</p>
<hr>
<p>Paragraph two after a thematic break.</p>

<wbr><!-- word break opportunity for long URLs -->
https://example.com/<wbr>very<wbr>long<wbr>url
04

Bilder & Multimedia

Bilder

Immer alt-Text für Accessibility und SEO inkludieren — er beschreibt das Bild für Screen-Reader und wenn das Bild nicht lädt. loading='lazy' verschiebt das Laden von Offscreen-Bildern und verbessert Page Speed. srcset und sizes ermöglichen responsive Bilder — der Browser wählt das beste Bild basierend auf Geräte-Auflösung und Viewport. Immer width und height angeben, um Layout-Shift zu verhindern.

html
<!-- Basic image -->
<img src="photo.jpg" alt="A sunset over mountains" width="800" height="600">

<!-- Image with lazy loading -->
<img src="hero.jpg" alt="Hero banner" loading="lazy" decoding="async">

<!-- Responsive image with srcset -->
<img
  src="medium.jpg"
  srcset="small.jpg 480w, medium.jpg 800w, large.jpg 1200w"
  sizes="(max-width: 600px) 480px, 800px"
  alt="Responsive photo"
>

Picture-Element

<picture> bietet Art Direction und Format-Fallback. <source>-Elemente bieten Alternativen — der Browser wählt das erste unterstützte Format (WebP/AVIF sind kleiner). Das media-Attribut ermöglicht unterschiedliche Bilder für unterschiedliche Bildschirmgrößen. Das finale <img> ist der Fallback und muss immer vorhanden sein. Dies ist srcset überlegen, wenn man komplett unterschiedliche Bilder serviert.

html
<picture>
  <source srcset="webp-image.webp" type="image/webp">
  <source srcset="avif-image.avif" type="image/avif">
  <source srcset="wide.jpg" media="(min-width: 800px)">
  <img src="fallback.jpg" alt="Art-directed image">
</picture>

Audio

<audio> bettet Audio-Content ein. controls fügt Play/Pause/Volume-Controls hinzu. Mehrere <source>-Elemente bieten Format-Fallbacks (MP3 ist am weitesten unterstützt). autoplay wird von Browsern eingeschränkt — muted autoplay ist generell erlaubt. loop wiederholt das Audio. Der Text innen wird gezeigt, wenn Audio nicht unterstützt wird. Immer controls für User-Experience bereitstellen.

html
<audio controls>
  <source src="song.mp3" type="audio/mpeg">
  <source src="song.ogg" type="audio/ogg">
  Your browser does not support the audio element.
</audio>

<!-- Autoplay (muted required in most browsers) -->
<audio autoplay muted loop>
  <source src="background.mp3" type="audio/mpeg">
</audio>

Video

<video> bettet Video mit Controls für Play, Pause, Volume und Fullscreen ein. poster setzt ein Thumbnail vor dem Playback. Mehrere Sources bieten Format-Fallback (MP4/H.264 ist am kompatibelsten). <track> fügt Subtitles, Captions oder Descriptions für Accessibility hinzu. playsinline verhindert erzwungenen Fullscreen auf iOS. Immer Controls inkludieren, außer bei muted Autoplay.

html
<video controls width="640" height="360" poster="thumbnail.jpg">
  <source src="movie.mp4" type="video/mp4">
  <source src="movie.webm" type="video/webm">
  <track kind="subtitles" src="subs.vtt" srclang="en" label="English">
  Your browser does not support video.
</video>

<!-- Autoplay muted loop (common for backgrounds) -->
<video autoplay muted loop playsinline>
  <source src="bg.mp4" type="video/mp4">
</video>

Figure & Figcaption

<figure> gruppiert selbstständigen Content wie Bilder, Diagramme, Code-Listings oder Zitate mit ihrem Caption. <figcaption> bietet eine Caption oder Legende. Diese semantische Gruppierung verbessert Accessibility — Screen-Reader kündigen die Beziehung an. Figures können aus Text referenziert werden ('siehe Figure 1') und im Layout verschoben werden, ohne Kontext zu verlieren.

html
<figure>
  <img src="chart.png" alt="Quarterly sales chart showing 20% growth">
  <figcaption>Figure 1: Q4 2024 sales growth by region.</figcaption>
</figure>

<figure>
  <blockquote>
    <p>The best way to predict the future is to invent it.</p>
  </blockquote>
  <figcaption>— Alan Kay, 1971</figcaption>
</figure>

Iframe-Einbettungen

<iframe> bettet externen Content ein (Videos, Maps, andere Seiten). Immer ein title-Attribut für Accessibility inkludieren. loading='lazy' verbessert Performance für Offscreen-Iframes. Das allow-Attribut gibt Feature-Policies an. sandbox-Attribut schränkt die Iframe-Fähigkeiten für Sicherheit ein. Vorsicht — Iframes können Performance und Sicherheit beeinträchtigen.

html
<!-- Embed a YouTube video -->
<iframe
  src="https://www.youtube.com/embed/dQw4w9WgXcQ"
  width="560" height="315"
  title="YouTube video"
  frameborder="0"
  allow="accelerometer; autoplay; encrypted-media"
  allowfullscreen>
</iframe>

<!-- Embed a map -->
<iframe
  src="https://maps.google.com/maps?q=Paris&output=embed"
  title="Map of Paris" loading="lazy">
</iframe>
05

Listen

Ungeordnete Listen

<ul> erstellt eine ungeordnete (bulleted) Liste. Jedes Item ist in <li> gewrappt. Die list-style-type-CSS-Eigenschaft ändert Bullet-Style (disc, circle, square, none). Ungeordnete Listen sind für Items, wo Reihenfolge nicht wichtig ist. list-style: none und benutzerdefiniertes Styling für Navigations-Menüs und Feature-Listen verwenden.

html
<ul>
  <li>Apple</li>
  <li>Banana</li>
  <li>Cherry</li>
</ul>

<!-- Custom bullet style via CSS -->
<ul style="list-style-type: square;">
  <li>First item</li>
  <li>Second item</li>
</ul>

Geordnete Listen

<ol> erstellt eine geordnete (nummerierte) Liste für sequenzielle Items. Das start-Attribut setzt die Startnummer. reversed zeigt Items in absteigender Reihenfolge. Das type-Attribut ändert Nummerierungs-Style (1, A, a, I, i). <ol> für Steps, Rankings oder jede Sequenz verwenden, wo Reihenfolge wichtig ist.

html
<ol>
  <li>First step</li>
  <li>Second step</li>
  <li>Third step</li>
</ol>

<!-- Start from a specific number -->
<ol start="5">
  <li>Fifth item</li>
  <li>Sixth item</li>
</ol>

<!-- Reverse order -->
<ol reversed>
  <li>Countdown 3</li>
  <li>Countdown 2</li>
  <li>Countdown 1</li>
</ol>

Description-Listen

<dl> erstellt eine Description-Liste, die Terms (<dt>) mit Descriptions (<dd>) paart. Ideal für Glossare, FAQ-Seiten und Term-Definition-Paare. Mehrere <dd> können ein <dt> beschreiben, und umgekehrt. Description-Listen bieten semantische Bedeutung, die Definition-Tabellen fehlen, und verbessern Accessibility.

html
<dl>
  <dt>HTML</dt>
  <dd>HyperText Markup Language</dd>

  <dt>CSS</dt>
  <dd>Cascading Style Sheets</dd>

  <dt>JavaScript</dt>
  <dd>A programming language for the web</dd>
</dl>

Verschachtelte Listen

Listen können verschachtelt werden, indem man ein <ul> oder <ol> in ein <li> platziert. Browser rücken verschachtelte Listen automatisch ein und können Bullet-Styles ändern. Verschachtelung erstellt hierarchische Strukturen wie Inhaltsverzeichnisse, Dateibäume oder Multi-Level-Menüs. Verschachtelung vernünftig halten (2-3 Level) für Usability. Tief verschachtelte Listen werden schwer lesbar.

html
<ul>
  <li>Fruits
    <ul>
      <li>Apple</li>
      <li>Banana</li>
    </ul>
  </li>
  <li>Vegetables
    <ol>
      <li>Carrot</li>
      <li>Spinach</li>
    </ol>
  </li>
</ul>

Liste mit Links (Navigation)

Listen von Links innerhalb von <nav> erstellen semantische Navigations-Menüs. Verschachtelte <ul>-Elemente bilden Dropdown-Submenus. Diese Struktur ist für Screen-Reader zugänglich und leicht mit CSS zu stylen. aria-Attribute (aria-expanded, aria-haspopup) für interaktive Dropdowns verwenden. Listenbasierte Navigation ist das Standard-Pattern für zugängliche Menüs.

html
<nav>
  <ul class="menu">
    <li><a href="/">Home</a></li>
    <li><a href="/products">Products</a>
      <ul class="submenu">
        <li><a href="/products/a">Product A</a></li>
        <li><a href="/products/b">Product B</a></li>
      </ul>
    </li>
    <li><a href="/contact">Contact</a></li>
  </ul>
</nav>
06

Tabellen

Basis-Tabelle

<table> erstellt tabellarische Daten. <thead> gruppiert Header-Zeilen, <tbody> gruppiert Body-Zeilen, <tfoot> gruppiert Footer-Zeilen. <tr> ist eine Tabellenzeile, <th> ist eine Header-Zelle (bold, zentriert), <td> ist eine Datenzelle. thead/tbody/tfoot verbessern Accessibility und ermöglichen besseres Styling. Tabellen sollten für Daten verwendet werden, nicht für Layout.

html
<table>
  <thead>
    <tr>
      <th>Name</th>
      <th>Age</th>
      <th>City</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Alice</td>
      <td>30</td>
      <td>New York</td>
    </tr>
    <tr>
      <td>Bob</td>
      <td>25</td>
      <td>London</td>
    </tr>
  </tbody>
</table>

Spanning Cells

colspan lässt eine Zelle über mehrere Spalten spannen (horizontal mergen). rowspan lässt eine Zelle über mehrere Zeilen spannen (vertikal mergen). Diese Attribute erstellen komplexe Tabellen-Layouts wie Header, die mehrere Spalten gruppieren. Vorsicht bei Spanning — es kann Tabellen für Screen-Reader schwerer zu parsen machen. Accessibility immer testen.

html
<table border="1">
  <tr>
    <th colspan="2">Name</th>
    <th rowspan="2">Age</th>
  </tr>
  <tr>
    <th>First</th>
    <th>Last</th>
  </tr>
  <tr>
    <td>Alice</td>
    <td>Smith</td>
    <td>30</td>
  </tr>
</table>

Tabellen-Caption & Scope

<caption> bietet einen Titel für die Tabelle und verbessert Accessibility. Das scope-Attribut auf <th> sagt Screen-Readern, ob ein Header für eine Spalte (scope='col') oder Zeile (scope='row') gilt. Essenziell für komplexe Tabellen. Für noch komplexere Tabellen id- und headers-Attribute verwenden, um Zellen explizit mit ihren Headern zu assoziieren.

html
<table>
  <caption>Employee Salary Report 2024</caption>
  <thead>
    <tr>
      <th scope="col">Name</th>
      <th scope="col">Department</th>
      <th scope="col">Salary</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th scope="row">Alice</th>
      <td>Engineering</td>
      <td>$95,000</td>
    </tr>
  </tbody>
</table>

Spalten-Gruppen

<colgroup> gruppiert Spalten zum Stylen. <col>-Elemente darin wenden Styles (insbesondere width) auf spezifische Spalten an. Dies ist effizienter als das Setzen von width auf jede Zelle. Spalten-Gruppen unterstützen auch das span-Attribut, um mehrere Spalten auf einmal zu stylen. Für konsistente Spaltenbreiten über alle Zeilen verwenden.

html
<table>
  <colgroup>
    <col style="width: 30%;">
    <col style="width: 50%;">
    <col style="width: 20%;">
  </colgroup>
  <tr>
    <th>Product</th>
    <th>Description</th>
    <th>Price</th>
  </tr>
  <tr>
    <td>Laptop</td>
    <td>15-inch laptop</td>
    <td>$999</td>
  </tr>
</table>

Tabellen stylen

border-collapse: collapse mergt adjazente Borders zu einer. :nth-child(even) für Zebra-gestreifte Zeilen verwenden (verbessert Lesbarkeit). :hover hebt Zeilen bei Mouseover hervor. th-Styling differenziert Header. Tabellen-Styling sauber und lesbar halten — übermäßige Borders vermeiden. Responsive Tabellen können overflow-x: auto auf einem Wrapper für kleine Bildschirme benötigen.

html
<style>
  table { border-collapse: collapse; width: 100%; }
  th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
  th { background-color: #f4f4f4; }
  tr:nth-child(even) { background-color: #f9f9f9; }
  tr:hover { background-color: #e0e0e0; }
</style>
<table>
  <tr><th>Name</th><th>Score</th></tr>
  <tr><td>Alice</td><td>95</td></tr>
  <tr><td>Bob</td><td>87</td></tr>
</table>
07

Formulare & Input

Formular-Struktur

<form> wrapt Input-Controls. action gibt die Submit-URL an, method ist GET (in URL sichtbar) oder POST (verborgen). enctype='multipart/form-data' ist für File-Uploads erforderlich. <fieldset> gruppiert verwandte Felder, <legend> bietet eine Caption. <label> immer mit Inputs über for/id-Matching für Accessibility assoziieren.

html
<form action="/submit" method="POST" enctype="multipart/form-data">
  <fieldset>
    <legend>Personal Information</legend>

    <label for="name">Name:</label>
    <input type="text" id="name" name="name" required>

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

  <button type="submit">Submit</button>
</form>

Input-Typen

HTML5 führte viele Input-Typen mit eingebauter Validierung und mobilenfreundlichen Keyboards ein. type='email' validiert E-Mail-Format. type='number' bietet Spinner. type='date' und 'time' zeigen native Picker. type='color' öffnet einen Color-Picker. type='range' erstellt einen Slider. type='file' mit accept schränkt Dateitypen ein. type='hidden' speichert Daten, die Usern nicht gezeigt werden.

html
<input type="text" name="username" placeholder="Username">
<input type="email" name="email" required>
<input type="password" name="pwd" minlength="8">
<input type="number" name="age" min="0" max="120" step="1">
<input type="date" name="birthday">
<input type="time" name="appointment">
<input type="color" name="favcolor" value="#ff0000">
<input type="range" name="volume" min="0" max="100">
<input type="file" name="upload" accept="image/*">
<input type="hidden" name="token" value="abc123">

Select & Textarea

<select> erstellt ein Dropdown. <optgroup> gruppiert verwandte Optionen mit einem Label. <option> definiert Choices; das selected-Attribut pre-selektiert eine. <textarea> ist für mehrzeilige Texteingabe. rows und cols setzen die sichtbare Größe. maxlength limitiert Zeichenanzahl. placeholder bietet einen Hinweis. Beide unterstützen required und disabled-Attribute.

html
<label for="country">Country:</label>
<select id="country" name="country">
  <optgroup label="North America">
    <option value="us">United States</option>
    <option value="ca">Canada</option>
  </optgroup>
  <optgroup label="Europe">
    <option value="uk">United Kingdom</option>
    <option value="fr">France</option>
  </optgroup>
</select>

<label for="bio">Bio:</label>
<textarea id="bio" name="bio" rows="4" cols="40"
  maxlength="500" placeholder="Tell us about yourself"></textarea>

Checkboxes & Radio-Buttons

Checkboxes erlauben Mehrfachauswahl; Radio-Buttons erlauben nur eine (wenn sie denselben Namen teilen). Das checked-Attribut pre-selektiert eine Option. Inputs immer in <label> wrappen für klickbaren Text. <fieldset> und <legend> verwenden, um verwandte Choices für Accessibility zu gruppieren. Der Wert wird nur an den Server gesendet, wenn selektiert.

html
<fieldset>
  <legend>Select your interests:</legend>
  <label><input type="checkbox" name="interest" value="tech" checked> Tech</label>
  <label><input type="checkbox" name="interest" value="music"> Music</label>
  <label><input type="checkbox" name="interest" value="sports"> Sports</label>
</fieldset>

<fieldset>
  <legend>Choose a plan:</legend>
  <label><input type="radio" name="plan" value="free" checked> Free</label>
  <label><input type="radio" name="plan" value="pro"> Pro</label>
  <label><input type="radio" name="plan" value="enterprise"> Enterprise</label>
</fieldset>

Formular-Validierung

HTML5 bietet eingebaute Client-seitige Validierung. required verhindert Submit, wenn leer. minlength/maxlength schränken Textlänge ein. pattern verwendet Regex für benutzerdefinierte Validierung (das title-Attribut leitet User). type='email' und type='url' validieren Format. min/max funktionieren mit Zahlen und Daten. novalidate zum Formular hinzufügen, um Validierung zu deaktivieren.

html
<form>
  <input type="text" name="username" required
         minlength="3" maxlength="20"
         pattern="[A-Za-z0-9_]+"
         title="3-20 alphanumeric characters">

  <input type="email" name="email" required>

  <input type="url" name="website"
         placeholder="https://example.com">

  <input type="number" name="age" min="18" max="99">

  <button type="submit">Submit</button>
</form>

Buttons & Datalist

type='submit' submittet das Formular, type='reset' leert alle Felder, type='button' ist ein benutzerdefinierter Button. <datalist> bietet Autocomplete-Suggestions für <input>-Elemente — mit list/id verlinken. Anders als <select> können User benutzerdefinierte Werte eingeben. Dies kombiniert die Flexibilität von Text-Input mit der Bequemlichkeit von Suggestions.

html
<!-- Button types -->
<button type="submit">Submit Form</button>
<button type="reset">Reset</button>
<button type="button" onclick="alert('Hi')">Click Me</button>

<!-- Datalist for autocomplete suggestions -->
<label for="browser">Choose a browser:</label>
<input list="browsers" name="browser" id="browser">
<datalist id="browsers">
  <option value="Chrome">
  <option value="Firefox">
  <option value="Safari">
  <option value="Edge">
</datalist>
08

Semantisches HTML

Header & Navigation

<header> repräsentiert einführenden Content — typischerweise ein Logo, Heading und Navigation. Kann oben auf einer Seite oder innerhalb eines <article> oder <section> erscheinen. <nav> identifiziert Navigations-Links und hilft Screen-Readern, zur Navigation zu springen. Eine Seite kann mehrere Header haben (z.B. einen pro Section). Header ist nicht dasselbe wie head — es ist sichtbarer Content.

html
<header>
  <h1>My Website</h1>
  <nav>
    <ul>
      <li><a href="/">Home</a></li>
      <li><a href="/blog">Blog</a></li>
      <li><a href="/contact">Contact</a></li>
    </ul>
  </nav>
</header>

Main & Article

<main> wrapt den dominanten Content der Seite (nur einer pro Seite). <article> repräsentiert selbstständigen Content, der unabhängig vertrieben werden könnte (Blog-Post, News-Artikel, Forum-Post). <time> mit datetime bietet maschinenlesbare Daten für SEO. <section> gruppiert thematisch verwandten Content mit einem Heading. Diese Tags verbessern Document-Outline und Accessibility.

html
<main>
  <article>
    <h1>Blog Post Title</h1>
    <p>Published on <time datetime="2024-01-15">January 15, 2024</time></p>
    <p>The main content of the article...</p>
    <section>
      <h2>Subsection</h2>
      <p>More content...</p>
    </section>
  </article>
</main>

Section & Aside

<section> gruppiert verwandten Content mit einem Heading — verwenden, wenn Content ein natürliches Heading hat. <aside> repräsentiert Content, der tangentiell zum Haupt-Content verwandt ist (Sidebars, Pull-Quotes, Ads, Related Links). Beide verbessern Dokumentstruktur. Sections können verschachtelt werden. Asides werden typischerweise als Sidebars gestylt, sind aber semantisch, nicht presentational.

html
<section>
  <h2>Services</h2>
  <p>We offer the following services:</p>
  <article>
    <h3>Web Design</h3>
    <p>Custom website design...</p>
  </article>
</section>

<aside>
  <h3>Related Articles</h3>
  <ul>
    <li><a href="/post1">Related Post 1</a></li>
    <li><a href="/post2">Related Post 2</a></li>
  </ul>
</aside>

Footer

<footer> enthält Footer-Content für eine Seite oder Section — Copyright, Links zu verwandten Dokumenten, Kontaktinfo, Sitemap. Eine Seite kann mehrere Footer haben (z.B. einen pro Article-Section). Footer müssen nicht visuell unten sein, repräsentieren aber semantisch abschließenden Content. &copy; für das Copyright-Symbol verwenden.

html
<footer>
  <div>
    <h3>About Us</h3>
    <p>Company information...</p>
  </div>
  <nav>
    <a href="/privacy">Privacy Policy</a>
    <a href="/terms">Terms of Service</a>
    <a href="/sitemap">Sitemap</a>
  </nav>
  <p>&copy; 2024 My Company. All rights reserved.</p>
</footer>

Details & Summary

<details> erstellt ein interaktives Disclosure-Widget — Content ist verborgen, bis der User auf <summary> klickt. Das open-Attribut zeigt es standardmäßig expandiert. Dies ist natives HTML, kein JavaScript benötigt. Großartig für FAQs, einklappbare Sections und progressive Disclosure. Verschachtelte Details erstellen Multi-Level-Akkordeons. Mit dem [open]-Attribut-Selector stylen.

html
<details>
  <summary>Click to expand FAQ</summary>
  <p>This content is hidden by default and shown when the summary is clicked.</p>
</details>

<!-- Open by default -->
<details open>
  <summary>What is HTML?</summary>
  <p>HTML (HyperText Markup Language) is the standard language for creating web pages.</p>
</details>

<!-- Nested details -->
<details>
  <summary>Advanced Topics</summary>
  <details>
    <summary>Sub-topic</summary>
    <p>Nested content...</p>
  </details>
</details>
09

Meta-Tags & SEO

Charset & Viewport

charset='UTF-8' deklariert Character-Encoding — essenziell für korrektes Anzeigen aller Zeichen. Das Viewport-Meta-Tag ist kritisch für responsives Design: width=device-width matcht die Gerätebreite, initial-scale=1.0 setzt den Zoom-Level. Ohne es rendern mobile Browser Desktop-Breite-Seiten. Diese zwei Meta-Tags sollten in jedem HTML-Dokument sein.

html
<head>
  <!-- Character encoding -->
  <meta charset="UTF-8">

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

  <!-- Internet Explorer compatibility -->
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
</head>

Description & Keywords

Das Description-Meta-Tag ist das wichtigste für SEO — Suchmaschinen zeigen es unter dem Titel in Ergebnissen (unter 160 Zeichen halten). keywords wird von modernen Suchmaschinen weitgehend ignoriert. robots steuert Indexierung: index/noindex, follow/nofollow. author credited den Content-Ersteller. Compelling Descriptions schreiben, um Click-Through-Rates zu verbessern.

html
<meta name="description"
      content="Free HTML tutorials for beginners. Learn HTML tags, attributes, and semantic markup with examples.">

<meta name="keywords"
      content="HTML, tutorial, web development, markup">

<meta name="author" content="John Doe">
<meta name="robots" content="index, follow">

Open Graph (Facebook)

Open Graph (og:)-Meta-Tags steuern, wie die Seite erscheint, wenn auf Facebook, LinkedIn und anderen Plattformen geteilt. og:title, og:description, og:image und og:url sind die wichtigsten. og:type kann article, website, product usw. sein. Das Bild sollte mindestens 1200x630 Pixel sein. Mit Facebooks Sharing Debugger vor dem Deploy testen.

html
<meta property="og:title" content="My Amazing Article">
<meta property="og:description" content="A brief description of the article.">
<meta property="og:image" content="https://example.com/image.jpg">
<meta property="og:url" content="https://example.com/article">
<meta property="og:type" content="article">
<meta property="og:site_name" content="My Website">
<meta property="og:locale" content="en_US">

Twitter Cards

Twitter Card-Meta-Tags steuern, wie Links auf Twitter/X erscheinen. twitter:card kann summary, summary_large_image oder player sein. Die Large-Image-Card ist am engagingsten. twitter:site und twitter:creator linken zu Twitter-Accounts. Wenn Open Graph-Tags vorhanden sind, fällt Twitter auf sie zurück, aber explizite Twitter-Tags geben mehr Kontrolle. Mit Twitter Card Validator testen.

html
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="My Amazing Article">
<meta name="twitter:description" content="A brief description.">
<meta name="twitter:image" content="https://example.com/image.jpg">
<meta name="twitter:site" content="@mywebsite">
<meta name="twitter:creator" content="@author">

Canonical & Structured Data

Der Canonical-Link-Tag sagt Suchmaschinen die bevorzugte URL für eine Seite und verhindert Duplicate-Content-Strafen. JSON-LD-Structured-Data hilft Suchmaschinen, den Content zu verstehen, und ermöglicht Rich Snippets (Star-Ratings, Breadcrumbs, FAQ-Akkordeons in Suchergebnissen). schema.org-Typen wie Article, Product, Event oder FAQPage verwenden. Mit Googles Rich Results Test validieren.

html
<!-- Canonical URL (prevents duplicate content issues) -->
<link rel="canonical" href="https://example.com/article">

<!-- Structured data (JSON-LD) -->
<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Article",
  "headline": "My Article Title",
  "author": "John Doe",
  "datePublished": "2024-01-15",
  "image": "https://example.com/image.jpg"
}
</script>
10

SVG & Canvas

SVG-Grundlagen

SVG (Scalable Vector Graphics) erstellt auflösungsunabhängige Grafiken, die ohne Qualitätsverlust skalieren. Inline-SVG kann mit CSS gestylt und mit JavaScript manipuliert werden. Häufige Shapes: <circle>, <rect>, <line>, <ellipse>, <polygon>, <path>. SVG ist ideal für Icons, Logos und Diagramme. Anders als Raster-Bilder sind SVGs bei jeder Größe scharf.

html
<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg">
  <circle cx="100" cy="100" r="50" fill="blue" stroke="black" stroke-width="2"/>
  <text x="100" y="105" text-anchor="middle" fill="white">Circle</text>
</svg>

<!-- Inline SVG (can be styled with CSS) -->
<svg width="100" height="100">
  <rect x="10" y="10" width="80" height="80" fill="red" rx="10"/>
</svg>

SVG-Shapes

SVG-Shapes verwenden koordinatenbasierte Attribute. <rect> braucht x, y, width, height; rx/ry erstellen abgerundete Ecken. <circle> braucht cx, cy (Center) und r (Radius). <ellipse> verwendet rx und ry für unterschiedliche x/y-Radien. <line> verbindet x1,y1 mit x2,y2. <polygon> nimmt eine Points-Liste. fill setzt Innenfarbe, stroke setzt Outline.

html
<svg width="300" height="200">
  <!-- Rectangle -->
  <rect x="10" y="10" width="80" height="50" fill="orange" rx="10" ry="10"/>

  <!-- Circle -->
  <circle cx="200" cy="50" r="40" fill="green"/>

  <!-- Ellipse -->
  <ellipse cx="100" cy="150" rx="60" ry="30" fill="purple"/>

  <!-- Line -->
  <line x1="10" y1="180" x2="290" y2="180" stroke="black" stroke-width="2"/>

  <!-- Polygon -->
  <polygon points="250,10 290,80 210,80" fill="pink"/>
</svg>

SVG-Paths

<path> ist das mächtigste SVG-Element und verwendet ein d-Attribut mit Befehlen: M (moveto), L (lineto), H/V (horizontal/vertikale Linie), C (kubische Bezier), Q (quadratische Bezier), A (Bogen), Z (Pfad schließen). Großbuchstaben = absolute Koordinaten, Kleinbuchstaben = relative. viewBox definiert das Koordinatensystem. SVG-Icons verwenden Paths für skalierbare, stylebare Icons.

html
<svg width="200" height="200">
  <!-- M=move, L=line, C=curve, Z=close -->
  <path d="M 10 10 L 100 10 L 100 100 Z" fill="none" stroke="black"/>

  <!-- Bezier curve -->
  <path d="M 10 100 C 50 10, 150 10, 190 100" fill="none" stroke="red"/>

  <!-- Arc -->
  <path d="M 10 100 A 90 90 0 0 1 190 100" fill="none" stroke="blue"/>
</svg>

<!-- SVG icon example -->
<svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor">
  <path d="M12 2L2 7v10l10 5 10-5V7z"/>
</svg>

Canvas-Grundlagen

<canvas> ist eine Bitmap-Zeichenoberfläche, die via JavaScript manipuliert wird. Den 2D-Context mit getContext('2d') holen. Anders als SVG ist Canvas Pixel-basiert (nicht skalierbar) und nicht Teil des DOM. Canvas ist besser für komplexe Animationen, Spiele und Bildverarbeitung. SVG ist besser für statische Grafiken, Icons und interaktive Charts. Basierend auf Bedürfnissen wählen.

html
<canvas id="myCanvas" width="300" height="200"></canvas>

<script>
  const canvas = document.getElementById('myCanvas');
  const ctx = canvas.getContext('2d');

  // Draw a rectangle
  ctx.fillStyle = 'blue';
  ctx.fillRect(10, 10, 100, 80);

  // Draw a circle
  ctx.beginPath();
  ctx.arc(200, 50, 30, 0, Math.PI * 2);
  ctx.fillStyle = 'red';
  ctx.fill();

  // Draw text
  ctx.font = '20px Arial';
  ctx.fillText('Hello Canvas', 50, 150);
</script>

Inline SVG-Icons

SVG <symbol> definiert wiederverwendbare Icons, die mit <use href='#id'> referenziert werden. Dies ist die SVG-Sprite-Technik — Icons einmal definieren, überall verwenden. Das Symbol ist hidden (display:none) und wird via <use> instanziiert. Icons erben Farbe von CSS 'color' via fill='currentColor'. Dieser Ansatz ist effizient (eine Definition, viele Verwendungen) und vollständig stylebar.

html
<!-- Reusable SVG symbol -->
<svg style="display:none">
  <symbol id="icon-home" viewBox="0 0 24 24">
    <path d="M12 2L2 12h3v8h6v-6h2v6h6v-8h3z"/>
  </symbol>
</svg>

<!-- Use the icon -->
<svg width="24" height="24" fill="currentColor">
  <use href="#icon-home"/>
</svg>

<!-- Styled icon -->
<svg width="32" height="32" class="icon" style="color: blue;">
  <use href="#icon-home"/>
</svg>
11

Accessibility (ARIA)

ARIA-Rollen

ARIA-Rollen definieren, was ein Element für Screen-Reader tut. Landmark-Rollen (banner, navigation, main, complementary, contentinfo) lassen Screen-Reader-User zwischen Page-Regionen springen. HTML5 semantische Elemente (<header>, <nav>, <main>) haben implizite ARIA-Rollen, sodass das Hinzufügen von role-Attributen oft redundant ist — aber nützlich für ältere Browser. Semantisches HTML gegenüber ARIA bevorzugen, wenn möglich.

html
<!-- Landmark roles for page structure -->
<header role="banner">Site Header</header>
<nav role="navigation">Main Menu</nav>
<main role="main">Primary Content</main>
<aside role="complementary">Sidebar</aside>
<footer role="contentinfo">Footer</footer>
<form role="search">Search Form</form>

<!-- Document structure roles -->
<article role="article">Blog Post</article>
<section role="region" aria-label="Comments">Comments</section>

aria-label & aria-labelledby

aria-label definiert einen zugänglichen Namen, wenn kein sichtbares Label existiert (z.B. Icon-only-Buttons). aria-labelledby referenziert die ID sichtbarer Text-Element(e), die das Control labeln — nützlich, wenn ein sichtbares Label bereits auf dem Screen ist. Wenn mehrere IDs gelistet sind, wird ihr Text in Reihenfolge verkettet. aria-labelledby bevorzugen, wenn sichtbarer Text existiert, da es Labels synchron hält.

html
<!-- aria-label provides accessible name directly -->
<button aria-label="Close menu" onclick="closeMenu()">✕</button>
<input type="search" aria-label="Search products" />

<!-- aria-labelledby references visible text -->
<div id="billing-label">Billing Address</div>
<input type="text" aria-labelledby="billing-label" />

<!-- Multiple labels combined -->
<span id="city">City</span>
<span id="required">required</span>
<input aria-labelledby="city required" />

aria-describedby & Tooltips

aria-describedby verlinkt ein Element mit zusätzlichem beschreibendem Text via Element-ID. Screen-Reader kündigen diese Description nach dem Label an. Ideal für Help-Text, Hints und Error-Messages. role='alert' auf Error-Messages verwenden, sodass sie sofort angekündigt werden, wenn sie erscheinen. aria-invalid='true' auf Felder mit Fehlern setzen, sodass Screen-Reader den invaliden Zustand anzeigen.

html
<label for="password">Password</label>
<input type="password" id="password"
       aria-describedby="pwd-help pwd-rules" />
<p id="pwd-help">Must be at least 8 characters</p>
<p id="pwd-rules">Include uppercase, number, and symbol</p>

<!-- Error messaging -->
<input type="email" id="email" aria-describedby="email-error" aria-invalid="true" />
<p id="email-error" role="alert">Please enter a valid email address</p>

Live Regions (aria-live)

Live Regions kündigen dynamische Content-Änderungen Screen-Reader-Usern an. aria-live='polite' wartet auf eine Pause vor der Ankündigung (gut für Status-Updates). aria-live='assertive' unterbricht sofort (für kritische Fehler). aria-atomic='true' liest den gesamten Region-Content statt nur des geänderten Teils. aria-relevant gibt an, welche Änderungstypen (additions, removals, text) Ankündigungen triggern. Essenziell für SPAs, Chat-Apps und Auto-Update-Content.

html
<!-- Polite: announces when user is idle -->
<div aria-live="polite" id="status">Saving...</div>

<!-- Assertive: announces immediately, interrupts -->
<div aria-live="assertive" role="alert" id="errors">
  Connection lost!
</div>

<!-- aria-atomic reads entire region, not just changes -->
<div aria-live="polite" aria-atomic="true" id="cart">
  3 items in cart
</div>

<!-- aria-relevant controls what changes are announced -->
<div aria-live="polite" aria-relevant="additions text">
  Chat messages appear here
</div>

Focus-Management & tabindex

tabindex steuert Keyboard-Focus-Verhalten. tabindex='0' macht nicht-interaktive Elemente (divs, spans) in der natürlichen DOM-Reihenfolge focusable — für benutzerdefinierte Widgets verwenden. tabindex='-1' macht Elemente nur programmatisch via JS .focus() focusable — nützlich für Modals und Skip-Targets. Niemals positive tabindex-Werte verwenden, da sie die natürliche Tab-Reihenfolge überschreiben und Verwirrung stiften. Immer Skip-Links als erstes focusable Element auf einer Seite bereitstellen.

html
<!-- tabindex="0": element is focusable in natural order -->
<div tabindex="0" role="button" onkeypress="handleKey()">
  Custom clickable div
</div>

<!-- tabindex="-1": focusable only via JS, removed from tab order -->
<div tabindex="-1" id="modal">Modal content</div>
<script>
  document.getElementById('modal').focus();
</script>

<!-- tabindex="1+": DO NOT USE — breaks natural tab order -->
<!-- Avoid: <div tabindex="2"> -->

<!-- Skip link for keyboard users -->
<a href="#main-content" class="skip-link">Skip to main content</a>
<main id="main-content">...</main>

Verborgener Content & Screen-Reader-Only

aria-hidden='true' entfernt Elemente aus dem Accessibility-Tree, während sie sichtbar bleiben — für dekorative Icons, redundanten Text oder Offscreen-Content verwenden. Das .sr-only-Pattern versteckt Text visuell, hält ihn aber für Screen-Reader lesbar — essenziell für Icon-only-Buttons. Niemals aria-hidden auf focusable Elemente verwenden, da dies eine Diskonnektion zwischen Keyboard- und Screen-Reader-Navigation erstellt. Die Clip-Technik ist die robusteste visuell-verborgene Methode.

html
<!-- aria-hidden: visible but hidden from screen readers -->
<div aria-hidden="true">
  <i class="icon-decoration"></i> Decorative only
</div>

<!-- visually hidden but available to screen readers -->
<style>
.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap; border: 0;
}
</style>
<button>
  <span class="sr-only">Delete item</span>
  <i class="icon-trash" aria-hidden="true"></i>
</button>
12

HTML5-APIs (Geolocation, Storage, Drag & Drop)

Geolocation-API

Die Geolocation-API lässt dich den physischen Standort des Users anfragen. Browser fragen immer nach Permission — der User muss explizit Zugriff gewähren. getCurrentPosition nimmt Success- und Error-Callbacks plus ein Options-Objekt (enableHighAccuracy, timeout, maximumAge). Für kontinuierliches Tracking watchPosition() verwenden, das eine ID zurückgibt, die man an clearWatch() übergeben kann. Fehler immer graceful handhaben (Permission denied, Position unavailable, Timeout). Geolocation erfordert HTTPS in modernen Browsern.

html
<!-- Request user location -->
<button onclick="getLocation()">Get My Location</button>
<p id="demo"></p>

<script>
function getLocation() {
  if (navigator.geolocation) {
    navigator.geolocation.getCurrentPosition(
      (pos) => {
        document.getElementById("demo").innerHTML =
          "Lat: " + pos.coords.latitude +
          "<br>Lon: " + pos.coords.longitude;
      },
      (err) => {
        alert("Error: " + err.message);
      },
      { enableHighAccuracy: true, timeout: 5000 }
    );
  } else {
    alert("Geolocation not supported.");
  }
}
</script>

Web Storage (localStorage & sessionStorage)

Web Storage bietet Key-Value-Storage auf dem Client. localStorage persistiert unbegrenzt; sessionStorage wird geleert, wenn der Tab schließt. Beide speichern nur Strings — JSON.stringify/parse für Objekte verwenden. Storage-Limit ist ~5-10MB pro Origin. Anders als Cookies werden Storage-Daten nicht mit jeder HTTP-Anfrage gesendet. Vorsicht: Storage ist synchron und blockiert den Main-Thread, und ist von jedem Script auf derselben Origin zugänglich (nicht für sensible Daten geeignet).

html
<!-- localStorage: persists until cleared -->
<script>
// Store data
localStorage.setItem("username", "alice");
localStorage.setItem("prefs", JSON.stringify({theme: "dark", lang: "en"}));

// Retrieve data
const user = localStorage.getItem("username");
const prefs = JSON.parse(localStorage.getItem("prefs") || "{}");

// Remove single item
localStorage.removeItem("username");

// Clear all items
localStorage.clear();

// sessionStorage: cleared when tab closes
sessionStorage.setItem("tempToken", "abc123");
</script>

Drag and Drop-API

Die HTML5 Drag and Drop-API ermöglicht native Drag-Interaktionen. draggable='true' auf dem Source-Element setzen. ondragstart feuert, wenn Dragging beginnt — dataTransfer.setData() verwenden, um die Dragged-Daten zu speichern. ondragover auf dem Drop-Target MUSS preventDefault() aufrufen, um Dropping zu erlauben. ondrop handhabt den tatsächlichen Drop — Daten mit dataTransfer.getData() abrufen. Man kann Dateien vom OS in den Browser ziehen via event.dataTransfer.files. Für komplexe Apps Bibliotheken wie SortableJS für besseren Cross-Browser-Support in Betracht ziehen.

html
<div id="drag1" draggable="true" ondragstart="drag(event)">
  Drag me!
</div>
<div id="dropzone" ondrop="drop(event)" ondragover="allowDrop(event)">
  Drop here
</div>

<script>
function allowDrop(ev) {
  ev.preventDefault(); // necessary to allow dropping
}

function drag(ev) {
  ev.dataTransfer.setData("text", ev.target.id);
}

function drop(ev) {
  ev.preventDefault();
  const data = ev.dataTransfer.getData("text");
  ev.target.appendChild(document.getElementById(data));
}
</script>

Page Visibility-API

Die Page Visibility-API sagt dir, ob die Seite für den User sichtbar ist (nicht minimiert, nicht in einem Hintergrund-Tab). Verwenden, um teure Animationen, Video-Playback oder Polling zu pausieren, wenn der User nicht hinschaut — spart Battery und CPU. document.hidden ist ein Boolean; document.visibilityState gibt 'visible', 'hidden' oder 'prerender' zurück. Das visibilitychange-Event feuert bei Übergängen. Dies ist zuverlässiger als blur/focus für das Erkennen tatsächlicher Sichtbarkeit.

html
<script>
document.addEventListener("visibilitychange", () => {
  if (document.hidden) {
    console.log("Tab is hidden — pause video/animation");
    video.pause();
  } else {
    console.log("Tab is visible — resume");
    video.play();
  }
});

// Check current state
if (document.visibilityState === "visible") {
  console.log("Page is visible");
}
</script>

Fullscreen-API

Die Fullscreen-API lässt dich jedes Element im Fullscreen-Modus anzeigen. requestFullscreen() muss durch eine User-Geste getriggert werden (Click/Keypress). Unterschiedliche Browser können Vendor-Prefixes benötigen (webkit, moz, ms). Das fullscreenchange-Event feuert beim Ein- oder Austritt in Fullscreen. document.fullscreenElement referenziert das aktuelle Fullscreen-Element (null, wenn nicht in Fullscreen). Die :fullscreen-CSS-Pseudo-Class verwenden, um Fullscreen-Elemente unterschiedlich zu stylen.

html
<button onclick="openFullscreen()">Fullscreen</button>
<button onclick="closeFullscreen()">Exit</button>
<div id="container">Content to fullscreen</div>

<script>
function openFullscreen() {
  const elem = document.getElementById("container");
  if (elem.requestFullscreen) {
    elem.requestFullscreen();
  } else if (elem.webkitRequestFullscreen) {
    elem.webkitRequestFullscreen();
  }
}

function closeFullscreen() {
  if (document.exitFullscreen) {
    document.exitFullscreen();
  }
}

document.addEventListener("fullscreenchange", () => {
  console.log("Fullscreen:", !!document.fullscreenElement);
});
</script>
13

Web Components

Custom Elements

Custom Elements lassen dich wiederverwendbare HTML-Tags mit gekapseltem Verhalten erstellen. Die Klasse erweitert HTMLElement (oder HTMLElement-Subklassen). connectedCallback feuert, wenn das Element zum DOM hinzugefügt wird — für Rendering verwenden. attributeChangedCallback reagiert auf Attribut-Änderungen, aber nur für Attribute, die in observedAttributes gelistet sind. Namen müssen einen Bindestrich enthalten (z.B. 'my-greeting'), um Konflikte mit nativem HTML zu vermeiden. customElements.define() registriert das Element. Shadow DOM vermeiden, außer man braucht Style-Kapselung.

html
<my-greeting name="World"></my-greeting>

<script>
class MyGreeting extends HTMLElement {
  constructor() {
    super();
    this.name = this.getAttribute("name") || "Guest";
  }
  connectedCallback() {
    this.innerHTML = `<h2>Hello, ${this.name}!</h2>`;
  }
  // Observe attribute changes
  static get observedAttributes() {
    return ["name"];
  }
  attributeChangedCallback(name, oldVal, newVal) {
    if (name === "name") {
      this.name = newVal;
      this.connectedCallback();
    }
  }
}
customElements.define("my-greeting", MyGreeting);
</script>

Shadow DOM

Shadow DOM bietet Style- und DOM-Kapselung — Styles innerhalb des Shadow-Trees leaken nicht heraus, und Page-Styles leaken nicht hinein. attachShadow({mode:'open'}) erstellt einen Shadow-Root, der via element.shadowRoot zugänglich ist. mode:'closed' verweigert externen Zugriff (selten verwendet). <slot>-Elemente sind Platzhalter, wo Light-DOM-Children projiziert werden. Named Slots (<slot name='title'>) matchen Children mit passenden slot-Attributen. ::slotted() stylt projizierten Content. Shadow DOM ist Schlüssel zum Bauen selbstständiger, wiederverwendbarer Komponenten.

html
<my-card>
  <span slot="title">Card Title</span>
  <p slot="body">Card content here.</p>
</my-card>

<script>
class MyCard extends HTMLElement {
  constructor() {
    super();
    const shadow = this.attachShadow({ mode: "open" });
    shadow.innerHTML = `
      <style>
        .card { border: 1px solid #ccc; padding: 16px; border-radius: 8px; }
        ::slotted([slot="title"]) { font-size: 1.5em; font-weight: bold; }
      </style>
      <div class="card">
        <slot name="title"></slot>
        <slot name="body"></slot>
      </div>
    `;
  }
}
customElements.define("my-card", MyCard);
</script>

HTML-Templates

Das <template>-Element hält HTML, das nicht gerendert wird, wenn die Seite lädt — sein Content ist inert (Scripts laufen nicht, Bilder laden nicht, Styles gelten nicht). Auf den Content via .content (ein DocumentFragment) zugreifen und mit cloneNode(true) klonen, um zu instanziieren. Templates sind ideal für wiederholende Strukturen, die von JavaScript generiert werden. Anders als innerHTML werden Templates einmal geparst und können wiederholt geklont werden, ohne neu zu parsen. Kombiniert mit Custom Elements und Shadow DOM bilden sie den Web-Components-Standard.

html
<template id="row-template">
  <tr>
    <td class="name"></td>
    <td class="email"></td>
  </tr>
</template>

<script>
function addRow(name, email) {
  const template = document.getElementById("row-template");
  const clone = template.content.cloneNode(true);
  clone.querySelector(".name").textContent = name;
  clone.querySelector(".email").textContent = email;
  document.querySelector("tbody").appendChild(clone);
}

addRow("Alice", "[email protected]");
addRow("Bob", "[email protected]");
</script>

Lifecycle-Callbacks

Custom Elements haben vier Lifecycle-Callbacks. constructor() läuft, wenn das Element erstellt wird (schwere Arbeit hier vermeiden). connectedCallback() feuert, wenn zum DOM hinzugefügt — ideal für Setup und Rendering. disconnectedCallback() feuert beim Entfernen — für Cleanup verwenden (Event-Listener, Timer). adoptedCallback() feuert beim Verschieben in ein neues Dokument via adoptNode() (selten). attributeChangedCallback() feuert nur für beobachtete Attribute. Die Upgrade-Reihenfolge ist immer: constructor → connectedCallback. Attribut-Änderungen können vor connectedCallback feuern.

html
<script>
class LifecycleDemo extends HTMLElement {
  constructor() {
    super();
    console.log("1. constructor: element created");
  }
  connectedCallback() {
    console.log("2. connected: added to DOM");
  }
  disconnectedCallback() {
    console.log("3. disconnected: removed from DOM");
  }
  adoptedCallback() {
    console.log("4. adopted: moved to new document");
  }
  attributeChangedCallback(attr, oldVal, newVal) {
    console.log(`5. attribute '${attr}' changed: ${oldVal} -> ${newVal}`);
  }
  static get observedAttributes() {
    return ["data-status"];
  }
}
customElements.define("lifecycle-demo", LifecycleDemo);
</script>

Customized Built-in Elements

Customized Built-in Elements erweitern native HTML-Elemente (wie button, input, div), um deren eingebautes Verhalten zu erben. Das 'is'-Attribut anstelle eines Custom-Tag-Namens verwenden. Das dritte Argument zu customElements.define() gibt an, welches native Element erweitert wird. Nützlich, wenn man bestehende Elemente erweitern möchte (z.B. Validierung zu <input> hinzufügen), anstatt komplett neue zu erstellen. Hinweis: Safari unterstützt keine Customized Built-in Elements — autonomous Custom Elements für Cross-Browser-Kompatibilität in Betracht ziehen.

html
<!-- Extend a native button -->
<button is="my-button">Click me</button>

<script>
class MyButton extends HTMLButtonElement {
  constructor() {
    super();
    this.addEventListener("click", () => {
      this.textContent = "Clicked!";
      this.style.background = "lightgreen";
    });
  }
  connectedCallback() {
    this.style.fontWeight = "bold";
  }
}
customElements.define("my-button", MyButton,
  { extends: "button" });
</script>
14

Media-Elemente (Audio & Video)

Video-Element

Das <video>-Element bettet Video ohne Plugins ein. Das controls-Attribut zeigt eingebaute Play/Pause/Volume-Controls. poster gibt ein Preview-Bild vor dem Playback an. Mehrere <source>-Tags bieten Format-Fallbacks — der Browser verwendet das erste, das er unterstützt (MP4/H.264 ist am weitesten unterstützt, WebM ist offen und effizient). <track>-Elemente fügen Subtitles, Captions oder Descriptions via WebVTT-Dateien hinzu. Immer Fallback-Text für sehr alte Browser inkludieren. Für Autoplay muted-Attribut hinzufügen — die meisten Browser blockieren Autoplay mit Sound.

html
<video width="640" height="360" controls poster="preview.jpg">
  <source src="movie.mp4" type="video/mp4">
  <source src="movie.webm" type="video/webm">
  <track kind="subtitles" src="subs_en.vtt"
         srclang="en" label="English" default>
  <track kind="captions" src="caps_en.vtt"
         srclang="en" label="English Captions">
  Your browser does not support the video tag.
</video>

Audio-Element

Das <audio>-Element bettet Sound ein. controls zeigt die eingebaute Player-UI. Ohne controls ist das Element unsichtbar — Playback via JavaScript steuern (play(), pause(), volume, currentTime). preload='auto' schlägt vor, dass der Browser die Datei puffern sollte; 'metadata' lädt nur Duration/Info; 'none' lädt nichts bis Play. MP3 hat universelle Unterstützung; OGG Vorbis ist offen, aber nicht in Safari unterstützt. Für Spiele oder präzises Timing die Web Audio API anstelle von <audio> für niedrigere Latenz und Effekte verwenden.

html
<!-- Basic audio player -->
<audio controls>
  <source src="song.mp3" type="audio/mpeg">
  <source src="song.ogg" type="audio/ogg">
  Your browser does not support audio.
</audio>

<!-- Audio controlled by JavaScript -->
<audio id="player" src="song.mp3" preload="auto"></audio>
<button onclick="document.getElementById('player').play()">Play</button>
<button onclick="document.getElementById('player').pause()">Pause</button>
<button onclick="document.getElementById('player').volume += 0.1">Vol+</button>

Picture & srcset (Responsive Bilder)

Responsive Bilder verbessern Performance, indem sie passend dimensionierte Bilder servieren. srcset mit Width-Deskriptoren (480w, 800w) plus sizes-Hints lassen den Browser das beste Bild wählen — dies wird für Resolution-Switching bevorzugt. <picture> mit Media-Queries ermöglicht Art Direction (unterschiedliche Crops für unterschiedliche Screens). <source> mit type-Attributen bietet moderne Format-Fallbacks (WebP, AVIF) mit JPG/PNG-Fallback. Immer ein reguläres <img> als letztes Child von <picture> für Fallback und Accessibility inkludieren.

html
<!-- srcset: let browser choose resolution -->
<img src="small.jpg"
     srcset="small.jpg 480w, medium.jpg 800w, large.jpg 1200w"
     sizes="(max-width: 600px) 480px, 800px"
     alt="Responsive image">

<!-- picture: art direction with different images -->
<picture>
  <source media="(max-width: 600px)" srcset="mobile.jpg">
  <source media="(max-width: 1200px)" srcset="tablet.jpg">
  <img src="desktop.jpg" alt="Art-directed image">
</picture>

<!-- Modern format with fallback -->
<picture>
  <source type="image/webp" srcset="photo.webp">
  <source type="image/avif" srcset="photo.avif">
  <img src="photo.jpg" alt="With format fallback">
</picture>

Iframe-Einbettung

iframes betten ein anderes Dokument innerhalb der aktuellen Seite ein. Das title-Attribut ist essenziell für Accessibility — Screen-Reader kündigen es an. Das sandbox-Attribut schränkt die Iframe-Fähigkeiten für Sicherheit ein: leerer Wert blockiert alles; Tokens (allow-scripts, allow-forms, allow-same-origin) hinzufügen, um spezifische Features zu re-aktivieren. loading='lazy' verschiebt das Laden bis nah zum Viewport. allow gibt Feature-Policies an (camera, microphone, autoplay). Vorsicht beim Einbetten von nicht vertrauenswürdigem Content — sandboxen. Cross-Origin-Iframes können nicht via JavaScript zugegriffen werden.

html
<!-- Basic iframe -->
<iframe src="https://example.com"
        width="600" height="400"
        title="Embedded Content">
</iframe>

<!-- Sandboxed iframe for security -->
<iframe src="untrusted.html"
        sandbox="allow-scripts allow-same-origin"
        loading="lazy">
</iframe>

<!-- YouTube embed -->
<iframe src="https://www.youtube.com/embed/VIDEO_ID"
        allow="accelerometer; autoplay; encrypted-media"
        allowfullscreen
        title="YouTube video">
</iframe>

Embed & Object

<embed> und <object> sind ältere Einbettungs-Methoden, größtenteils durch <iframe> und <video> ersetzt. <embed> ist self-closing und einfach, bietet aber keinen Fallback-Content. <object> ist flexibler — Content innerhalb der Tags dient als Fallback, wenn die eingebettete Ressource nicht angezeigt werden kann. <object> für PDFs und SVGs verwenden, wo Fallback benötigt wird. Für moderne Web-Entwicklung <iframe> für externe Seiten, <video>/<audio> für Media, und inline <svg> für Vektorgrafiken bevorzugen. <embed> wird hauptsächlich für Plugin-Content verwendet (Flash, mittlerweile veraltet).

html
<!-- embed: simple, self-closing -->
<embed src="animation.svg" type="image/svg+xml"
       width="300" height="200">

<!-- object: more flexible with fallback -->
<object data="document.pdf" type="application/pdf"
        width="100%" height="600px">
  <p>Unable to display PDF.
     <a href="document.pdf">Download it instead.</a>
  </p>
</object>

<!-- embed YouTube without iframe -->
<embed src="https://www.youtube.com/v/VIDEO_ID"
       type="application/x-shockwave-flash"
       width="560" height="315">
15

Input-Typen Deep Dive

Date & Time-Inputs

HTML5 Date/Time-Input-Typen bieten native Picker ohne JavaScript-Bibliotheken. type='date' gibt einen Kalender; type='time' gibt einen Time-Picker; type='datetime-local' kombiniert beide. type='month' und type='week' selektieren Monate und Wochen. min/max schränken den wählbaren Bereich ein. step definiert Granularität (z.B. step='1800' für 30-Minuten-Intervalle in Sekunden). Das angezeigte Format variiert nach Browser/Locale, aber der eingereichte Wert ist immer ISO 8601-Format (YYYY-MM-DD). Nicht alle Browser unterstützen alle Typen gleich gut — cross-browser testen.

html
<label for="birthday">Birthday:</label>
<input type="date" id="birthday" min="1900-01-01" max="2025-12-31">

<label for="appt">Appointment:</label>
<input type="time" id="appt" min="09:00" max="17:00" step="1800">

<label for="meeting">Meeting:</label>
<input type="datetime-local" id="meeting">

<label for="month">Pick a month:</label>
<input type="month" id="month">

<label for="week">Pick a week:</label>
<input type="week" id="week">

Number & Range-Inputs

type='number' bietet ein Spinner-Control mit Up/Down-Pfeilen. min, max und step schränken Werte ein. Für Währung step='0.01' verwenden. type='range' rendert einen Slider — immer mit einem <output> oder sichtbaren Label paaren, das den aktuellen Wert zeigt, da der Wert standardmäßig nicht angezeigt wird. Number-Inputs filtern nicht-numerische Eingaben, erlauben aber trotzdem einige invaliden Zeichen; server-seitig validieren. Für Mengen, die keinen Spinner brauchen, type='text' mit inputmode='numeric' und pattern-Validierung in Betracht ziehen.

html
<label for="qty">Quantity (1-100):</label>
<input type="number" id="qty" min="1" max="100"
       step="1" value="10">

<label for="price">Price ($):</label>
<input type="number" id="price" min="0" step="0.01"
       placeholder="0.00">

<label for="volume">Volume:</label>
<input type="range" id="volume" min="0" max="100"
       value="50" oninput="out.value=this.value">
<output id="out">50</output>

Color & File-Inputs

type='color' öffnet einen nativen Color-Picker und gibt einen Hex-Wert (#rrggbb) zurück. type='file' lässt User Dateien selektieren. Das accept-Attribut filtert nach MIME-Typ oder Erweiterung (image/*, .pdf, image/png). Das multiple-Attribut erlaubt das Selektieren mehrerer Dateien. Auf selektierte Dateien via der files-Eigenschaft (eine FileList) in JavaScript zugreifen. URL.createObjectURL() verwenden, um eine lokale Preview-URL für Bilder zu erstellen. Für große File-Uploads Chunked-Uploads oder die File API für Progress-Tracking in Betracht ziehen. Dateitypen und -größen immer server-seitig validieren.

html
<label for="color">Pick a color:</label>
<input type="color" id="color" value="#ff0000">

<label for="avatar">Upload avatar:</label>
<input type="file" id="avatar" accept="image/*">

<label for="docs">Upload documents:</label>
<input type="file" id="docs" accept=".pdf,.doc,.docx" multiple>

<!-- File input with image preview -->
<input type="file" accept="image/*" onchange="preview(this)">
<img id="preview-img" hidden>
<script>
function preview(input) {
  const file = input.files[0];
  if (file) {
    document.getElementById("preview-img").src =
      URL.createObjectURL(file);
    document.getElementById("preview-img").hidden = false;
  }
}
</script>

datalist (Input-Suggestions)

<datalist> bietet Autocomplete-Suggestions für Input-Felder. Mit einem Input via list-Attribut verlinken, das zur id der datalist passt. Anders als <select> können User weiterhin beliebige Werte eingeben — Suggestions sind optional. Funktioniert mit text, number, date, color und range-Inputs. Der Browser zeigt matchende Suggestions an, während der User tippt. Dies ist eine leichtgewichtige Alternative zu JavaScript-Autocomplete-Bibliotheken für einfache Anwendungsfälle. Hinweis: Stylen von Optionen innerhalb von datalist wird nicht unterstützt — sie rendern mit Browser-Defaults.

html
<label for="browser">Favorite browser:</label>
<input list="browsers" id="browser" name="browser">
<datalist id="browsers">
  <option value="Chrome">
  <option value="Firefox">
  <option value="Safari">
  <option value="Edge">
  <option value="Opera">
</datalist>

<!-- Works with various input types -->
<label for="color">Choose color:</label>
<input type="color" list="preset-colors" id="color">
<datalist id="preset-colors">
  <option value="#ff0000">
  <option value="#00ff00">
  <option value="#0000ff">
</datalist>

Form-Validierungs-Attribute

HTML5 bietet eingebaute Client-seitige Validierung via Attribute. required verhindert Submit, wenn leer. type='email'/'url' validieren Format automatisch. minlength/maxlength schränken Textlänge ein. min/max schränken Zahlen und Daten ein. pattern verwendet Regex für benutzerdefinierte Validierung. Der Browser zeigt Default-Error-Bubbles. Messages mit setCustomValidity() anpassen — aber immer bei Input clearen (setCustomValidity('')), um klebrige Errors zu vermeiden. Client-seitige Validierung verbessert UX, muss aber mit server-seitiger Validierung für Sicherheit gepaart werden, da sie umgangen werden kann.

html
<form>
  <label>Email: <input type="email" required></label>
  <label>Username:
    <input type="text" required minlength="3" maxlength="20"
           pattern="[a-zA-Z0-9_]+">
  </label>
  <label>Age:
    <input type="number" min="18" max="120" required>
  </label>
  <label>Website:
    <input type="url" placeholder="https://example.com">
  </label>
  <button type="submit">Submit</button>
</form>

<!-- Custom validation message -->
<input type="text" required
  oninvalid="this.setCustomValidity('Please enter your name')"
  oninput="this.setCustomValidity('')">
16

Service Worker & PWA

Service Worker-Registrierung

Ein Service Worker ist eine JavaScript-Datei, die im Hintergrund läuft, getrennt von der Web-Page, und Offline-Support, Push-Notifications und Background-Sync ermöglicht. Von der Main-Page registrieren — muss über HTTPS serviert werden. Der Speicherort der Service-Worker-Datei bestimmt ihren Scope (sie kontrolliert Pages in ihrem Verzeichnis und Unterverzeichnissen). Registrierung ist asynchron und passiert nur einmal pro Scope. Nach dem ersten Besuch aktiviert sich der SW bei nachfolgenden Page-Loads. Das load-Event verwenden, um die Registrierung zu verzögern, bis nach dem die Page interaktiv ist.

html
<!-- Register a service worker in main page -->
<script>
if ("serviceWorker" in navigator) {
  window.addEventListener("load", () => {
    navigator.serviceWorker
      .register("/sw.js")
      .then((reg) => {
        console.log("SW registered:", reg.scope);
      })
      .catch((err) => {
        console.log("SW registration failed:", err);
      });
  });
}
</script>

Service Worker: Caching

Der Service-Worker-Lifecycle hat drei Phasen: install (Core-Assets cachen), activate (alte Caches cleanup), und fetch (Netzwerk-Anfragen abfangen). Die Cache-First-Strategie serviert gecachte Responses sofort und fällt auf Netzwerk zurück. Andere Strategien inkludieren Network-First (Netzwerk versuchen, auf Cache zurückfallen) und Stale-While-Revalidate (Cache servieren, im Hintergrund aktualisieren). CACHE_NAME bumpen, um Cache-Updates zu triggern. Die Cache-API speichert Request/Response-Paare. Service Worker laufen nur, wenn benötigt, und können vom Browser terminiert werden, um Speicher zu sparen.

html
// sw.js - Cache assets for offline use
const CACHE_NAME = "my-app-v1";
const ASSETS = ["/", "/index.html", "/style.css", "/app.js"];

// Install: cache core assets
self.addEventListener("install", (e) => {
  e.waitUntil(
    caches.open(CACHE_NAME).then((cache) => cache.addAll(ASSETS))
  );
});

// Fetch: serve from cache, fall back to network
self.addEventListener("fetch", (e) => {
  e.respondWith(
    caches.match(e.request).then((cached) => {
      return cached || fetch(e.request);
    })
  );
});

// Activate: clean old caches
self.addEventListener("activate", (e) => {
  e.waitUntil(
    caches.keys().then((keys) =>
      Promise.all(
        keys.filter((k) => k !== CACHE_NAME)
            .map((k) => caches.delete(k))
      )
    )
  );
});

Web App Manifest

Das Web App Manifest ist eine JSON-Datei, die eine Web-App installierbar macht (Add to Home Screen). name ist der vollständige Name; short_name erscheint auf dem Home-Screen-Icon. display:'standalone' versteckt die Browser-UI und lässt es wie eine native App aussehen. theme_color beeinflusst die Browser-Chrome-Farbe. icons müssen mindestens 192px- und 512px-Größen inkludieren. 'purpose':'maskable' lässt Android das Icon an unterschiedliche Formen anpassen. Ein valides Manifest plus ein registrierter Service Worker sind die Mindestanforderungen für eine PWA. Mit Lighthouse auf PWA-Compliance testen.

html
<!-- Link the manifest in HTML -->
<link rel="manifest" href="manifest.json">

<!-- manifest.json -->
{
  "name": "My PWA App",
  "short_name": "MyApp",
  "start_url": "/",
  "display": "standalone",
  "background_color": "#ffffff",
  "theme_color": "#1976d2",
  "orientation": "portrait",
  "icons": [
    {
      "src": "/icon-192.png",
      "sizes": "192x192",
      "type": "image/png"
    },
    {
      "src": "/icon-512.png",
      "sizes": "512x512",
      "type": "image/png",
      "purpose": "maskable"
    }
  ]
}

Push-Notifications

Push-Notifications lassen dich User re-engagen, selbst wenn der Tab geschlossen ist. Zuerst Permission mit Notification.requestPermission() anfragen. Dann via PushManager subscriben — das Subscription-Objekt enthält eine Endpoint-URL und Keys. Diese Subscription an den Server senden, der sie verwendet, um Push-Messages via der Web Push API zu senden (mit VAPID-Keys für Authentifizierung). Der Push-Event-Handler des Service Workers zeigt die Notification. userVisibleOnly:true bedeutet, dass jeder Push eine Notification zeigen muss (keine silent Pushes). Erfordert HTTPS und einen Service Worker.

html
<!-- Request notification permission -->
<button onclick="subscribe()">Enable Notifications</button>

<script>
async function subscribe() {
  const permission = await Notification.requestPermission();
  if (permission !== "granted") return;

  const reg = await navigator.serviceWorker.ready;
  const subscription = await reg.pushManager.subscribe({
    userVisibleOnly: true,
    applicationServerKey: urlBase64ToUint8Array(VAPID_KEY)
  });
  // Send subscription to your server
  await fetch("/api/subscribe", {
    method: "POST",
    body: JSON.stringify(subscription)
  });
}
</script>

<!-- In sw.js: handle push events -->
self.addEventListener("push", (e) => {
  const data = e.data.json();
  e.waitUntil(
    self.registration.showNotification(data.title, {
      body: data.body,
      icon: "/icon-192.png",
      badge: "/badge.png"
    })
  );
});

Background Sync

Background Sync lässt dich Aktionen aufschieben, bis der User stabile Konnektivität hat. Wenn man ein Sync-Event registriert, feuert der Browser es, wenn Konnektivität wiederhergestellt ist — selbst wenn der User den Tab geschlossen hat. Der Sync-Event-Handler (im Service Worker) führt die aufgeschobene Arbeit aus. Wenn die Arbeit einen Error wirft, versucht der Browser automatisch mit exponentiellem Backoff erneut. e.tag identifiziert den Sync-Typ — nur ein Sync pro Tag wird gequeued. IndexedDB verwenden, um pending Daten zu speichern. Ideal für Messaging-Apps, Form-Submissions und Daten-Sync. Periodic Sync (für regelmäßige Updates) ist in Chrome verfügbar, aber nicht allen Browsern.

html
// Register a sync event from the page
navigator.serviceWorker.ready.then((reg) => {
  return reg.sync.register("send-messages");
});

// Handle sync in sw.js
self.addEventListener("sync", (e) => {
  if (e.tag === "send-messages") {
    e.waitUntil(sendPendingMessages());
  }
});

async function sendPendingMessages() {
  const messages = await getMessagesFromIndexedDB();
  for (const msg of messages) {
    try {
      await fetch("/api/messages", {
        method: "POST",
        body: JSON.stringify(msg)
      });
      await deleteMessageFromIndexedDB(msg.id);
    } catch (err) {
      throw err; // triggers retry
    }
  }
}
17

Meta-Tags Deep Dive (Open Graph & Twitter)

Open Graph-Tags (Facebook)

Open Graph (OG)-Tags steuern, wie die Page erscheint, wenn auf Facebook, LinkedIn und den meisten sozialen Plattformen geteilt. og:title ist die Headline; og:description ist die Summary; og:image ist das Preview-Bild (empfohlen 1200x630px). og:type (website, article, video.movie) beeinflusst Rendering. Für Articles article:published_time, article:author und article:section für reichhaltigere Previews hinzufügen. og:image-Dimensionen immer angeben für schnelleres Rendering. Mit Facebooks Sharing Debugger testen. OG-Tags sind essenziell für Social-Media-Marketing und Click-Through-Rates.

html
<head>
  <meta property="og:title" content="My Awesome Article">
  <meta property="og:description" content="A deep dive into modern web development.">
  <meta property="og:type" content="article">
  <meta property="og:url" content="https://example.com/article">
  <meta property="og:image" content="https://example.com/img/og.jpg">
  <meta property="og:image:width" content="1200">
  <meta property="og:image:height" content="630">
  <meta property="og:site_name" content="My Website">
  <meta property="og:locale" content="en_US">
  <meta property="article:published_time" content="2025-01-15T08:00:00Z">
  <meta property="article:author" content="Jane Doe">
</head>

Twitter Card-Tags

Twitter Card-Tags steuern, wie Links auf X (Twitter) erscheinen. twitter:card-Typ kann 'summary' (kleines Bild), 'summary_large_image' (großes Bild über Text), 'player' (Video/Audio) oder 'app' sein. twitter:site ist das @handle der Site; twitter:creator ist das @handle des Autors. Das Bild sollte mindestens 300x157px (summary) oder 600x314px (large image) sein. twitter:image:alt verbessert Accessibility. Mit Twitters Card Validator testen. Selbst wenn OG-Tags vorhanden sind, geben Twitter-spezifische Tags mehr Kontrolle über Twitter-Previews.

html
<head>
  <meta name="twitter:card" content="summary_large_image">
  <meta name="twitter:site" content="@mywebsite">
  <meta name="twitter:creator" content="@janedoe">
  <meta name="twitter:title" content="My Awesome Article">
  <meta name="twitter:description" content="A deep dive into modern web dev.">
  <meta name="twitter:image" content="https://example.com/img/twitter.jpg">
  <meta name="twitter:image:alt" content="Article cover image">
</head>

Viewport & Mobile Meta

Das Viewport-Meta-Tag ist kritisch für responsives Design — ohne es rendern mobile Browser Pages in Desktop-Breite und zoomen heraus. width=device-width matcht die Gerätebreite; initial-scale=1 setzt den Zoom-Level. User-Zoom deaktivieren vermeiden (user-scalable=no), da es WCAG-Accessibility-Guidelines verletzt. apple-mobile-web-app-capable macht die App Full-Screen, wenn zum iOS-Home-Screen hinzugefügt. theme-color beeinflusst die Browser-Address-Bar-Farbe auf mobilem Chrome und Safari. Diese Mobile-spezifischen Tags verbessern die PWA- und Mobile-Experience signifikant.

html
<head>
  <!-- Responsive viewport -->
  <meta name="viewport"
        content="width=device-width, initial-scale=1.0">

  <!-- Disable zoom (accessibility concern — avoid) -->
  <meta name="viewport"
        content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">

  <!-- iOS Safari: full-screen web app -->
  <meta name="apple-mobile-web-app-capable" content="yes">
  <meta name="apple-mobile-web-app-status-bar-style"
        content="black-translucent">
  <meta name="apple-mobile-web-app-title" content="MyApp">

  <!-- Android Chrome theme color -->
  <meta name="theme-color" content="#1976d2">
</head>

HTTP-Equiv & Charset

http-equiv-Meta-Tags simulieren HTTP-Header direkt in HTML. charset muss das erste Element in <head> und innerhalb der ersten 1024 Bytes sein, um Encoding-basierte XSS-Angriffe zu verhindern. http-equiv='refresh' leitet nach einer Verzögerung weiter — server-seitige Redirects für SEO bevorzugen. Content-Security-Policy via Meta ist limitiert (kein report-uri, kein frame-ancestors) — HTTP-Header bevorzugen. Cache-Control via Meta ist unzuverlässig — stattdessen HTTP-Header verwenden. X-UA-Compatible zwingt IE, seine neueste Rendering-Engine zu verwenden. Echte HTTP-Header gegenüber http-equiv bevorzugen, wenn möglich.

html
<head>
  <!-- Character encoding (must be first in head) -->
  <meta charset="UTF-8">

  <!-- Refresh/redirect after 5 seconds -->
  <meta http-equiv="refresh" content="5; url=https://example.com">

  <!-- Set content security policy -->
  <meta http-equiv="Content-Security-Policy"
        content="default-src 'self'; script-src 'self'">

  <!-- X-UA-Compatible for IE -->
  <meta http-equiv="X-UA-Compatible" content="IE=edge">

  <!-- Cache control -->
  <meta http-equiv="Cache-Control"
        content="no-cache, no-store, must-revalidate">
</head>

Structured Data (JSON-LD)

JSON-LD (JavaScript Object Notation for Linked Data) ist Googles empfohlenes Format für Structured Data. Es hilft Suchmaschinen, den Content zu verstehen, und ermöglicht Rich Snippets (Star-Ratings, Event-Daten, Breadcrumbs, FAQ-Akkordeons) in Suchergebnissen. Häufige Typen inkludieren Article, Product, Recipe, Event, LocalBusiness und FAQPage. Das Script in <head> mit type='application/ld+json' platzieren. Mit Googles Rich Results Test validieren. Structured Data garantiert keine Rich Snippets, macht aber eligible. Es ist ein mächtiges SEO-Tool für increasing Click-Through-Rates aus Suchergebnissen.

html
<head>
  <script type="application/ld+json">
  {
    "@context": "https://schema.org",
    "@type": "Article",
    "headline": "My Awesome Article",
    "author": {
      "@type": "Person",
      "name": "Jane Doe"
    },
    "datePublished": "2025-01-15",
    "image": "https://example.com/img/article.jpg",
    "publisher": {
      "@type": "Organization",
      "name": "My Website",
      "logo": {
        "@type": "ImageObject",
        "url": "https://example.com/logo.png"
      }
    }
  }
  </script>
</head>
18

Semantisches HTML Deep Dive

Article vs. Section vs. Div

Das Wählen des richtigen Container-Elements matters für Accessibility und SEO. <article> ist für Content, der unabhängig vertrieben werden könnte (Blog-Posts, News, Comments, Product Cards). <section> gruppiert thematisch verwandten Content — sollte immer ein Heading haben. <div> ist ein letzter Ausweg für Layout/Styling, wenn kein semantisches Element passt. Verschachtelte <article>-Elemente (wie Comments innerhalb eines Posts) sind valid. Die Daumenregel: wenn Content via RSS syndiziert werden könnte, <article> verwenden; wenn es ein thematisches Kapitel ist, <section> verwenden; wenn es rein für Layout ist, <div> verwenden.

html
<!-- <article>: self-contained, syndicable content -->
<article>
  <h2>Blog Post Title</h2>
  <p>Content that makes sense on its own...</p>
  <article><h3>Comment 1</h3><p>...</p></article>
</article>

<!-- <section>: thematic grouping with a heading -->
<section>
  <h2>Chapter 1: Introduction</h2>
  <p>Related content...</p>
</section>

<!-- <div>: generic container, no semantic meaning -->
<div class="layout-wrapper">
  <div class="grid-item">Styling hook only</div>
</div>

Figure & Figcaption

<figure> repräsentiert selbstständigen Content, der vom Haupt-Text referenziert wird — Bilder, Diagramme, Code-Listings oder Zitate. <figcaption> bietet eine Caption/Titel. Anders als ein plain <img> verlinkt figure/figcaption semantisch das Visuelle mit seiner Description. Screen-Reader kündigen Figures mit ihren Captions an. Figures können überall relativ zum Text positioniert werden, der sie referenziert. <figure> für jeden Content verwenden, der eine Caption hat und per Nummer referenziert wird (Figure 1, Listing 1). Für rein dekorative Bilder ein plain <img> mit leerem alt verwenden.

html
<figure>
  <img src="chart.png" alt="Sales growth chart showing 40% increase">
  <figcaption>
    Figure 1: Quarterly sales growth from Q1 to Q4 2025.
    Data source: Internal sales database.
  </figcaption>
</figure>

<!-- Figure can contain code blocks too -->
<figure>
  <pre><code>const x = 42;</code></pre>
  <figcaption>Listing 1: Variable declaration example</figcaption>
</figure>

Details & Summary (Disclosure)

<details> und <summary> erstellen native einklappbare (Akkordeon-)Sections ohne JavaScript. Klicken auf <summary> togglet den Content. Das open-Attribut macht es standardmäßig expandiert. Das toggle-Event feuert beim Expandieren/Kollabieren. Exzellent für FAQs, Settings-Panels und progressive Disclosure. Screen-Reader kündigen es als Disclosure-Widget an. Den Default-Dreieck-Marker mit CSS stylen (summary::-webkit-details-marker oder list-style). Für komplexe Interaktionen kann dennoch JavaScript benötigt werden, aber für einfache Toggles ist diese native Lösung ideal.

html
<!-- Native collapsible without JavaScript -->
<details>
  <summary>Click to expand FAQ</summary>
  <p>Here is the hidden answer that appears when expanded.</p>
</details>

<!-- Open by default -->
<details open>
  <summary>Already expanded</summary>
  <p>This content is visible on page load.</p>
</details>

<!-- Nested disclosures -->
<details>
  <summary>Level 1</summary>
  <details>
    <summary>Level 2</summary>
    <p>Deeply nested content</p>
  </details>
</details>

Time & Mark-Elemente

<time> wrapt menschenlesbare Daten/Zeiten mit einem maschinenlesbaren datetime-Attribut im ISO 8601-Format. Dies hilft Suchmaschinen, Kalendern und assistiven Technologien, Daten korrekt zu parsen. datetime unterstützt Daten (YYYY-MM-DD), Zeiten (HH:MM), Datetimes mit Zeitzone und Dauern (PT2H30M). <mark> repräsentiert Text, der für Relevanz hervorgehoben wurde, wie Search-Term-Matches. Anders als <strong> oder <em> (die Wichtigkeit/Emphasis anzeigen), zeigt <mark> kontextuelle Relevanz an. Beide Elemente verbessern semantische Bedeutung und SEO.

html
<!-- <time>: machine-readable dates/times -->
<p>Published on
  <time datetime="2025-01-15">January 15, 2025</time>
</p>
<p>Event at
  <time datetime="2025-03-20T14:30-05:00">2:30 PM EST</time>
</p>
<p>Duration:
  <time datetime="PT2H30M">2 hours 30 minutes</time>
</p>

<!-- <mark>: highlighted/relevant text -->
<p>Search results: the keyword
  <mark>HTML5</mark> appears in 3 documents.
</p>

Dialog-Element

Das <dialog>-Element bietet native Modale und nicht-modale Dialoge ohne Bibliotheken. showModal() öffnet es als Modal (mit Backdrop, blockiert Page-Interaktion); show() öffnet es nicht-modal. close() schließt es. form method='dialog' schließt den Dialog beim Submit, mit dem button-Wert als returnValue. Das ::backdrop-Pseudo-Element stylt das Modal-Overlay. ESC-Taste schließt modale Dialoge automatisch. Top-Layer-Rendering bedeutet, der Dialog erscheint über allem anderen Content unabhängig vom z-index. Das close-Event feuert nach dem Schließen. Dies ist mittlerweile gut unterstützt und ersetzt viele JavaScript-Modal-Bibliotheken.

html
<!-- Native modal dialog -->
<dialog id="myDialog">
  <h2>Confirm Action</h2>
  <p>Are you sure you want to proceed?</p>
  <form method="dialog">
    <button value="cancel">Cancel</button>
    <button value="confirm">Confirm</button>
  </form>
</dialog>

<button onclick="document.getElementById('myDialog').showModal()">
  Open Modal
</button>

<script>
const dialog = document.getElementById("myDialog");
dialog.addEventListener("close", () => {
  console.log("Dialog closed with:", dialog.returnValue);
});
// Close on backdrop click
dialog.addEventListener("click", (e) => {
  if (e.target === dialog) dialog.close();
});
</script>
19

Advanced Forms & Input

Fieldset & Legend

<fieldset> gruppiert verwandte Form-Controls, und <legend> bietet eine Caption für die Gruppe. Dies ist crucial für Accessibility — Screen-Reader kündigen die Legend vor jedem Control in der Gruppe an und provide Context. Das disabled-Attribut auf einem fieldset deaktiviert alle Controls darin. Fieldsets verbessern auch visuelle Organisation mit einem Default-Border. Für Radio-Buttons ist fieldset/legend der empfohlene Weg, die Gruppe zu labeln. Fieldsets nicht zu tief verschachteln, da es Screen-Reader-User verwirren kann.

html
<form>
  <fieldset>
    <legend>Shipping Address</legend>
    <label>Street: <input type="text" name="street" required></label>
    <label>City: <input type="text" name="city" required></label>
    <label>ZIP: <input type="text" name="zip" pattern="[0-9]{5}"></label>
  </fieldset>

  <fieldset disabled>
    <legend>Billing (same as shipping)</legend>
    <label>Card: <input type="text" name="card"></label>
  </fieldset>

  <fieldset>
    <legend>Subscription Plan</legend>
    <label><input type="radio" name="plan" value="free"> Free</label>
    <label><input type="radio" name="plan" value="pro" checked> Pro</label>
  </fieldset>
</form>

Output & Progress-Elemente

<output> zeigt das Ergebnis einer Berechnung — es hat eine Live-Beziehung mit Form-Inputs (via des for-Attributs). Es ist semantisch bedeutungsvoller als ein span für berechnete Werte. <progress> repräsentiert den Abschluss einer Task (value/max); ohne value zeigt es einen indeterminaten Spinner. <meter> repräsentiert einen skalaren Wert innerhalb eines bekannten Bereichs (wie Speicherplatz oder Test-Scores) — die low-, high- und optimum-Attribute definieren Schwellwerte, die die Farbe beeinflussen (grün/gelb/rot). Sowohl progress als auch meter haben eingebautes Styling, das nach Browser variiert, aber mit CSS angepasst werden kann.

html
<form oninput="result.value = parseInt(a.value) + parseInt(b.value)">
  <input type="number" id="a" value="10"> +
  <input type="number" id="b" value="20"> =
  <output name="result" for="a b">30</output>
</form>

<!-- Progress bar -->
<label>Downloading: <progress id="prog" value="70" max="100">70%</progress></label>

<!-- Meter (gauge within a range) -->
<label>Disk usage: <meter value="0.6" min="0" max="1" low="0.5" high="0.8" optimum="0.2">60%</meter></label>
<label>Score: <meter value="85" min="0" max="100" low="40" high="70" optimum="90">85</meter></label>

Form-Autocomplete

Das autocomplete-Attribut hilft Browsern, Forms mit gespeicherten User-Daten auszufüllen. Standardisierte Tokens verwenden: 'name', 'email', 'tel', 'street-address', 'address-level2' (city), 'postal-code', 'country'. Für Kreditkarten: 'cc-name', 'cc-number', 'cc-exp'. autocomplete='off' deaktiviert Autofill (obwohl Browser dies für nicht-sensible Felder ignorieren können). autocomplete='one-time-code' triggert SMS-Code-Autofill auf Mobile. Proper Autocomplete-Tokens verbessern Form-Completion-Rates und User-Experience drastisch. Sie helfen auch Password-Managern, Felder korrekt zu identifizieren.

html
<form autocomplete="on">
  <!-- Browser can autofill name -->
  <label>Name: <input type="text" name="name" autocomplete="name"></label>

  <!-- Email autofill -->
  <label>Email: <input type="email" name="email" autocomplete="email"></label>

  <!-- Address autofill tokens -->
  <fieldset>
    <legend>Address</legend>
    <input autocomplete="street-address">
    <input autocomplete="address-level2"> <!-- City -->
    <input autocomplete="postal-code">
    <input autocomplete="country">
  </fieldset>

  <!-- Disable autocomplete for sensitive field -->
  <label>SSN: <input type="text" autocomplete="off"></label>

  <!-- One-time code (SMS) -->
  <label>Code: <input type="text" autocomplete="one-time-code"></label>
</form>

Form-Submission-Methoden

GET hängt Form-Daten an die URL (sichtbar, bookmarkable, limitierte Länge) — für Searches und Filter verwenden. POST sendet Daten im Request-Body (nicht sichtbar, keine Längen-Limit) — für Erstellen/Aktualisieren von Daten verwenden. enctype='multipart/form-data' ist für File-Uploads erforderlich. Das name/value-Paar des Buttons wird beim Submit inkludiert — mehrere Submit-Buttons können unterschiedliche Aktionen via desselben Namens mit unterschiedlichen Werten triggern. Für AJAX-Submission das FormData-Objekt und fetch() verwenden. Für sensible Daten immer POST verwenden, da GET-Daten in Browser-History und Server-Logs erscheinen.

html
<!-- GET: data in URL query string -->
<form method="GET" action="/search">
  <input name="q" value="html5">
  <!-- URL: /search?q=html5 -->
</form>

<!-- POST: data in request body -->
<form method="POST" action="/submit" enctype="application/x-www-form-urlencoded">
  <input name="name" value="Alice">
</form>

<!-- File upload: multipart -->
<form method="POST" action="/upload" enctype="multipart/form-data">
  <input type="file" name="document">
</form>

<!-- Form with custom submit button -->
<form method="POST" action="/save">
  <button type="submit" name="action" value="save">Save</button>
  <button type="submit" name="action" value="publish">Publish</button>
</form>

Contenteditable & Spellcheck

contenteditable='true' macht jedes Element direkt im Browser editierbar — die Basis von Rich-Text-Editoren. spellcheck='true' aktiviert Browser-Spellchecking (rote Unterstreichung für Tippfehler). Für Code-Snippets spellcheck='false' setzen, um False Positives zu vermeiden. Das contenteditable-Attribut kann vererbt werden — Child-Elemente sind editierbar, außer auf 'false' gesetzt. Das Speichern von editierbarem Content erfordert JavaScript (z.B. in localStorage bei Input speichern). Einen vollständigen Rich-Text-Editor mit contenteditable zu bauen ist komplex (Paste, Formatierung, Cursor-Position handhaben) — Bibliotheken wie Quill, TipTap oder ProseMirror für Produktion in Betracht ziehen.

html
<!-- Editable div -->
<div contenteditable="true">
  Click to edit this text directly in the browser.
</div>

<!-- Editable with spellcheck -->
<p contenteditable="true" spellcheck="true">
  Typoos will be underlined in red.
</p>

<!-- Turn off spellcheck for code -->
<pre contenteditable="true" spellcheck="false">
  const varible = "code"; // no spellcheck
</pre>

<!-- Entire document editable -->
<body contenteditable="true">

<!-- Save editable content -->
<div id="note" contenteditable="true"
     oninput="localStorage.setItem('note', this.innerHTML)">
  <script>document.getElementById('note').innerHTML =
    localStorage.getItem('note') || '';</script>
</div>
20

SEO Meta-Tags

Open Graph-Tags

Open Graph-Tags (von Facebook erstellt) steuern, wie die Page erscheint, wenn auf Social Media geteilt. og:image sollte 1200x630px sein. Ohne diese Tags erfinden Plattformen Previews aus Page-Content, oft schlecht.

html
<meta property="og:title" content="My Awesome Article">
<meta property="og:description" content="A deep dive into modern web design.">
<meta property="og:image" content="https://example.com/cover.jpg">
<meta property="og:url" content="https://example.com/article">
<meta property="og:type" content="article">
<meta property="og:site_name" content="Example Site">

Twitter Cards

Twitter Card-Tags steuern, wie Links auf X/Twitter rendern. summary_large_image zeigt ein prominentes Bild über dem Titel; summary zeigt ein kleineres quadratisches Thumbnail. Der twitter:site-Tag linkt die Card zum Account.

html
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:site" content="@yoursite">
<meta name="twitter:title" content="My Article">
<meta name="twitter:description" content="A deep dive into web design.">
<meta name="twitter:image" content="https://example.com/cover.jpg">

Canonical & Robots

rel="canonical" verhindert Duplicate-Content-Strafen, indem auf die Master-URL gezeigt wird. Der robots-Meta-Tag leitet Crawler: noindex entfernt die Page aus Ergebnissen, nofollow blockiert Link-Following.

html
<!-- Canonical: tells search engines the preferred URL -->
<link rel="canonical" href="https://example.com/article">

<!-- Robots: control indexing -->
<meta name="robots" content="index, follow">
<meta name="robots" content="noindex, nofollow">
<meta name="robots" content="noindex, follow">

Structured Data (JSON-LD)

JSON-LD-Structured-Data hilft Suchmaschinen, Content zu verstehen, und ermöglicht Rich Results (Star-Ratings, Breadcrumbs, Event-Info). Schema.org definiert das Vokabular. Das Script-Tag in head oder body platzieren.

html
<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Article",
  "headline": "Modern Web Design",
  "author": { "@type": "Person", "name": "Jane Doe" },
  "datePublished": "2025-01-15",
  "image": "https://example.com/cover.jpg"
}
</script>

Meta Description & Viewport

Das Description-Meta-Tag beeinflusst Click-Through-Rate — unter 160 Zeichen halten. Das Viewport-Tag ist mandatory für responsives Design auf Mobile. theme-color stylt die Browser-UI-Bar. charset muss das erste Element in head sein.

html
<meta name="description" content="A concise 150-160 character summary that appears in search results.">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="theme-color" content="#4285f4">
<meta charset="UTF-8">
21

SVG-Grundlagen

Basis-Shapes

SVG zeichnet mit XML-Elementen. Shapes inkludieren rect, circle, ellipse, line, polyline und polygon. Anders als Raster-Bilder skalieren SVGs ohne Qualitätsverlust und können mit CSS gestylt werden. fill setzt Innenfarbe, stroke setzt Outline.

html
<svg width="200" height="150" xmlns="http://www.w3.org/2000/svg">
  <rect x="10" y="10" width="80" height="50" fill="steelblue"/>
  <circle cx="140" cy="40" r="30" fill="tomato"/>
  <line x1="10" y1="100" x2="180" y2="100" stroke="black" stroke-width="2"/>
  <ellipse cx="100" cy="120" rx="60" ry="20" fill="none" stroke="green"/>
</svg>

Paths

Das path-Element ist das mächtigste SVG-Primitive. Befehle: M (move), L (line), H/V (horizontal/vertikal), C (kubische Bezier), Q (quadratisch), A (Bogen), Z (close). Großbuchstaben = absolute Koordinaten, Kleinbuchstaben = relative.

html
<svg width="200" height="200">
  <!-- M=move, L=line, C=cubic bezier, Z=close -->
  <path d="M 10 10 L 100 10 L 100 100 Z" fill="none" stroke="black"/>
  <path d="M 10 150 C 50 50, 150 50, 190 150" stroke="red" fill="none"/>
  <path d="M 10 180 Q 100 120 190 180" stroke="blue" fill="none"/>
</svg>

Gruppen & Wiederverwendung

Elemente mit g gruppieren, um gemeinsame Attribute zu teilen oder gemeinsam zu transformieren. Wiederverwendbare Shapes innerhalb von defs definieren und mit use href="#id" referenzieren. Dies hält SVGs DRY und kleiner.

html
<svg width="200" height="200">
  <defs>
    <g id="star">
      <polygon points="50,5 61,39 98,39 68,61 79,95 50,75 21,95 32,61 2,39 39,39"/>
    </g>
  </defs>
  <use href="#star" x="0" y="0" fill="gold"/>
  <use href="#star" x="100" y="100" fill="orange"/>
</svg>

Text & Styling

SVG-Text ist echter Text — selektierbar, durchsuchbar und bei jeder Größe scharf. font-family, font-size, font-weight spiegeln CSS wider. text-anchor steuert horizontale Ausrichtung (start/middle/end).

html
<svg width="300" height="100">
  <text x="10" y="50" font-family="Arial" font-size="24" fill="navy">
    Hello SVG
  </text>
  <text x="150" y="80" font-size="16" font-weight="bold" text-anchor="middle">
    Centered Bold Text
  </text>
</svg>

Gradients & Patterns

Gradients werden in defs definiert und via fill="url(#id)" referenziert. linearGradient überträgt entlang einer Linie; radialGradient strahlt von einem Mittelpunkt aus. Jeder stop definiert eine Farbe bei einem Prozent-Offset.

html
<svg width="200" height="100">
  <defs>
    <linearGradient id="lg" x1="0%" y1="0%" x2="100%" y2="0%">
      <stop offset="0%" stop-color="red"/>
      <stop offset="100%" stop-color="blue"/>
    </linearGradient>
    <radialGradient id="rg">
      <stop offset="0%" stop-color="yellow"/>
      <stop offset="100%" stop-color="green"/>
    </radialGradient>
  </defs>
  <rect width="100" height="100" fill="url(#lg)"/>
  <rect x="100" width="100" height="100" fill="url(#rg)"/>
</svg>
22

Canvas

Shapes zeichnen

Die Canvas-API zeichnet Pixel auf ein canvas-Element via eines 2D-Rendering-Contexts. fillRect/strokeRect zeichnen Rechtecke; paths (beginPath, arc, lineTo) bauen komplexe Shapes vor fill() oder stroke(). Canvas ist Raster — Skalieren verwischt die Zeichnung.

html
const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d');

ctx.fillStyle = 'tomato';
ctx.fillRect(10, 10, 100, 50);

ctx.strokeStyle = 'navy';
ctx.lineWidth = 3;
ctx.strokeRect(130, 10, 80, 80);

ctx.beginPath();
ctx.arc(200, 150, 40, 0, Math.PI * 2);
ctx.fill();

Paths & Linien

Paths bauen Shapes Punkt für Punkt. moveTo startet einen neuen Sub-Path; lineTo fügt gerade Segmente hinzu; closePath verbindet zum Start. bezierCurveTo und quadraticCurveTo zeichnen Kurven mit Kontrollpunkten.

html
ctx.beginPath();
ctx.moveTo(50, 50);
ctx.lineTo(150, 50);
ctx.lineTo(100, 150);
ctx.closePath();
ctx.fillStyle = 'gold';
ctx.fill();
ctx.stroke();

// Bezier curves
ctx.beginPath();
ctx.moveTo(0, 200);
ctx.bezierCurveTo(100, 100, 200, 300, 300, 200);
ctx.stroke();

Bilder zeichnen

drawImage malt ein Bild, Video oder ein anderes Canvas. Die 9-Argument-Form cropt ein Source-Rechteck und malt es in ein Destination-Rechteck — nützlich für Sprite-Sheets. Vor dem Zeichnen auf onload warten.

html
const img = new Image();
img.src = 'photo.jpg';
img.onload = () => {
  ctx.drawImage(img, 0, 0);                    // full image
  ctx.drawImage(img, 0, 0, 200, 150);          // scaled
  ctx.drawImage(img, 50, 50, 100, 100, 300, 0, 100, 100); // cropped
};

Animation-Loop

requestAnimationFrame plant draw() einmal pro Browser-Repaint (~60fps) ein und pausiert, wenn der Tab hidden ist. clearRect wischt das Canvas jeden Frame, um Trails zu verhindern. Für Physik Bewegung mit Delta-Time multiplizieren für konsistente Geschwindigkeit.

html
let x = 0;
function draw() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  ctx.fillStyle = 'steelblue';
  ctx.fillRect(x, 50, 40, 40);
  x += 2;
  if (x > canvas.width) x = -40;
  requestAnimationFrame(draw);
}
requestAnimationFrame(draw);

Pixel-Manipulation

getImageData gibt ein Uint8ClampedArray roher RGBA-Pixel-Werte zurück (0-255 pro Kanal). Direkter Pixel-Zugriff ermöglicht Filter und Effekte. putImageData schreibt den modifizierten Buffer zurück. Dies ist langsam für große Canvases.

html
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = imageData.data; // RGBA bytes

for (let i = 0; i < data.length; i += 4) {
  const avg = (data[i] + data[i + 1] + data[i + 2]) / 3;
  data[i] = data[i + 1] = data[i + 2] = avg; // grayscale
}

ctx.putImageData(imageData, 0, 0);
23

Iframes & Embeds

Iframe-Grundlagen

Ein iframe bettet ein anderes Dokument in die aktuelle Page ein. Das title-Attribut ist für Accessibility erforderlich. loading="lazy" verschiebt das Laden bis nah zum Viewport. Immer width und height setzen, um Layout-Shift zu verhindern.

html
<iframe
  src="https://example.com/widget"
  width="600"
  height="400"
  title="Example Widget"
  loading="lazy"
  referrerpolicy="no-referrer">
</iframe>

Sandbox-Attribut

Das sandbox-Attribut schränkt Iframe-Fähigkeiten ein. Ein leerer Wert blockiert alles. Tokens hinzufügen, um Features zu re-aktivieren: allow-scripts, allow-forms, allow-same-origin, allow-popups. Niemals allow-scripts mit allow-same-origin für nicht vertrauenswürdigen Content kombinieren.

html
<!-- Locks down the iframe completely -->
<iframe src="untrusted.html" sandbox></iframe>

<!-- Selectively re-enable features -->
<iframe
  src="widget.html"
  sandbox="allow-scripts allow-same-origin allow-forms">
</iframe>

Embed & Object

embed und object sind Legacy-Elemente. object unterstützt Fallback-Content, der gezeigt wird, wenn die Ressource fehlschlägt. Moderne HTML5-Elemente (video, audio, picture) werden bevorzugt. iframe für HTML-Content verwenden, video für Video.

html
<!-- Embed for plugins/media -->
<embed src="video.mp4" type="video/mp4" width="400" height="300">

<!-- Object with fallback content -->
<object data="report.pdf" type="application/pdf" width="100%" height="600">
  <p>Your browser cannot display PDFs. <a href="report.pdf">Download</a></p>
</object>

<!-- Video with multiple sources -->
<video controls>
  <source src="movie.webm" type="video/webm">
  <source src="movie.mp4" type="video/mp4">
  Your browser does not support video.
</video>

postMessage-Kommunikation

postMessage ist der einzige Weg, über Iframe-Grenzen hinweg zu kommunizieren (unterschiedliche Origins). Immer die Target-Origin im dritten Argument angeben. Auf der Empfangs-Seite e.origin verifizieren, bevor der Message vertraut wird.

html
<!-- Parent page -->
<iframe id="f" src="child.html"></iframe>
<script>
  const frame = document.getElementById('f');
  frame.contentWindow.postMessage({ type: 'greet', text: 'Hi' }, 'https://example.com');

  window.addEventListener('message', (e) => {
    if (e.origin !== 'https://example.com') return;
    console.log('From child:', e.data);
  });
</script>

Responsive Iframes

Um Iframes responsiv zu machen (z.B. 16:9-Video), in einem Container mit padding-bottom gleich dem Aspect-Ratio-Prozentsatz wrappen (56.25% für 16:9). Das iframe absolut positionieren, um den Container zu füllen.

html
<div style="position:relative; padding-bottom:56.25%; height:0; overflow:hidden;">
  <iframe
    src="https://youtube.com/embed/abc"
    style="position:absolute; top:0; left:0; width:100%; height:100%; border:0;"
    title="Video"
    allowfullscreen>
  </iframe>
</div>
24

Performance-Optimierung

Resource Hints

Resource Hints sagen dem Browser, Verbindungen vorzubereiten oder Assets zu fetchen, bevor sie benötigt werden. preconnect wärmt DNS/TCP/TLS auf. preload fetcht kritische Current-Page-Assets früh. prefetch fetcht Next-Page-Ressourcen während Idle-Time.

html
<!-- Preconnect to a third-party origin -->
<link rel="preconnect" href="https://fonts.googleapis.com">

<!-- DNS prefetch for lower-priority origins -->
<link rel="dns-prefetch" href="https://analytics.example.com">

<!-- Preload critical assets -->
<link rel="preload" href="hero.webp" as="image">
<link rel="preload" href="/fonts/main.woff2" as="font" type="font/woff2" crossorigin>

<!-- Prefetch next page -->
<link rel="prefetch" href="/next-page.html">

Lazy Loading Bilder

loading="lazy" verschiebt das Laden von Offscreen-Bildern, bis der User nah scrollt. Immer width und height setzen, um Layout-Shift zu verhindern. Das picture-Element serviert moderne Formate (WebP/AVIF) mit JPG-Fallback.

html
<!-- Native lazy loading -->
<img src="photo.jpg" loading="lazy" width="800" height="600" alt="...">

<!-- Picture with responsive sources -->
<picture>
  <source srcset="small.webp" media="(max-width: 600px)" type="image/webp">
  <source srcset="large.webp" type="image/webp">
  <img src="large.jpg" loading="lazy" width="1200" height="800" alt="...">
</picture>

Script-Loading-Strategien

Ohne Attribute blockiert ein Script HTML-Parsing. async lädt parallel, führt aber sofort aus, wenn bereit — Reihenfolge nicht garantiert. defer lädt parallel und führt in Reihenfolge nach DOM-Parsing aus — am besten für Haupt-Scripts.

html
<!-- Normal: blocks HTML parsing -->
<script src="app.js"></script>

<!-- Async: downloads in parallel, runs ASAP -->
<script src="analytics.js" async></script>

<!-- Defer: downloads in parallel, runs after HTML parse -->
<script src="app.js" defer></script>

<!-- Module scripts defer by default -->
<script type="module" src="app.mjs"></script>

Critical CSS

Inlining von Critical CSS (Styles, die für Above-the-Fold-Content benötigt werden) eliminiert render-blockierende CSS-Requests und beschleunigt First Paint. Das restliche CSS lädt asynchron via des Preload-Tricks. Tools wie Critical extrahieren Critical CSS automatisch.

html
<!-- Inline above-the-fold CSS in head -->
<head>
  <style>
    body { margin: 0; font-family: sans-serif; }
    .hero { height: 100vh; background: #f0f0f0; }
  </style>
  <!-- Load the rest asynchronously -->
  <link rel="preload" href="full.css" as="style" onload="this.rel='stylesheet'">
  <noscript><link rel="stylesheet" href="full.css"></noscript>
</head>

Performance messen

Die Performance-API misst Real-User-Timing. Schlüsselmetriken: FCP (First Contentful Paint), LCP (Largest Contentful Paint), CLS (Cumulative Layout Shift), INP (Interaction to Next Paint). Lighthouse für Lab-Daten verwenden.

html
// PerformanceObserver for Core Web Vitals
new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    console.log(entry.name, entry.startTime);
  }
}).observe({ entryTypes: ['paint', 'largest-contentful-paint'] });

// Navigation timing
const [nav] = performance.getEntriesByType('navigation');
console.log('DOM Content Loaded:', nav.domContentLoadedEventEnd);
console.log('Load:', nav.loadEventEnd);
25

Forms Advanced

Input-Typen

HTML5-Input-Typen bieten eingebaute Validierung und UI. email/url validieren Format. number/date bieten Picker. color/range haben spezialisierte UI. accept filtert Dateitypen. Browser handhaben Validierung automatisch.

html
<input type="email" required>
<input type="url" placeholder="https://">
<input type="number" min="0" max="100" step="5">
<input type="date" min="2024-01-01">
<input type="color" value="#ff0000">
<input type="range" min="0" max="10">
<input type="file" accept="image/*">

Form-Validierung

required verhindert Submit, wenn leer. minlength/maxlength limitieren Länge. pattern verwendet Regex-Validierung. Der Browser verhindert Submit und zeigt Errors. Mit setCustomValidity und dem invalid-Event anpassen.

html
<form>
  <input type="text" required minlength="3" maxlength="20" pattern="[A-Za-z]+">
  <input type="email" required>
  <input type="submit" value="Submit">
</form>

Fieldset & Legend

fieldset gruppiert verwandte Form-Felder. legend bietet eine Caption. disabled auf fieldset deaktiviert alle Felder. Verbessert Accessibility durch Gruppierung verwandter Inputs. Screen-Reader kündigen die Legend für jedes Feld an.

html
<fieldset>
  <legend>Shipping Address</legend>
  <label>Street: <input type="text" name="street"></label>
  <label>City: <input type="text" name="city"></label>
</fieldset>
<fieldset disabled>
  <legend>Billing (disabled)</legend>
  <input type="text" name="billing">
</fieldset>

Datalist

datalist bietet Autocomplete-Suggestions für Input. User können selektieren oder frei tippen. Anders als select erlaubt es benutzerdefinierte Werte. Das list-Attribut linkt Input zu datalist via id. Nützlich für Search und Tags.

html
<label>Choose browser:
  <input list="browsers" name="browser">
</label>
<datalist id="browsers">
  <option value="Chrome">
  <option value="Firefox">
  <option value="Safari">
</datalist>

Output-Element

output zeigt berechnete Ergebnisse. Das for-Attribut linkt zu Input-IDs. Aktualisiert live mit Form-Änderungen. Kein JavaScript für einfache Berechnungen benötigt. Für Screen-Reader als Live-Region zugänglich.

html
<form oninput="result.value = parseInt(a.value) + parseInt(b.value)">
  <input type="number" id="a" value="0"> +
  <input type="number" id="b" value="0"> =
  <output name="result" for="a b">0</output>
</form>
26

Accessibility (a11y)

ARIA-Labels

aria-label bietet zugängliche Namen für Elemente ohne sichtbaren Text. aria-expanded zeigt Toggle-Zustand an. aria-controls linkt zum kontrollierten Element. ARIA nur verwenden, wenn HTML-Semantik unzureichend ist.

html
<button aria-label="Close menu" onclick="closeMenu()">
  <svg>...</svg>
</button>
<nav aria-label="Main navigation">...</nav>
<button aria-expanded="false" aria-controls="menu">Menu</button>

Landmark-Rollen

Landmark-Rollen helfen Screen-Reader-Usern zu navigieren. Die meisten semantischen Elemente haben implizite Rollen. Explizite Rollen nur hinzufügen, wenn benötigt. role="search" auf einem Form erstellt eine Search-Landmark. Rollen-Redundanz mit semantischen Elementen vermeiden.

html
<header role="banner">...</header>
<nav role="navigation">...</nav>
<main role="main">...</main>
<aside role="complementary">...</aside>
<footer role="contentinfo">...</footer>
<form role="search">...</form>

Focus-Management

Focus für Keyboard-User managen. Beim Öffnen von Modals Focus nach innen bewegen. Beim Schließen Focus zum Trigger zurückgeben. tabindex="-1" verwenden, um Elemente programmatisch focusable zu machen. Niemals Focus-Outlines ohne Ersatz entfernen.

html
<button id="open">Open</button>
<div id="modal" hidden>
  <button id="close">Close</button>
</div>
<script>
document.getElementById('open').onclick = () => {
  modal.hidden = false;
  document.getElementById('close').focus();
};
</script>

Skip-Links

Skip-Links lassen Keyboard-User repetitive Navigation umgehen. Visuell hidden bis fokussiert. Das href zeigt auf die Main-Content-ID. Essenziell für Accessibility-Compliance (WCAG). Verbessert Navigations-Effizienz.

html
<body>
  <a href="#main" class="skip-link">Skip to main content</a>
  <nav>...long navigation...</nav>
  <main id="main">...</main>
</body>
<style>
.skip-link { position: absolute; left: -9999px; }
.skip-link:focus { left: 0; }
</style>

Alt-Text

Alt-Text beschreibt Bilder für Screen-Reader. Leeres alt="" markiert dekorative Bilder (ignoriert). Content und Zweck beschreiben, nicht Aussehen. Für komplexe Bilder woanders eine längere Description bereitstellen. Niemals alt für Tooltips verwenden (title verwenden).

html
<!-- Informative image -->
<img src="chart.png" alt="Bar chart showing 30% increase in sales">
<!-- Decorative image -->
<img src="spacer.gif" alt="">
<!-- Complex image -->
<img src="diagram.png" alt="Network topology" longdesc="diagram-desc.html">
27

Häufige Fallstricke

Fehlender Alt-Text

Fehlender Alt-Text bricht Accessibility. Screen-Reader lesen den Dateinamen. "image" oder "photo" sind unhelpful. Content und Zweck beschreiben. Leeres alt="" markiert dekorative Bilder. Niemals das alt-Attribut komplett weglassen.

html
<!-- BAD: no alt -->
<img src="photo.jpg">
<!-- BAD: unhelpful alt -->
<img src="photo.jpg" alt="image">
<!-- GOOD: descriptive alt -->
<img src="photo.jpg" alt="Team meeting in conference room">
<!-- Decorative: empty alt -->
<img src="border.png" alt="">

Div-Suppe

Divs für alles zu verwenden entfernt semantische Bedeutung. Screen-Reader können nicht navigieren. SEO kann Content-Struktur nicht verstehen. Semantische Elemente verwenden: header, nav, main, article, section, aside, footer. div für Gruppierung ohne semantische Intention reservieren.

html
<!-- BAD: div for everything -->
<div class="header">...</div>
<div class="nav">...</div>
<div class="article">...</div>
<!-- GOOD: semantic elements -->
<header>...</header>
<nav>...</nav>
<article>...</article>

Inline-Styles

Inline-Styles mischen Content und Präsentation und machen Wartung schwer. Sie haben hohe Spezifität und überschreiben Stylesheets. Können nicht gecacht oder wiederverwendet werden. Klassen und externe Stylesheets verwenden. Inline-Styles für dynamische Werte reservieren.

html
<!-- BAD: inline styles -->
<div style="color: red; font-size: 16px;">Text</div>
<!-- GOOD: external CSS -->
<div class="error">Text</div>
<link rel="stylesheet" href="styles.css">

Button vs. Link

Buttons triggern Aktionen (save, delete, toggle). Links navigieren zu URLs. Links für Aktionen zu verwenden bricht Keyboard-Navigation (Space vs. Enter) und Semantik. Screen-Reader kündigen sie unterschiedlich an. type="button" verwenden, um Form-Submit zu verhindern.

html
<!-- BAD: link for actions -->
<a href="#" onclick="save()">Save</a>
<!-- GOOD: button for actions -->
<button type="button" onclick="save()">Save</button>
<!-- Link for navigation -->
<a href="/about">About</a>

Heading-Hierarchie

Headings erstellen eine Document-Outline. Keine Level überspringen (h1 zu h3). Eine h1 pro Page verwenden (Haupttitel). Screen-Reader-User navigieren nach Headings. Logische Hierarchie pflegen. CSS für visuelles Styling verwenden, nicht Heading-Level.

html
<!-- BAD: skip levels -->
<h1>Title</h1>
<h3>Subtitle</h3>  <!-- Skipped h2 -->
<!-- BAD: multiple h1 -->
<h1>Title</h1>
<h1>Another</h1>
<!-- GOOD: hierarchical -->
<h1>Main Title</h1>
<h2>Section</h2>
<h3>Subsection</h3>

Was this helpful?

Learning path

Learn from scratch

Learn this language from the ground up with structured lessons.