Files
uni/slides/dhbw/01_web_eng.md
T
libretech 0774b8652d dhbw 01: pruefungsleistung aktualisiert (100 basis + 15 bonus statt 75+10)
punkteverteilung nach source-of-truth (git.librete.ch/DHBW/pruefungsleistung):
- grundanforderungen 30p (projektgrundlagen 15 + praesentation 15)
- clean code 25p (struktur 10 + qualitaet 10 + doku 5)
- accessibility & ux 25p (a11y 15 + responsive 10) — neu
- technische umsetzung 20p — neu
- bonus max 15p (6 bereiche statt 8, je 5p)
2026-05-08 08:54:40 +02:00

1826 lines
40 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
marp: true
theme: gaia
paginate: true
backgroundColor: #fff
header: "Web Engineering – DHBW Stuttgart"
footer: "Michael Czechowski – SoSe 2026"
title: Web Engineering
---
<style>
:root {
--color-foreground: #1a1a2e;
--color-highlight: #d63384;
--color-dimmed: #4a4a6a;
}
section.invert {
--color-foreground: #fff;
}
section {
font-size: 1.4rem;
}
h1 {
color: #a02060;
}
section.invert h1 {
color: #fff;
}
h2 {
color: #1f2937;
}
section.invert h2 {
color: #f48fb1;
}
pre {
background: #0f0f23;
color: #f48fb1;
border-radius: 8px;
border-left: 3px solid #d63384;
}
pre code {
background: transparent;
color: inherit;
}
code {
background: #1a1a2e;
color: #f48fb1;
padding: 0.15em 0.4em;
border-radius: 4px;
}
a {
color: var(--color-highlight);
}
</style>
<!-- _class: invert -->
<!-- _header: '' -->
<!-- _backgroundColor: #000 -->
![bg cover opacity:0.2](./assets/background.png)
# Web Engineering
**DHBW Stuttgart** · Informatik / Wirtschaftsinformatik
**Sommersemester 2026**
---
# Ressourcen zum Selbstlernen
- **CODE CRISPIES** — [codecrispi.es](https://codecrispi.es/)
- **Online Code-Editor** — [codepen.io](https://codepen.io/pen/)
- **MDN** (Mozilla Developer Network) — [developer.mozilla.org/de/](https://developer.mozilla.org/de/)
- **Flexbox-Spiel** — [flexboxfroggy.com](https://flexboxfroggy.com/)
- **Grid-Spiel** — [cssgridgarden.com](https://cssgridgarden.com/)
---
<!-- _class: lead -->
# Herzlich Willkommen!
## 1. Sitzung: 08.05.2026
---
# Über mich
![bg right:33% fit](./assets/logos/collage.png)
**Michael Werner Czechowski**
- Systems and Platform Engineer
- Schwerpunkte:
- Web-Technologien, Barriere-Armut, Open Source
- Hintergrund:
- Philosophie (Uni Stuttgart)
- Wirtschaftsinformatik (Leibniz-FH Hannover)
- Honorardozent (DHBW Stuttgart, HdM Stuttgart, Leibniz-FH)
- Kontakt: michael.czechowski@lehre.dhbw-stuttgart.de
---
# Vorlesungsplan
<style scoped>
.lp-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 10px;
margin-top: 0.5rem;
}
.lp-card {
border: 1px solid #d63384;
border-radius: 8px;
padding: 10px 12px;
background: #fff;
font-size: 0.95em;
display: flex;
flex-direction: column;
gap: 4px;
}
.lp-card .head {
font-weight: bold;
color: #a02060;
display: flex;
justify-content: space-between;
align-items: baseline;
font-size: 0.85em;
}
.lp-card .head .num {
font-size: 1.1em;
}
.lp-card .topic {
color: #1a1a2e;
line-height: 1.25;
}
.lp-card.milestone {
background: #fce4ec;
border-color: #a02060;
border-width: 2px;
}
.lp-card.milestone .topic {
font-weight: bold;
}
</style>
<div class="lp-grid">
<div class="lp-card"><div class="head"><span class="num">1</span><span>08.05.</span></div><div class="topic">Intro · Projektgruppen · Internet 101</div></div>
<div class="lp-card"><div class="head"><span class="num">2</span><span>15.05.</span></div><div class="topic">HTML und CSS (Frameworks)</div></div>
<div class="lp-card"><div class="head"><span class="num">3</span><span>22.05.</span></div><div class="topic">JS (Frameworks) und npm</div></div>
<div class="lp-card"><div class="head"><span class="num">4</span><span>29.05.</span></div><div class="topic">nodeJS: Scripting, Running, Building</div></div>
<div class="lp-card"><div class="head"><span class="num">5</span><span>05.06.</span></div><div class="topic">Express API, CRUD, Middlewares</div></div>
<div class="lp-card milestone"><div class="head"><span class="num">6</span><span>12.06.</span></div><div class="topic">Projektwerkstattbericht</div></div>
<div class="lp-card"><div class="head"><span class="num">7</span><span>19.06.</span></div><div class="topic">Testing (Unit · Integration · E2E)</div></div>
<div class="lp-card"><div class="head"><span class="num">8</span><span>26.06.</span></div><div class="topic">TypeScript</div></div>
<div class="lp-card"><div class="head"><span class="num">9</span><span>03.07.</span></div><div class="topic">Docker · Proxies · DBs</div></div>
<div class="lp-card"><div class="head"><span class="num">10</span><span>10.07.</span></div><div class="topic">Wrap-up & Projektsupport</div></div>
<div class="lp-card milestone"><div class="head"><span class="num">11</span><span>17.07.</span></div><div class="topic">Präsentation</div></div>
</div>
---
# Prüfungsleistung – Übersicht
Eigenes Projekt: **Web-App** ODER **Backend** (API/CLI).
| Punkte | Bereich |
|--------|---------|
| 30 | Grundanforderungen (Projektgrundlagen + Präsentation) |
| 25 | Clean Code Prinzipien |
| 25 | Accessibility & UX |
| 20 | Technische Umsetzung |
| **100** | **Basispunkte** |
| +15 | Bonuspunkte (max. 3 Features a 5 P.) |
---
# Prüfungsleistung – Grundanforderungen (30 P.)
**Projektgrundlagen (15 P.)**
- Funktionsfähige Anwendung (8 P.)
- Repository mit Versionskontrolle (4 P.)
- Projektdokumentation / README (3 P.)
**Präsentation (15 P.)**
- Elevator Pitch (5 P.)
- Technische Präsentation (5 P.)
- Projektevolution: wie hat sich das Projekt vs. Ursprungsidee verändert? (5 P.)
---
# Prüfungsleistung – Clean Code (25 P.)
**Projektstruktur (10 P.)**
- Ordnerstruktur (5 P.)
- Datei-Organisation (5 P.)
**Code-Qualität (10 P.)**
- KISS – Keep It Simple, Stupid (3 P.)
- Beschreibende Namen (3 P.)
- Funktionsverantwortlichkeiten (4 P.)
**Kommentierung & Dokumentation (5 P.)**
---
# Prüfungsleistung – Accessibility & UX (25 P.)
**Web Accessibility (15 P.)**
- Semantisches HTML (5 P.)
- ARIA Labels & Alt-Texte (5 P.)
- Tastaturnavigation (5 P.)
**Responsive Design (10 P.)**
- Mobile First Approach (5 P.)
- Flexbox/Grid Layout (5 P.)
---
# Prüfungsleistung – Technische Umsetzung (20 P.)
- Plattformunabhängigkeit (5 P.)
- Package Management (5 P.)
- Build Tools & Optimierung (5 P.)
- Live-Demo (5 P.)
---
# Prüfungsleistung – Bonuspunkte (max. 15 P.)
Mindestens 2 Bereiche wählen, je 5 Punkte:
- API Integration
- Local Storage / State Management
- Progressive Web App Features
- Testing
- Erweiterte Responsive Features (3+ Breakpoints)
- Security Features
---
# Prüfungsleistung – Abgabe & Termine
- **Code-Upload:** bis 27.07.
- **Präsentation:** 17.07. (Gruppen, ~10 Min.)
Details: https://git.librete.ch/DHBW/pruefungsleistung
---
# Internet-Timeline
| Jahr | Meilenstein |
|------|-------------|
| **1966** | ARPANET-Projekt startet (DARPA) |
| **1969** | Erste Verbindung zwischen UCLA und Stanford |
| **1974** | TCP/IP-Protokoll entwickelt |
| **1989** | Tim Berners-Lee erfindet das WWW (CERN) |
| **1993** | Mosaic — erster grafischer Browser |
| **1994** | W3C gegründet (HTML, CSS, SVG, WCAG) |
| **1995** | ECMAScript / JavaScript wird Standard |
| **2008** | V8 JavaScript Engine (Chrome / Node.js) |
---
<!-- _header: '' -->
<!-- _footer: '' -->
![bg fit](./assets/arpanet.jpg)
---
# Das WWW (1989)
**Tim Berners-Lee** am **CERN** (Genf)
**Problem:** Wissenschaftler:innen können Forschungsdokumente nicht verlinken — Inkompatible Systeme, kein gemeinsames Format.
**Lösung — drei Bausteine:**
- **HTML** — Auszeichnungssprache für Dokumente
- **HTTP** — Protokoll zur Übertragung
- **URL** — eindeutige Adressen
**1991:** erste Webseite geht online · 1993 vom CERN gemeinfrei freigegeben.
→ WWW ≠ Internet. Das WWW ist eine **Anwendung auf** dem Internet.
---
<!-- _header: '' -->
<!-- _footer: '' -->
![bg fit](./assets/mosaic.jpg)
---
<!-- _header: '' -->
<!-- _footer: '' -->
![bg cover](./assets/img_633d7b91366e0-1025x538-768x403.jpg)
---
# Heute: Physische Infrastruktur
- **5,5 Milliarden** Menschen online
- **> 400 Unterseekabel**, ca. **1,3 Mio. km** Glasfaser
- Daten reisen mit **Lichtgeschwindigkeit**
- Latenz Frankfurt — New York: ~80 ms
→ Keine "Cloud" ohne Kabel. Das Internet ist **physische** Infrastruktur — und damit angreifbar.
**Geopolitik:** Five-Eyes-Allianz (USA, UK, CA, AU, NZ) zapft Unterseekabel ab (Programm "Tempora", aufgedeckt 2013 durch Snowden). DE ist Teil der Fourteen Eyes.
---
<!-- _header: '' -->
<!-- _footer: '' -->
![bg fit](./assets/demos/browser-server-sequence.png)
---
# HTTP – Hypertext Transfer Protocol
**Request:**
```
GET /products HTTP/1.1
Host: localhost:8080
```
**Response:**
```
HTTP/1.1 200 OK
Content-Type: application/json
[{"id": 1, "name": "Produkt A"}, ...]
```
---
<!-- _class: invert -->
<!-- _header: '' -->
<!-- _backgroundColor: #000 -->
# Onboarding
## Tools, Runtimes, Workflows
---
# Werkzeuge & Betriebssystem
**Erforderliche Werkzeuge:**
- **Terminal** (zsh / bash / fish / pwsh) — Kommandozeile
- **Editor** (siehe folgende Folie)
- **JavaScript-Runtime** (Node.js / Bun / Deno)
- **Browser mit DevTools** (Chromium / Firefox / Safari)
- **Git** — verteiltes Versionskontrollsystem (Stand der Industrie)
**OS-Empfehlung:**
| OS | Status |
|----|--------|
| **macOS** | First-class, viele Tools "just work" |
| **Linux** | First-class, beste Server-Parität |
| **Windows + WSL2** | Empfohlen — Windows-CLI hat Edge Cases |
| **Windows nativ** (PowerShell) | Funktioniert, aber holpriger Pfad |
---
# Node.js installieren – macOS
Empfohlen: **LTS** (aktuell **Node.js 24** — Stand 2026).
Paketmanager: **[Homebrew](https://brew.sh)**
```bash
# Homebrew installieren (falls nicht vorhanden)
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
# Node.js LTS installieren
brew install node@24
# Version prüfen
node --version
npm --version
```
Alternative: Installer von [nodejs.org](https://nodejs.org)
---
# Node.js installieren – Linux
Empfohlen: **LTS** (aktuell **Node.js 24**).
**Debian / Ubuntu** ([NodeSource](https://github.com/nodesource/distributions)):
```bash
curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash -
sudo apt install -y nodejs
```
**Arch / Manjaro:**
```bash
sudo pacman -S nodejs npm
```
**Fedora / RHEL:**
```bash
sudo dnf module install nodejs:24/common
```
→ Distro-Pakete sind oft **veraltet**. Versionsmanager (folgende Folie) bevorzugen.
---
# Node.js installieren – Windows
Empfohlen: **LTS** (aktuell **Node.js 24**).
**Option 1: winget** (empfohlen, Win 10/11):
```powershell
winget install OpenJS.NodeJS.LTS
```
**Option 2: Chocolatey** ([chocolatey.org](https://chocolatey.org)):
```powershell
choco install nodejs-lts
```
**Option 3: Scoop** ([scoop.sh](https://scoop.sh)):
```powershell
scoop install nodejs-lts
```
**Option 4:** Installer von [nodejs.org](https://nodejs.org)
→ **Empfehlung:** WSL2 + Linux-Workflow nutzen.
---
# Direkt-Install: Wenn es eng wird
**Typisches Szenario** — drei parallele Projekte mit unterschiedlichen Anforderungen:
| Projekt | Stack | Node-Version |
|---------|-------|--------------|
| Praktikums-API | Express (Legacy) | 18.x (LTS Hydrogen) |
| Studienarbeit | Next.js 15 | 22.x (LTS Jod) |
| Aktuelles Lab-Projekt | neueste Features | 24.x (Iron, current LTS) |
System-Install kennt nur **eine** Node-Version global → Konflikt.
---
# Symptome im Alltag
- `npm install` bricht mit `engines`-Warning ab
- native Module (z. B. `node-sass`) bauen nicht
- CI-Pipeline ist grün, lokal rot — oder umgekehrt
- erheblicher Zeitverlust beim Debuggen von Versions-Konflikten
→ Lösung: **Versionsmanager** und Node-Version pro Projekt pinnen.
---
# Node-Versionsmanager
Verschiedene Projekte brauchen oft verschiedene Node-Versionen. **Lösung:** Versionsmanager.
| Tool | Sprache | Geschwindigkeit | Plattform |
|------|---------|-----------------|-----------|
| **nvm** | Bash | langsam (Shell-Funktion) | macOS, Linux |
| **fnm** | Rust | sehr schnell | macOS, Linux, Windows |
| **asdf** | Bash | mittel, multi-language | macOS, Linux |
| **volta** | Rust | schnell, pinning per `package.json` | alle |
```bash
# fnm
curl -fsSL https://fnm.vercel.app/install | bash
fnm install --lts # aktuell Node 24
fnm use lts-latest
# .nvmrc / .node-version automatisch
echo "lts/*" > .nvmrc
fnm use # liest .nvmrc
```
---
# Alternative Runtimes
| Runtime | Erschienen | Engine | USP |
|---------|------------|--------|-----|
| **Node.js** | 2009 | V8 (C++) | Standard, größtes Ökosystem |
| **Deno** | 2020 | V8 (Rust) | Sicherheit, TypeScript nativ, Std-Lib |
| **Bun** | 2022 | JavaScriptCore (Zig) | Geschwindigkeit, all-in-one |
```bash
# Deno
curl -fsSL https://deno.land/install.sh | sh
deno run main.ts
# Bun
curl -fsSL https://bun.sh/install | bash
bun install
bun run dev
```
→ Im Kurs primär **Node.js**. Bun und Deno sind ebenfalls zulässig.
---
# Editor
- **VS Code** (empfohlen) — kostenlos, große Plugin-Auswahl
- **JetBrains WebStorm** — sehr mächtig, kostenpflichtig
- kostenlos für Studierende via [JetBrains Education](https://www.jetbrains.com/community/education/#students)
- **Vim / Neovim / Emacs** — für CLI-Profis
- **Zed** — modern, schnell
---
# Browser DevTools
Chromium / Firefox / Safari — `F12` oder `Cmd+Opt+I`
<small>Chromium = Open-Source-Basis von Chrome, Edge, Brave, Opera, Vivaldi etc.</small>
**Wichtigste Panels:**
- **Network** — HTTP-Requests, Responses, Timing
- **Console** — `console.log`, JS-Errors, REPL
- **Elements** — DOM-Inspektor, Live-CSS-Editor
- **Sources** — Debugger, Breakpoints, Source-Maps
- **Performance** — Profiling, Frame-Rate, FPS
- **Application** — LocalStorage, Cookies, Service Workers
---
# HTTP-Clients
- **Bruno** ([usebruno.com](https://usebruno.com)) — open source, git-friendly
- **Hoppscotch** ([hoppscotch.io](https://hoppscotch.io)) — open source, browser-basiert (vormals Postwoman)
- **Insomnia** / **Postman** — etabliert, freemium
- **curl** / **httpie** — CLI (Command-Line Interface, scriptbar)
---
# Git Setup & Workflow
**Einmalige Konfiguration:**
```bash
git config --global user.name "Vorname Nachname"
git config --global user.email "vorname.nachname@example.com"
git config --global init.defaultBranch main
git config --global pull.rebase true
```
**SSH-Key für GitHub/GitLab:**
```bash
ssh-keygen -t ed25519 -C "vorname.nachname@example.com"
cat ~/.ssh/id_ed25519.pub # → in GitHub-Settings einfügen
```
**Tägliche Befehle:**
```bash
git status # was hat sich geändert?
git add <file> # für Commit vormerken
git commit -m "feat: ..." # Conventional Commits
git push # hochladen
git pull --rebase # neueste Änderungen holen
```
---
# Projekt-Skeleton
```bash
mkdir mein-projekt && cd mein-projekt
git init
npm init -y # erzeugt package.json
echo "node_modules" > .gitignore
echo ".env" >> .gitignore
npm install express
```
**`package.json` minimal:**
```json
{
"name": "mein-projekt",
"version": "0.1.0",
"type": "module",
"scripts": {
"start": "node index.js",
"dev": "node --watch index.js"
}
}
```
`.env` für Secrets (nie committen!), `.env.example` mit Dummy-Werten committen.
---
<!-- _class: invert -->
<!-- _header: '' -->
<!-- _backgroundColor: #000 -->
# HTML – Hypertext Markup Language
---
# Was ist HTML? (1/2)
**H**yper**T**ext **M**arkup **L**anguage
- **Keine** Programmiersprache
- Am ehesten eine Formattierungssprache
- Beschreibt **Struktur und Aufbau** einer Webseite
```html
<p>Das ist ein Absatz.</p>
<input type="date" />
```
Erfunden 1989 von Tim Berners-Lee. Aktuelle Version: HTML5 (seit 2014).
---
# Was ist HTML? (2/2)
- Mit HTML werden **HTML-Dokumente** beschrieben (`index.html`)
- Ein HTML-Dokument beschreibt das **Document Object Model (DOM)**
- Der DOM ist eine **hierarchische Baumstruktur** (Eltern, Kinder, Geschwister)
- *parent* nodes / elements
- *child* nodes / elements
- *sibling* nodes / elements
<small>In HTML sprechen wir von **Elementen**, in JavaScript eher von **Nodes**.</small>
---
# HTML-Anatomie (1/2)
```
Opening tag Closing tag
│ │
▼ ▼
<p> My cat is very grumpy </p>
└────────┬─────────┘
Content
└─────────────────────────────────┘
Element
```
- **Opening tag** + **Content** + **Closing tag** = **Element**
- Öffnende und schließende Tags müssen identisch sein
- Schließendes Tag hat ein `/` nach der Spitzklammer
---
# HTML-Anatomie — Attribute
```
Attribute
┌───────────────┐
<p class="editor-note"> My cat is very grumpy </p>
```
- **Attribute** stehen im opening tag
- Format: `name="wert"` (Anführungszeichen empfohlen)
- Mehrere Attribute durch Leerzeichen getrennt: `<input type="text" name="email" required>`
---
# HTML-Anatomie (2/2)
Wir unterscheiden **umschließende** und **selbst-schließende** Tags.
**Umschließend:**
- `<b> ... </b>` – fett-gedruckter Text (inline)
- `<a> ... </a>` – Hyperlink
- `<body> ... </body>` – sichtbarer Teil eines HTML-Dokuments
- `<details> ... </details>` – Aufklapp-Text / Akkordion
**Selbst-schließend:**
- `<img />` – Bild, Vektorgrafik
- `<input />` – Eingabefeld
- `<meta />` – Metadaten
---
# Darstellungsebene und Metadaten
```html
<html>
<head>
METADATEN
</head>
<body>
DARSTELLUNGSEBENE
</body>
</html>
```
Ein HTML-Dokument besteht aus zwei Teilen:
- `<head> ... </head>` – Metadaten für Browser, Suchmaschinen, Social Sharing
- `<body> ... </body>` – darzustellender Inhalt, Text, Formulare
---
# HTML Metadaten
```html
<html>
<head>
<title>DHBW Stuttgart</title>
<meta name="description" content="Studium mit Praxis" />
<meta property="og:image" content="https://...." />
</head>
...
</html>
```
<small>*Webseiten besuchen nicht nur Menschen, sondern auch Suchmaschinen, Bots, Screen-Reader. Metadaten helfen beim "Verstehen" der Inhalte.*</small>
---
# HTML Metadaten – Vertiefung
| Tag | Funktion |
|-----|----------|
| `<title>` | Browser-Tab, Suchergebnis-Titel |
| `<meta charset>` | Zeichenkodierung (Umlaute!) |
| `<meta viewport>` | Mobile Darstellung |
| `<meta description>` | Suchergebnis-Snippet (max 160 Zeichen) |
**Open Graph** (Social-Media-Vorschau):
```html
<meta property="og:title" content="Artikel-Titel">
<meta property="og:image" content="https://example.com/preview.jpg">
```
→ Wirkt auf Mastodon, LinkedIn, Signal, Slack, MS Teams ...
**SEO:** Google nutzt `<title>` + `<meta description>` für Ranking + Snippet.
---
# HTML-Tags und Attribute
![bg right:35%](./assets/demos/tag-attribut.png)
```html
<body>
<p class="wichtig">Das ist ein wichtiger Absatz.</p>
<p>Das ist ein gewöhnlicher Absatz.</p>
</body>
```
| Teil | Bezeichnung |
|------|-------------|
| `<p>` | Opening Tag |
| `class="wichtig"` | Attribut |
| `Das ist ein wichtiger Absatz.` | Inhalt |
| `</p>` | Closing Tag |
---
# HTML-Tags und Attribute (selbst-schließend)
![bg right:35%](./assets/demos/input-date.png)
```html
Geburtsdatum <input type="date" />
```
| Teil | Bezeichnung |
|------|-------------|
| `<input ...` | Eingabefeld |
| `type="date"` | Attribut *type* mit Wert *date* |
| `... />` | Schließendes `/` im (öffnenden) Tag |
---
# Vollständiges Grundgerüst
![bg right:35%](./assets/demos/grundgeruest.png)
```html
<!DOCTYPE html>
<html lang="de">
<head>
<title>Portfolio von ...</title>
<meta name="description" content="..." />
<meta property="og:image" content="https://...." />
</head>
<body>
<h1>Hallo Welt!</h1>
<p>Das ist mein erster Absatz.</p>
</body>
</html>
```
---
# Die wichtigsten Tags
| Tag | Bedeutung |
|-----|-----------|
| `<h1>` … `<h6>` | Überschriften (h1 = größte) |
| `<p>` | Absatz (Paragraph) |
| `<a href="..."> ... </a>` | Hyperlink |
| `<img src="..." />` | Bild |
| `<ul>`, `<ol>`, `<li>` | Listen |
| `<div>` | Container / Box |
| `<span>` | Inline-Container |
| `<input type="...">` | Eingabefeld |
<small>Semantische Tags (`<header>`, `<main>`, `<article>`, `<footer>`, `<nav>`, `<aside>`) wichtig für Accessibility.</small>
---
# Natives HTML
Was früher mit JavaScript gelöst wurde, kann HTML heute selbst. JS dafür einzusetzen ist heute oft ein **Code Smell**.
| Funktion | HTML-Element |
|----------|--------------|
| Aufklapp-Text | `<details>` + `<summary>` |
| Popup / Modal | `<dialog>` |
| Fortschrittsbalken | `<progress>` |
| Datum-Auswahl | `<input type="date">` |
| Validierung | Attribute: `required`, `min`, `max`, `pattern` |
---
# Beispiel: Details/Summary
<small>*Akkordion · Accordion · Aufklappmenü · Collapsible*</small>
![bg right:35%](./assets/demos/details-closed.png)
```html
<details>
<summary>Klick mich!</summary>
<p>Dieser Text ist versteckt.</p>
</details>
```
<small>Doku: [developer.mozilla.org](https://developer.mozilla.org/de/docs/Web/HTML/Reference/Elements/details)</small>
---
# Beispiel: Details/Summary (geöffnet)
![bg right:35%](./assets/demos/details-open.png)
```html
<details open>
<summary>Klick mich!</summary>
<p>Dieser Text war versteckt.</p>
</details>
```
---
# Beispiel: Button
![bg right:35%](./assets/demos/button.png)
```html
<button>Add to favorites</button>
```
<small>Doku: [developer.mozilla.org](https://developer.mozilla.org/de/docs/Web/HTML/Reference/Elements/button)</small>
---
# Beispiel: Input/Eingabefeld
![bg right:35%](./assets/demos/input.png)
```html
<input
type="text"
maxlength="8"
size="10" />
```
<small>Doku: [developer.mozilla.org](https://developer.mozilla.org/de/docs/Web/HTML/Reference/Elements/input)</small>
---
# Beispiel: Dialog
<small>*Modal · Modales Fenster · Popup · Overlay · Dialogfenster*</small>
![bg right:35%](./assets/demos/dialog.png)
```html
<dialog open>
<p>Greetings, one and all!</p>
<form method="dialog">
<button>OK</button>
</form>
</dialog>
```
<small>Doku: [developer.mozilla.org](https://developer.mozilla.org/de/docs/Web/HTML/Reference/Elements/dialog)</small>
---
<!-- _class: invert -->
<!-- _header: '' -->
<!-- _backgroundColor: #000 -->
# Barrierefreiheit
## Accessibility (a11y)
---
# Wie nutzen Menschen das Web?
| Eingabe | Nutzungsweise |
|---------|---------------|
| **Maus** | Klicken, Scrollen |
| **Tastatur** | Tab-Navigation, Enter, Pfeiltasten |
| **Screenreader** | NVDA, VoiceOver, TalkBack, Orca |
| **Sprachsteuerung** | "Klicke auf Anmelden" |
| **Augensteuerung** | Eye-Tracking |
| **Switch-Geräte** | Ein-/Aus-Schalter (motorische Einschränkungen) |
→ Nicht alle Menschen nutzen Maus oder Touchscreens gleichermaßen.
---
# Web-Zugänglichkeit — Statistik
WHO: ca. **15 % der Weltbevölkerung** mit Behinderung — über **1 Milliarde** potenzielle Nutzer:innen.
| Typ | Permanent | Temporär | Situativ |
|-----|-----------|----------|----------|
| Visuell | Blindheit | Augen-OP | Grelle Sonne |
| Motorisch | Amputation | Gebrochener Arm | Kind auf dem Arm |
| Auditiv | Taubheit | Ohrenentzündung | Laute Umgebung |
| Kognitiv | Legasthenie | Müdigkeit | Ablenkung |
**Curb-Cut-Effekt:** Bordsteinabsenkung für Rollstühle hilft auch Kinderwagen, Rollkoffern, Fahrrädern.
---
# Warum Barrierefreiheit?
**Rechtlich (DE / EU):**
- **EAA** — European Accessibility Act, in Kraft seit 28.06.2025
- **BFSG** — DE-Umsetzung des EAA, betrifft auch Privatwirtschaft
- **BITV 2.0** — Barrierefreie Informationstechnik-Verordnung (öff. Stellen)
- Bußgelder bis **100.000 €**
**Ethisch:** Teilhabe und digitale Inklusion.
**Praktisch:**
- Bessere UX für **alle** (mobile, ältere Menschen, situative Einschränkungen)
- SEO-Bonus durch semantisches HTML, Alt-Texte
- Größerer Markt — ca. 15 % der Bevölkerung
---
# WCAG: Der Standard
**W**eb **C**ontent **A**ccessibility **G**uidelines · Herausgeber: W3C / WAI
**Aktuell:** WCAG 2.2 (verbindlich seit Okt. 2023). WCAG 3 in Working-Draft.
**4 Prinzipien (POUR):**
| Prinzip | Bedeutung |
|---------|-----------|
| **P**erceivable | Wahrnehmbar — Inhalte müssen erkennbar sein |
| **O**perable | Bedienbar — Funktionen müssen nutzbar sein |
| **U**nderstandable | Verständlich — Inhalte müssen klar sein |
| **R**obust | Robust — funktioniert mit verschiedenen Technologien |
**Konformitätslevel:** A · **AA** (gesetzlicher Standard) · AAA
→ [w3.org/WAI/WCAG22/quickref](https://www.w3.org/WAI/WCAG22/quickref/)
---
# Perceivable: Wahrnehmbar
![bg right:35% fit](./assets/demos/contrast-levels.png)
**Texte:**
- **Kontrast:** mindestens 4,5:1 für normalen Text
- **Untertitel** für Videos
- Inhalte bei **200 % Zoom** noch nutzbar
**Textalternativen für Nicht-Text:**
```html
<img src="tankman.jpg"
alt="Ein Mann mit Einkaufstüten steht
allein vor einer Reihe Panzer —
Tiananmen, Peking, 5. Juni 1989">
```
→ Leeres `alt=""` für rein dekorative Bilder.
---
# Operable: Bedienbar
![bg right:35%](./assets/demos/a11y-focus.png)
**Tastaturzugänglich:**
```css
/* Fokus-Ring nur bei Tastatur-Navigation */
button:focus-visible {
outline: 3px solid #d63384;
outline-offset: 3px;
border-radius: 4px;
}
/* Anti-Pattern */
button:focus { outline: none; }
```
**Genügend Zeit:** Session-Timeouts ankündigen, Verlängerung ermöglichen.
**Kein Flackern:** maximal 3×/Sekunde (epileptische Anfälle vermeiden).
---
# Understandable: Verständlich
![bg right:35%](./assets/demos/a11y-error.png)
**Sprache angeben:**
```html
<html lang="de">
```
**Konsistente Navigation** — gleiche Elemente an gleicher Stelle.
**Fehler erklären:**
```html
<input type="email" aria-describedby="email-error">
<p id="email-error" role="alert">
Bitte eine gültige E-Mail-Adresse eingeben.
</p>
```
---
# Robust: Technisch solide
![bg right:35%](./assets/demos/a11y-semantic.png)
**Semantisches HTML:**
```html
<!-- Schlecht -->
<div class="button" onclick="...">Klick mich</div>
<!-- Gut -->
<button type="button">Klick mich</button>
```
**ARIA — nur wenn nötig:**
```html
<div role="tablist" aria-label="Produktkategorien">
<button role="tab" aria-selected="true">Schuhe</button>
<button role="tab" aria-selected="false">Jacken</button>
</div>
```
→ Erste ARIA-Regel: **wenn möglich, natives HTML nutzen**.
---
# Barrierefreiheit testen — Werkzeuge
**Automatisierte Tools** (finden ca. 30 % der Verstöße):
| Tool | Typ | Findet |
|------|-----|--------|
| [WAVE](https://wave.webaim.org/) | Browser-Extension | Kontrast, Struktur, Tab-Reihenfolge |
| [Lighthouse](https://developer.chrome.com/docs/lighthouse/overview) | Chrome DevTools | Performance + A11y-Audit |
| [axe DevTools](https://www.deque.com/axe/devtools/) | Browser-Extension | Detailanalyse, Regel-Engine |
| [Pa11y](https://pa11y.org/) | CLI | CI/CD-Integration |
**Screenreader (OS-nativ oder Open Source):**
| OS | Screenreader |
|----|--------------|
| macOS / iOS | VoiceOver (`Cmd + F5`) — builtin |
| Windows | [NVDA](https://www.nvaccess.org/) (OSS) · Narrator (builtin) |
| Linux | [Orca](https://orca.gnome.org/) — GNOME builtin |
| Android | TalkBack — builtin |
---
# Barrierefreiheit testen
Automatisierte Tools finden nur etwa **30 %** der Probleme. Manuelles Testen unverzichtbar — Gold-Standard: echte Nutzer:innen mit Assistiven Technologien.
**Tastatur-Test** — Maus weglegen, nur Tab / Shift+Tab / Enter / Pfeiltasten:
![w:900 center](./assets/demos/keyboard-a11y.png)
---
<!-- _class: invert -->
<!-- _header: '' -->
<!-- _backgroundColor: #000 -->
# CSS – Cascading Style Sheets
---
# Was ist CSS?
**C**ascading **S**tyle **S**heets
```css
p {
color: blue;
font-size: 16px;
}
```
- Trennt **Inhalt** (HTML) von **Darstellung** (CSS)
- "Cascading" = Regeln können überschrieben werden
- Eine CSS-Datei kann viele HTML-Seiten stylen
---
# CSS einbinden
**Option 1: Externe Datei** (empfohlen)
```html
<link rel="stylesheet" href="style.css">
```
**Option 2: Style-Tag**
```html
<style>p { color: blue; }</style>
```
**Option 3: Inline** (vermeiden)
```html
<p style="color: blue;">...</p>
```
→ Standard ist externe Datei. Inline vermeiden (schwer zu warten, keine Wiederverwendung).
---
# CSS-Anatomie
```css
/* ID selector */
#description {
color: orangered;
/* │ └──── Indicates the value of the expression
│
└──── Indicates the property of the expression */
}
```
- **Selector** — was wird gestylt (`#description` = Element mit `id="description"`)
- **Property** — welche Eigenschaft (`color`)
- **Value** — welcher Wert (`orangered`)
- **Declaration** — `property: value;` (Semikolon trennt Deklarationen)
- **Declaration block** — alles zwischen `{` und `}`
---
# Selektoren: Element
![bg right:35%](./assets/demos/css-selector-element.png)
```css
/* Alle <p>-Elemente */
p {
color: gray;
}
/* Mehrere Elemente gleichzeitig */
h1, h2, h3 {
font-family: sans-serif;
}
```
Element-Selektoren sind die einfachsten. Komma = "oder".
---
# Selektoren: Klasse
![bg right:35%](./assets/demos/css-selector-class.png)
```html
<p class="wichtig">Dieser Text ist wichtig.</p>
<p>Dieser nicht.</p>
```
```css
.wichtig {
color: red;
font-weight: bold;
}
```
**Punkt** vor dem Namen = Klasse. Beliebig oft anwendbar; ein Element kann mehrere Klassen haben.
---
# Selektoren: ID
![bg right:35%](./assets/demos/css-selector-id.png)
```html
<nav id="hauptnavigation">...</nav>
```
```css
#hauptnavigation {
background: #333;
padding: 1rem;
}
```
**Raute** vor dem Namen = ID.
**Hinweis:** IDs sollten **einmalig** pro Seite sein. In der Praxis: Klassen meist besser.
---
# Selektoren: Kombinationen
![bg right:35%](./assets/demos/css-combinators.png)
```css
/* Nachfahre (beliebig tief verschachtelt) */
article p { line-height: 1.6; }
/* Direktes Kind (eine Ebene) */
nav > a { text-decoration: none; }
/* Nächstes Geschwister */
h2 + p { font-size: 1.2rem; }
/* Element mit Klasse */
p.wichtig { color: red; }
```
---
# Spezifität: Welche Regel gewinnt?
![bg right:35%](./assets/demos/css-specificity.png)
| Selektor | Spezifität |
|----------|------------|
| Element (`p`) | 0,0,0,1 |
| Klasse (`.wichtig`) | 0,0,1,0 |
| ID (`#header`) | 0,1,0,0 |
| Inline (`style="..."`) | 1,0,0,0 |
```css
p { color: blue; } /* 0,0,0,1 */
.text { color: green; } /* 0,0,1,0 → gewinnt */
#intro { color: red; } /* 0,1,0,0 → gewinnt über beide */
```
---
# CSS Spezifität – Vertiefung
| Selektor | Inline | IDs | Klassen | Elemente | Gesamt |
|----------|--------|-----|---------|----------|--------|
| `p` | 0 | 0 | 0 | 1 | 0,0,0,1 |
| `.info` | 0 | 0 | 1 | 0 | 0,0,1,0 |
| `p.info` | 0 | 0 | 1 | 1 | 0,0,1,1 |
| `#header` | 0 | 1 | 0 | 0 | 0,1,0,0 |
| `#header .nav a` | 0 | 1 | 1 | 1 | 0,1,1,1 |
**Regeln:**
- Eine Klasse (0,0,1,0) schlägt **jede Anzahl** Elemente (0,0,0,99)
- Eine ID schlägt jede Anzahl Klassen
- `!important` bricht alles → vermeiden
**Best Practice:** Flache Spezifität. BEM-Methodik (`.block__element--modifier`) hält sie niedrig.
---
# Box-Modell
![bg right:42% fit](./assets/demos/box-model-diagram.png)
Jedes HTML-Element ist eine rechteckige **Box**.
**Schichten innen → außen:**
- **content** – Inhalt (Text, Bild)
- **padding** – Innenabstand
- **border** – Rahmen
- **margin** – Außenabstand
<small>Gesamt-Breite = `width + padding + border + margin`. Tipp: `box-sizing: border-box` rechnet padding + border mit ein.</small>
---
# Box-Modell: CSS
![bg right:35%](./assets/demos/css-box-model.png)
```css
.box {
width: 200px;
height: 100px;
padding: 20px;
border: 2px solid black;
margin: 10px;
}
```
**Wichtig:**
```css
* {
box-sizing: border-box;
}
```
→ width/height inkludiert padding + border.
---
# Farben
![bg right:35%](./assets/demos/css-colors.png)
CSS kennt fünf Notationen für Farben: **Keyword**, **Hex**, **RGB**, **RGBA** (mit Transparenz) und **HSL**.
```css
/* Keyword */
color: red;
color: rebeccapurple;
/* Hex */
color: #FF0000;
color: #F00;
/* RGB / RGBA */
color: rgb(255, 0, 0);
color: rgba(255, 0, 0, 0.5);
/* HSL */
color: hsl(0, 100%, 50%);
```
---
# Einheiten
| Einheit | Bedeutung |
|---------|-----------|
| `px` | Pixel (absolut) |
| `%` | Prozent vom Elternelement |
| `em` | Relativ zur Schriftgröße des Elements |
| `rem` | Relativ zur Schriftgröße des Root-Elements |
| `vw` / `vh` | Prozent der Viewport-Breite/-Höhe |
**Empfehlung:**
`rem` für Schrift, `%` oder `vw/vh` für Layout.
---
# Pseudo-Klassen
![bg right:35%](./assets/demos/css-pseudo-classes.png)
```css
/* Hover */
a:hover { color: red; }
/* Besuchter Link */
a:visited { color: purple; }
/* Fokussiertes Element */
input:focus { border-color: blue; }
/* Erstes/n-tes Kind */
li:first-child { font-weight: bold; }
li:nth-child(odd) { background: #eee; }
```
`:` vor dem Namen = Pseudo-Klasse.
---
# Pseudo-Elemente
![bg right:35%](./assets/demos/css-pseudo-elements.png)
```css
/* Vor dem Inhalt einfügen */
.required::before {
content: "* ";
color: red;
}
/* Erster Buchstabe */
p::first-letter {
font-size: 2em;
}
```
`::` = Pseudo-Element (erzeugt "virtuelles" Element)
`:` = Pseudo-Klasse (wählt existierendes Element im Zustand)
---
# Layout: Flexbox
```css
.container {
display: flex;
justify-content: space-between;
align-items: center;
gap: 1rem;
}
```
→ Eindimensionales Layout (Zeile *oder* Spalte). Tiefer in `02_css_extended`.
---
# Layout: Grid
```css
.grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20px;
}
```
→ Zweidimensionales Layout (Zeilen *und* Spalten gleichzeitig).
---
# Responsive Design
![bg right:35%](./assets/demos/css-responsive.png)
```css
/* Mobile First: Basis-Styles */
.container {
padding: 1rem;
}
/* Ab 768px (Tablet) */
@media (min-width: 768px) {
.container { padding: 2rem; }
}
/* Ab 1024px (Desktop) */
@media (min-width: 1024px) {
.container { padding: 3rem; }
}
```
---
# Responsive Design – Vertiefung
**Mobile First** ist Standard: Basis-CSS für kleine Screens, dann Erweiterungen.
| Breakpoint | Gerät | Media Query |
|------------|-------|-------------|
| < 576px | Smartphone (Portrait) | Basis |
| ≥ 576px | Smartphone (Landscape) | `@media (min-width: 576px)` |
| ≥ 768px | Tablet | `@media (min-width: 768px)` |
| ≥ 992px | Desktop | `@media (min-width: 992px)` |
| ≥ 1200px | Large Desktop | `@media (min-width: 1200px)` |
**Viewport-Meta-Tag (kritisch!):**
```html
<meta name="viewport" content="width=device-width, initial-scale=1">
```
**Moderne Alternativen:** `clamp()`, Container Queries, CSS Grid `auto-fit`/`auto-fill`.
---
<!-- _class: invert -->
<!-- _header: '' -->
<!-- _backgroundColor: #000 -->
# JavaScript
---
# ECMAScript
- **Ecma International** — European Computer Manufacturers Association
- Seit **1997** standardisiert als **ECMA-262**
- Implementierungen: **JavaScript** (Netscape, später Mozilla), **JScript** (Microsoft), **ActionScript** (Adobe Flash) etc.
- Aktuelle Version: **ECMAScript 2024 (ES15)**, jährliche Releases
**Browser-Kompatibilität:**
- Faustregel: **ES2017+** läuft in allen modernen Browsern
- Ältere Targets via Transpiler (Babel, esbuild, swc, tsc)
- Kompatibilitätstabelle: [kangax.github.io/compat-table](https://kangax.github.io/compat-table/)
---
# JavaScript Grundlagen
```javascript
// Variablen
let name = "Welt";
const alter = 25;
// Funktionen
function gruss(name) {
return `Hallo, ${name}!`;
}
// Arrow Functions
const add = (a, b) => a + b;
// Arrays
const arr = [1, 2, 3];
arr.map(x => x * 2); // [2, 4, 6]
```
---
# DOM Manipulation
```javascript
// Element auswählen
const title = document.querySelector('h1');
// Inhalt ändern
title.textContent = 'Neue Überschrift';
// Event Listener
button.addEventListener('click', () => {
alert('Geklickt!');
});
```
---
# Fetch API
```javascript
fetch('/api/products')
.then(res => res.json())
.then(data => {
console.log(data);
})
.catch(err => console.error(err));
```
---
# Async/Await
```javascript
async function loadProducts() {
try {
const res = await fetch('/api/products');
const data = await res.json();
return data;
} catch (err) {
console.error('Fehler:', err);
}
}
```
---
<!-- _header: '' -->
<!-- _footer: '' -->
<!-- _backgroundColor: #050517 -->
![bg fit](./assets/demos/web-engineering-mandala.png)
---
<!-- _backgroundColor: #050517 -->
<!-- _color: #e2e8f0 -->
# Web Engineering Mandala
Interaktive version: [nextlevelshit.github.io/web-engineering-mandala](https://nextlevelshit.github.io/web-engineering-mandala/)
3 Schichten:
- **Core Layer** — JS, HTML, CSS (vanilla)
- **Build Layer** — bundlers, runtimes, template engines, pre/post processors
- **Application Layer** — frontend, backend, frameworks, SSR, CSS-utilities
3 Segmente: HTML (blau) · JavaScript (rot) · CSS (grün) · Mittelpunkt: `package.json`
---
# JavaScript Frameworks – Kategorien
| Kategorie | Beispiele |
|-----------|-----------|
| **CSS Frameworks** | Tailwind, Bootstrap, shadcn/ui |
| **Frontend Frameworks** | React, Vue, Svelte, Astro |
| **Rendering / Meta** | Next.js, Nuxt, Gatsby |
| **Build Tools / Bundler** | Webpack, Vite, Parcel, esbuild |
| **Backend Frameworks** | Express, Fastify, NestJS |
---
# Vanilla JS – Counter
```html
<button id="myButton">Clicked 0 times</button>
<script>
let count = 0;
const btn = document.getElementById('myButton');
btn.addEventListener('click', () => {
count++;
btn.textContent = `Clicked ${count} times`;
});
</script>
```
**Pro:** hohe Kompatibilität, simpel
**Contra:** State-Management und Re-Rendering werden schnell komplex
---
# React – Counter (JSX)
![bg right:25% fit](./assets/logos/frameworks/react.svg)
```jsx
import { useState } from "react";
function MyButton() {
const [count, setCount] = useState(0);
return (
<button onClick={() => setCount(count + 1)}>
Clicked {count} times
</button>
);
}
```
- **Component-Based** Architecture
- **Virtual DOM**, JSX, Hooks
- großes Ökosystem (React Router, Redux, …)
---
# Vue 3 – Composition API
![bg right:25% fit](./assets/logos/frameworks/vue.svg)
```vue
<script setup>
import { ref } from "vue";
const count = ref(0);
</script>
<template>
<button @click="count++">
Clicked {{ count }} times
</button>
</template>
```
- **Reactive Data Binding**
- Single-File Components (`.vue`)
- Vue Router, Pinia (State)
---
# Svelte – Counter
![bg right:25% fit](./assets/logos/frameworks/svelte.svg)
```svelte
<script>
let count = 0;
</script>
<button on:click={() => count += 1}>
Clicked {count} {count === 1 ? 'time' : 'times'}
</button>
```
- **Compiler-Based** – kein Runtime-Framework
- Reactive Assignments (`let`)
- Built-in Animationen
---
# Astro – Content-First
![bg right:25% fit](./assets/logos/frameworks/astro.svg)
```astro
---
const greeting = "Hallo DHBW";
---
<html>
<body>
<h1>{greeting}</h1>
<MyReactButton client:load />
</body>
</html>
```
- **Islands Architecture** – Komponenten mehrerer Frameworks mischen
- Default: kein JS im Output (nur statisches HTML)
- Hydration on demand (`client:load`, `client:visible`)
---
# Rendering Frameworks
| | Frontend | SSR | SSG | File Routing |
|---|---|---|---|---|
| **Next.js** | React | ja | ja | `/app/page.js` |
| **Nuxt** | Vue | ja | ja | `/pages/*.vue` |
| **Gatsby** | React | nein | ja | GraphQL Data |
---
# Build Tools – Webpack
![bg right:25% fit](./assets/logos/frameworks/webpack.svg)
- Module Bundling (JS, CSS, Images)
- Module Loaders + großes Plugin-Ökosystem
- Code Splitting, HMR
- Konfigurations-lastig (`webpack.config.js`)
→ Standard für viele Legacy-Setups.
---
# Build Tools – Vite
![bg right:25% fit](./assets/logos/frameworks/vite.svg)
```javascript
// vite.config.js
import { defineConfig } from "vite";
export default defineConfig({
server: {
proxy: {
"/api": {
target: "http://localhost:4567",
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, "")
}
}
}
});
```
- Rollup unter der Haube, **HMR mit ES Modules**
- Tree-Shaking, Code Splitting, React + Vue out-of-the-box
---
# Build Tools – Parcel
![bg right:25% fit](./assets/logos/frameworks/parcel.png)
```json
{
"name": "my-project",
"source": "src/index.html",
"browserslist": "> 0.5%, last 2 versions, not dead",
"scripts": {
"start": "parcel",
"build": "parcel build"
},
"devDependencies": {
"parcel": "latest"
}
}
```
- **Zero-Config**
- Auto-Resolution, HMR
- TS / CSS-Preprocessors out-of-the-box
---
# Microfrontends
- Mehrere unabhängige Frontend-Apps in einer Page
- Module Federation (Webpack 5)
- **single-spa**: https://single-spa.js.org/
- Anwendungsfall: große Teams, unterschiedliche Tech-Stacks pro Domain
→ Komplexitätskosten: nur bei echtem Skalierungsbedarf.
---
# Demo-Repos
- https://github.com/nextlevelshit/dhbw-client-js (Counter, multi-framework)
- https://github.com/nextlevelshit/node-cache-api (API + Tests)
- https://github.com/nextlevelshit/dhbw-docker (Compose-Stack)