branch-coexist: 3 neue decks 223015b-2026 / 223015c-2026 / dhbw-2026 daneben main

per user-request einen branch der main-content UND rewrite-content trägt — saubere separierung statt symlink/merge-conflict.

struktur:
- slides/<course>/ → main-content restored, eigene assets (kein new-demo-leak)
- slides/<course>-2026/ → rewrite-content, eigene assets (komplett kopiert + new demos)

Makefile: COURSES += 223015b-2026 223015c-2026 dhbw-2026 mit eigenen NAME/KAPITEL/DEPLOY/KLAUSUR-konfig. Klausur für b+c=1, dhbw=leer. Deploy-paths /hdm/223015b-2026 etc.

make build durchlaufen für alle 6 decks, 0 fehler.

dedup: 223015c+dhbw assets identisch in beiden ordnern (kein neu-demos auf b ergänzt). 223015b 86 → 120 files in -2026 (= +34 neue eroeffner/usb-c-drei-achsen/container-vs-codec/etc).
This commit is contained in:
libretech committed 2026-05-14 21:54:15 +02:00
1 parent 6209f9f3a0
commit 351e3dfc23
467 files changed
+32391 -4701

No files matched your search

+837
View File
@@ -0,0 +1,837 @@
---
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** — [developer.mozilla.org](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 Czechowski
- Software Engineer, ehemals freischaffend
- Lektor an HdM Stuttgart + DHBW
- librete.ch
---
# Vorlesungsplan (Auszug)
| Termin | Thema |
|--------|-------|
| 1 | Web Engineering (heute) |
| 2 | CSS Extended |
| 3 | Node.js Basics |
| 4 | Node.js Advanced |
| 5 | Testing |
| 6 | TypeScript |
| 7 | Docker |
| 8 | Best Practices |
---
# Prüfungsleistung — 75 P + 10 Bonus
**Projekt-Abgabe** statt Klausur.
| Bereich | Punkte |
|---------|-------:|
| Projekt-Struktur + README | 10 |
| Code-Qualität | 15 |
| Git-Hygiene | 10 |
| Tests | 10 |
| Docker | 10 |
| HTTP / API | 10 |
| Frontend + A11y | 10 |
| Präsentation + Bonus | 5 + 10 |
---
<!-- _class: lead -->
# Kontext: was ist „das Web"?
---
# Internet-Timeline
| Jahr | Was |
|------|-----|
| 1969 | ARPANET — 4 Knoten |
| 1971 | Email (Ray Tomlinson, `@`) |
| 1983 | TCP/IP-Standard |
| **1989** | **WWW** (Berners-Lee, CERN) |
| 1993 | Mosaic-Browser → Web wird populär |
---
# Das WWW (1989)
**Tim Berners-Lee am CERN.** Drei Standards:
- **HTTP** — Protokoll
- **HTML** — Format
- **URL** — Adresse
Patentfrei → Web konnte explodieren.
---
# Heute: physische Infrastruktur
- ~400 Unterseekabel
- 1,3 Mio km Glasfaser weltweit
- DE-CIX Frankfurt: größter Internet-Knoten (~12 Tbit/s)
Das Web ist **physisch.**
---
# URL → Pixel in 7 Schritten
1. **URL parsen** — Schema, Host, Port, Path
2. **DNS-Lookup** — Host-Name → IP
3. **TCP-Handshake** mit Server
4. **TLS-Handshake** (https)
5. **HTTP-Request** senden
6. Server antwortet mit **HTML + CSS + JS**
7. Browser **parsed + rendert** → Pixel
---
# HTTP — Anatomie
```http
GET /index.html HTTP/1.1
Host: librete.ch
User-Agent: Mozilla/5.0 ...
HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 1234
<!DOCTYPE html>...
```
**Statuscodes:** 200 OK · 301 Moved · 404 Not Found · 500 Server Error
---
<!-- _class: lead -->
# Onboarding
## Tools, Runtimes, Workflows
---
# Werkzeuge & Betriebssystem
| Bereich | Empfehlung |
|---------|------------|
| Editor | **VS Code** · JetBrains (edu lizenz frei) |
| Browser | **Chromium / Firefox** |
| Terminal | macOS Terminal · Linux Terminal · Windows Terminal |
| Paket-Manager | macOS: brew · Linux: apt/dnf · Windows: winget/scoop/choco |
| Versions-Control | Git + GitHub/Gitea |
---
# Node.js installieren
**Best Practice:** Versions-Manager statt Direkt-Install.
| OS | Empfehlung |
|----|------------|
| macOS | `brew install fnm` → `fnm install --lts` |
| Linux | `curl -fsSL https://fnm.vercel.app/install \| bash` |
| Windows | `winget install Schniz.fnm` |
**Aktuelle LTS:** Node 24.
---
# Warum Versions-Manager?
**Direkt-Install** (z.B. `brew install node`) bringt Probleme:
- Projekt-A braucht Node 18, Projekt-B braucht Node 22 → Konflikt
- Update bricht alte Projekte
- Kein automatisches Switching pro Projekt
**fnm / nvm / volta:** pro Projekt Node-Version, automatisch via `.nvmrc`.
---
# Alternative Runtimes
| Runtime | Stärke |
|---------|--------|
| **Node** | Standard, größtes Ökosystem |
| **Deno** | Sicher by default, TypeScript nativ |
| **Bun** | Schnell, all-in-one (runtime + bundler + tester) |
Für DHBW-Kurs: **Node 24 LTS.**
---
# Browser DevTools
**F12** öffnet das Power-Tool jeder Webentwicklung.
| Tab | Wofür |
|-----|-------|
| Elements | DOM-Baum inspizieren + live editieren |
| Console | JS ausführen, Errors lesen |
| Network | HTTP-Requests sehen, Latenz |
| Performance | Render + Memory profilen |
| Lighthouse | A11y · SEO · Perf-Audit |
---
# HTTP-Clients
Tools zum Testen von APIs:
- **curl** — CLI, überall
- **Hoppscotch** — Browser, Open Source
- **Postman** — GUI, kommerziell
- **VS Code REST Client** — Plugin
---
# Git Setup
```sh
git config --global user.name "Dein Name"
git config --global user.email "du@dhbw.de"
git config --global init.defaultBranch main
git config --global core.autocrlf input # Windows: true
```
**SSH-Key** für GitHub/Gitea ohne Passwort-Prompt:
```sh
ssh-keygen -t ed25519 -C "du@dhbw.de"
cat ~/.ssh/id_ed25519.pub # zu GitHub kopieren
```
---
# Projekt-Skeleton
```
mein-projekt/
├── .git/
├── .gitignore # node_modules/, .env, build/
├── README.md # was, wie, warum
├── package.json # npm metadata + scripts
├── src/ # eigener Code
├── public/ # statische Assets (für Web)
├── tests/ # Unit + Integration
└── Dockerfile # für Container-Deploy
```
---
<!-- _class: lead -->
# HTML
## Hypertext Markup Language
---
# Was ist HTML?
**Tim Berners-Lee, 1989.** Struktur-Format des Webs.
**Syntax:** Tags mit Attributen umfassen Inhalt.
**Browser parst HTML** → DOM (Document Object Model) → rendert.
Plain-Text mit Tags. Lesbar mit jedem Editor.
---
# HTML-Anatomie
```html
<a href="https://librete.ch" target="_blank">Mein Link</a>
```
- `<a` — Opening-Tag mit Tag-Namen
- `href="..."` — Attribut (Name + Wert)
- `Mein Link` — Inhalt
- `</a>` — Closing-Tag
- Alles zusammen = **Element**
---
# Self-closing Tags
```html
<img src="foto.jpg" alt="Sonnenuntergang">
<br>
<input type="text" name="username">
<meta charset="utf-8">
<link rel="stylesheet" href="style.css">
```
Kein Closing-Tag. Inhalt aus Attributen + (für `<input>`) User-Eingabe.
---
# Document-Grundgerüst
```html
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Meine Seite</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<h1>Hallo Welt</h1>
</body>
</html>
```
---
# Semantische HTML-Tags
| Tag | Bedeutung |
|-----|-----------|
| `<header>` | Kopfbereich (Logo, Nav) |
| `<nav>` | Navigation |
| `<main>` | Hauptinhalt |
| `<section>` | Thematischer Abschnitt |
| `<article>` | eigenständiger Inhalt |
| `<aside>` | Seiten-Inhalt |
| `<footer>` | Fußbereich |
**Pflicht** für SEO + A11y + Wartbarkeit.
---
# Native HTML-Elemente — nicht vergessen!
Bevor du eine Custom-Component baust: **gibt's das schon nativ?**
| Element | Was |
|---------|-----|
| `<details>` / `<summary>` | Accordion ohne JS |
| `<dialog>` | Modal mit Native Backdrop |
| `<input type="date">` | Date-Picker, native, A11y |
| `<input type="color">` | Color-Picker |
| `<input type="range">` | Slider |
| `<datalist>` | Autocomplete-Vorschläge |
| `<progress>` | Lade-Balken |
**Faustregel:** Native zuerst, Custom nur wenn nötig.
---
<!-- _class: lead -->
# Barrierefreiheit
## A11y — Accessibility
---
# BFSG + EAA — Pflicht ab 28.06.2025
**Barrierefreiheitsstärkungsgesetz** (DE) setzt **European Accessibility Act** (EU) um.
**Pflicht:**
- Online-Shops, Banken, Versicherungen
- E-Books, Buchungssysteme
- Smartphone-Apps mit kommerziellem Bezug
**Ausnahme:** < 10 Mitarbeiter + < 2 Mio € Umsatz.
**Strafe:** bis 100.000 € Bußgeld + Klage durch Behindertenverbände.
---
# Wie nutzen Menschen das Web?
- **Sehen:** Screen-Reader (NVDA, JAWS, VoiceOver)
- **Hören:** Untertitel + Transkripte
- **Motorik:** Tastatur statt Maus, Switch-Control
- **Kognitiv:** klare Sprache, viel Whitespace
- **Vorübergehend:** Sonne im Bildschirm, gebrochener Arm, ÖPNV-Lärm
~10 % der Bevölkerung haben relevante Beeinträchtigungen. *Du auch — irgendwann.*
---
# WCAG · 4 Prinzipien (POUR)
| Prinzip | Was |
|---------|-----|
| **P**erceivable | Alt-Text · Untertitel · Kontrast |
| **O**perable | Keyboard · Skip-Links |
| **U**nderstandable | klare Sprache · Fehler-Hilfe |
| **R**obust | semantisches HTML · Standards-konform |
**WCAG 2.1 Level AA** = Mindest-Standard für BFSG.
---
# Perceivable — wahrnehmbar
- **Alt-Text** für jedes Bild (`<img alt="...">`)
- **Untertitel** für jedes Video
- **Kontrast 4.5:1** für Text (Level AA)
- **Skalierbar** bis 200 %
```html
<img src="foto.jpg" alt="Sonnenuntergang am Bodensee">
<!-- LEER alt="" für rein dekorative Bilder -->
```
---
# Operable — bedienbar
- Alle interaktiven Elemente **mit Tastatur erreichbar**
- **Fokus sichtbar** (`:focus-visible` mit Outline)
- **Skip-Links** für Screen-Reader (Hauptnav überspringen)
- **Genug Zeit** für Aufgaben (Auto-Logout pausierbar)
```css
button:focus-visible {
outline: 3px solid hotpink;
outline-offset: 2px;
}
```
---
# Understandable — verständlich
- **Lese-Niveau** angemessen (Level AA: 9. Klasse)
- **Klare Fehlermeldungen** (was war falsch, wie korrigieren)
- **Konsistente Navigation** (Header bleibt gleich)
- **`lang`-Attribut** im html-Element
```html
<html lang="de">
<p lang="en">This sentence is in English.</p>
</html>
```
---
# Robust — Tech-stabil
- **Semantisches HTML** statt div-Suppe
- **ARIA** *nur als Ergänzung*, nicht als Ersatz
- **Standards-konform** (Validator: validator.w3.org)
```html
<!-- ❌ semantisch falsch -->
<div onclick="...">Klick</div>
<!-- ✓ semantisch korrekt -->
<button onclick="...">Klick</button>
```
---
# A11y-Testen — Werkzeuge
| Tool | Was |
|------|-----|
| **Lighthouse** (Chrome DevTools) | automatischer Audit |
| **axe DevTools** | Plugin, präziser |
| **WAVE** | Browser-Plugin, visuell |
| **Manuell** | Maus weglegen, nur Tab |
| **Screen-Reader** | macOS: VoiceOver (Cmd+F5) · Win: NVDA |
**Automatisierte Tools** finden ~30 %. Rest = manuell.
---
<!-- _class: lead -->
# CSS
## Cascading Style Sheets
*(Vertiefung in Kap 2 — CSS Extended)*
---
# CSS einbinden
```html
<!-- External (best practice) -->
<link rel="stylesheet" href="./style.css">
<!-- Internal -->
<style>
body { background: #fafafa; }
</style>
<!-- Inline (vermeiden) -->
<button style="background: hotpink">Klick</button>
```
---
# CSS-Anatomie
```css
button {
background-color: hotpink;
padding: 10px 20px;
border-radius: 8px;
}
```
- `button` = **Selektor** (welche Elemente)
- `background-color` = **Property**
- `hotpink` = **Value**
- alles in `{ }` = **Declaration Block**
---
# Selektoren
| Selektor | Was |
|----------|-----|
| `p` | alle `<p>` |
| `.btn` | alle mit `class="btn"` |
| `#header` | das Element mit `id="header"` |
| `button:hover` | Button beim Hover |
| `nav > a` | direkte `<a>` unter `<nav>` |
| `*` | alles |
---
# Spezifizität — wer gewinnt?
```css
p { color: blue; } /* 1 */
.notice { color: red; } /* 10 */
#warn { color: green; } /* 100 */
[style] /* inline */ /* 1000 */
```
**Inline > ID > Klasse > Element.** Bei Gleichstand: **letzte Regel.**
`!important` umgeht alles — *vermeiden.*
---
# Box-Model
```
┌──────────────────────┐
│ margin │
│ ┌────────────────┐ │
│ │ border │ │
│ │ ┌──────────┐ │ │
│ │ │ padding │ │ │
│ │ │ content │ │ │
│ │ └──────────┘ │ │
│ └────────────────┘ │
└──────────────────────┘
```
**Best Practice:** `* { box-sizing: border-box; }` global.
---
# Farben
| Notation | Beispiel |
|----------|----------|
| Hex | `#FF5733` |
| RGB | `rgb(255, 87, 51)` |
| RGBA | `rgb(255, 87, 51, 0.5)` |
| HSL | `hsl(11, 100%, 60%)` |
| OKLCH (modern) | `oklch(0.7 0.2 30)` |
| Schlüsselwort | `hotpink`, `tomato` |
---
# Einheiten
| Einheit | Was |
|---------|-----|
| `px` | Pixel, fix |
| `rem` | relativ zu Wurzel-Font (16 px default) |
| `em` | relativ zu Eltern-Font |
| `%` | relativ zur Eltern-Größe |
| `vw` / `vh` | Viewport-Breite/-Höhe |
| `ch` | Breite eines Zeichens |
**Faustregel:** Font + Spacing in `rem`. Layout in `%` oder `fr`.
---
# Pseudo-Klassen & -Elemente
```css
/* Pseudo-Klassen (Zustand) */
a:hover { color: hotpink; }
input:focus { outline: 2px solid; }
button:disabled { opacity: 0.5; }
li:nth-child(2n) { background: #eee; }
/* Pseudo-Elemente (Virtuelles) */
p::first-letter { font-size: 2em; }
.tooltip::after { content: " 💡"; }
```
---
<!-- _class: lead -->
# JavaScript
## Die Sprache des Webs
*(Vertiefung in Kap 3+4 — Node.js)*
---
# ECMAScript
**ECMA International** (Schweiz) standardisiert die Sprache.
| Version | Jahr | Highlight |
|---------|------|-----------|
| ES5 | 2009 | strict mode, JSON |
| ES6 / 2015 | 2015 | `let` `const`, arrow, classes, modules |
| ES2017 | 2017 | async/await |
| ES2020 | 2020 | optional chaining `?.` |
| ES15 | 2024 | aktuell |
---
# JavaScript-Grundlagen
```javascript
// Variablen
const name = "Ada";
let alter = 56;
// Funktionen
const begrüßen = (name) => `Hallo ${name}`;
// Arrays + Objects
const fruits = ["A", "B"];
const user = { name: "Ada", admin: true };
// Schleifen
fruits.map(f => f.toUpperCase());
// async
async function laden() {
const res = await fetch('/api');
return res.json();
}
```
---
# DOM Manipulation
```javascript
// Element finden
const btn = document.querySelector('#myBtn');
// Inhalt ändern
btn.textContent = 'Neu';
btn.classList.add('active');
// Event-Handler
btn.addEventListener('click', () => {
console.log('Klick!');
});
// Element erzeugen
const li = document.createElement('li');
li.textContent = 'Item';
document.querySelector('ul').appendChild(li);
```
---
# Fetch + JSON
```javascript
// GET
const res = await fetch('https://api.github.com/users/torvalds');
const data = await res.json();
console.log(data.public_repos);
// POST
await fetch('/api/posts', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ title: 'Hallo', body: '...' })
});
```
---
<!-- _class: lead -->
# Frameworks-Vorschau
---
# Framework-Landschaft
| Framework | Typ | Use-Case |
|-----------|-----|----------|
| **React** | Library | dominant, große Community |
| **Vue 3** | Framework | sanfter Einstieg |
| **Svelte** | Compiler | kein Virtual DOM, kleines Bundle |
| **Astro** | Hybrid | Content-First, Multi-Framework |
| **Angular** | Framework | Enterprise, Google |
Alle: **Komponenten + reaktive State + Re-Render.**
---
# Counter — Vanilla + React
**Vanilla JS:**
```javascript
let count = 0;
btn.onclick = () => { count++; display.textContent = count; };
```
**React (JSX):**
```jsx
function Counter() {
const [count, setCount] = useState(0);
return <button onClick={() => setCount(count + 1)}>{count}</button>;
}
```
---
# Counter — Vue + Svelte
**Vue 3 (Composition):**
```vue
<script setup>const count = ref(0)</script>
<template><button @click="count++">{{ count }}</button></template>
```
**Svelte:**
```svelte
<script>let count = 0</script>
<button on:click={() => count++}>{count}</button>
```
Vier Frameworks, **dasselbe Pattern:** State → UI re-rendert.
---
# Build-Tools
| Tool | Stärke |
|------|--------|
| **Vite** | schnell, modern, Default für React/Vue/Svelte |
| **Webpack** | etabliert, mächtig, verbreitet |
| **Parcel** | zero-config |
| **Bun** | all-in-one, sehr schnell |
**Heute:** Vite ist der Default für neue Projekte.
---
# Rendering-Modi
| Modus | Wann |
|-------|------|
| **CSR** (Client-Side) | Single-Page-Apps (Dashboard, Editor) |
| **SSR** (Server-Side) | SEO + erste Latenz wichtig (News, Shop) |
| **SSG** (Static Site Gen) | reine Content-Sites (Blog, Doku) |
| **ISR** (Incremental SSG) | Hybrid: Content selten ändert |
Astro / Next.js / Nuxt unterstützen alle.
---
<!-- _class: aufgabe -->
# Selbstlernen — Erste eigene Seite
1. **Mappe anlegen** `meine-seite/`
2. `index.html` mit dem **Grundgerüst** (DOCTYPE, head, body, h1, p)
3. `style.css` daneben — mit Hotpink-Background
4. **VS Code Live Server** starten → im Browser öffnen
5. **DevTools** auf, F12, Tab Elements → DOM-Baum anschauen
**Bonus:** Lighthouse Audit laufen lassen. Welchen Score erreicht ihr?
---
# Zusammenfassung
**Heute gelernt:**
- Internet-Geschichte → WWW → URL→Pixel-7-Schritte
- Onboarding-Stack: Node (fnm), VS Code, Git, DevTools
- HTML: Anatomie, semantisch, A11y-Foundation
- A11y: BFSG/EAA-Pflicht, WCAG POUR
- CSS-Basics (Vertiefung in Kap 2)
- JS-Basics (Vertiefung in Kap 3+4)
- Framework-Landschaft (Vorschau)
**Nächste Stunde:** CSS deeper — Flexbox, Grid, Responsive, Animations.