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)
1826 lines
40 KiB
Markdown
1826 lines
40 KiB
Markdown
---
|
||
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 -->
|
||
|
||

|
||
|
||
# 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
|
||
|
||

|
||
|
||
**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: '' -->
|
||
|
||

|
||
|
||
---
|
||
|
||
# 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: '' -->
|
||
|
||

|
||
|
||
---
|
||
|
||
<!-- _header: '' -->
|
||
<!-- _footer: '' -->
|
||
|
||

|
||
|
||
---
|
||
|
||
# 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: '' -->
|
||
|
||

|
||
|
||
|
||
---
|
||
|
||
# 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
|
||
|
||

|
||
|
||
```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)
|
||
|
||

|
||
|
||
```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
|
||
|
||

|
||
|
||
```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>
|
||
|
||

|
||
|
||
```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)
|
||
|
||

|
||
|
||
```html
|
||
<details open>
|
||
<summary>Klick mich!</summary>
|
||
<p>Dieser Text war versteckt.</p>
|
||
</details>
|
||
```
|
||
|
||
---
|
||
|
||
# Beispiel: Button
|
||
|
||

|
||
|
||
```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
|
||
|
||

|
||
|
||
```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>
|
||
|
||

|
||
|
||
```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
|
||
|
||

|
||
|
||
**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
|
||
|
||

|
||
|
||
**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
|
||
|
||

|
||
|
||
**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
|
||
|
||

|
||
|
||
**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:
|
||
|
||

|
||
|
||
---
|
||
|
||
<!-- _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
|
||
|
||

|
||
|
||
```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
|
||
|
||

|
||
|
||
```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
|
||
|
||

|
||
|
||
```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
|
||
|
||

|
||
|
||
```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?
|
||
|
||

|
||
|
||
| 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
|
||
|
||

|
||
|
||
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
|
||
|
||

|
||
|
||
```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
|
||
|
||

|
||
|
||
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
|
||
|
||

|
||
|
||
```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
|
||
|
||

|
||
|
||
```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
|
||
|
||

|
||
|
||
```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 -->
|
||
|
||

|
||
|
||
---
|
||
|
||
<!-- _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)
|
||
|
||

|
||
|
||
```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
|
||
|
||

|
||
|
||
```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
|
||
|
||

|
||
|
||
```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
|
||
|
||

|
||
|
||
```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
|
||
|
||

|
||
|
||
- 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
|
||
|
||

|
||
|
||
```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
|
||
|
||

|
||
|
||
```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)
|
||
|