Handy: Sicherheitsabstaende, Wisch-Reiter, zweispaltige Uebersicht

Der wichtigste Fund: env(safe-area-inset-*) stand bereits im CSS, lieferte
aber immer null -- viewport-fit=cover fehlte auf allen dreizehn Seiten.
Der Code sah richtig aus und tat nichts. Zusammen mit
apple-mobile-web-app-status-bar-style=black-translucent (schon gesetzt)
hiess das: installiert lag die Kopfzeile auf einem iPhone hinter Uhr und
Akkuanzeige.

Behoben:
- viewport-fit=cover auf allen 13 Seiten.
- Vier Sicherheitsabstaende zentral benannt statt an jeder Stelle
  einzeln geschrieben. Kopfzeile weicht der Statusleiste, Container dem
  seitlichen Notch im Querformat, Fusszeile der Gestenleiste.
- Der 'Ueberspringen'-Knopf des Vorspanns lag mit bottom:2rem praktisch
  AUF dem Entsperr-Strich (34px). Man haette die App verlassen statt
  uebersprungen.
- Eigener Zweig fuer den installierten Betrieb: kein Gummiband-
  Nachfedern (sieht in einer App nach einem Fehler aus), kein
  Installations-Hinweis.
- Die vier Sprungmarken auf der Rechtsseite waren 39px hoch -- fuenf
  unter dem Daumenmass. Ausgerechnet dort muss man zum Widerrufsrecht
  springen koennen.
- 'Waehle links einen Verlauf aus': Auf dem Handy gibt es kein links,
  die Liste steht darueber. Richtungswort entfernt.
- Sechs Reiter brauchten auf dem Handy drei Zeilen. Jetzt ein
  Wischstreifen mit Einrasten und Auslauf am Rand; der aktive Reiter
  wird herangeholt, wenn man ueber eine Kachel springt.
- Uebersicht zweispaltig statt zwoelf Zeilen untereinander: 2635px ->
  1924px. Eine Uebersicht, an der man vorbeiwischen muss, ist keine.

Geprueft mit 55 neuen Handy-Pruefungen auf iPhone 14 Pro, Pixel 7 und
320px Breite, jeweils im Browser und im installierten Zweig. Drei
Fehlalarme der eigenen Pruefung wurden begruendet ausgenommen (Honigtopf
bei left:-9999px, Eingabefeld in einer Beschriftung, Inline-Link im
Fliesstext -- WCAG 2.5.8 nimmt letztere ausdruecklich aus).

Zwei Selbstkorrekturen an der Pruefung dokumentiert: Die Emulation von
display-mode wirkt nicht (Chromium nimmt den Befehl an und ignoriert
ihn) -- ohne das waeren die zwoelf 'installiert'-Zeilen ein zweiter
Browser-Durchgang gewesen. Und die Messung gegen die Systemleisten mass
zuerst die Kastenkante statt der Inhaltskante und meldete elf korrekte
Seiten als fehlerhaft. Eine Selbstpruefung mit einem absichtlich falsch
gesetzten Knopf belegt jetzt, dass die Messung echte Fehler findet.

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
2026-08-23 19:51:10 +02:00
co-authored by Claude Opus 5
parent c1cb51884f
commit 37f1b4a8f5
18 changed files with 912 additions and 23 deletions
+6 -1
View File
@@ -2,7 +2,12 @@
<html lang="de" data-i18n-titel="seiten_titel">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<!-- viewport-fit=cover ist die Voraussetzung dafuer, dass env(safe-area-inset-*)
ueberhaupt einen Wert liefert. Ohne diese Angabe gibt jedes env() null zurueck
-- die Sicherheitsabstaende im CSS waeren totes Recht. Zusammen mit
apple-mobile-web-app-status-bar-style=black-translucent (siehe unten) laeuft
der Inhalt sonst installiert unter Uhr und Akkuanzeige. -->
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
<title>Ablauf — Dogfather Webdesign</title>
<meta name="description" content="Von der Anfrage bis zur Übergabe: sieben Schritte, jeweils mit dem, was du machst, was ich mache und was am Ende dabei herauskommt." />
<meta name="robots" content="noindex, nofollow, noarchive" />
+6 -1
View File
@@ -2,7 +2,12 @@
<html lang="de" data-i18n-titel="seiten_titel">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<!-- viewport-fit=cover ist die Voraussetzung dafuer, dass env(safe-area-inset-*)
ueberhaupt einen Wert liefert. Ohne diese Angabe gibt jedes env() null zurueck
-- die Sicherheitsabstaende im CSS waeren totes Recht. Zusammen mit
apple-mobile-web-app-status-bar-style=black-translucent (siehe unten) laeuft
der Inhalt sonst installiert unter Uhr und Akkuanzeige. -->
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
<title>Projekt anfragen — Dogfather Webdesign</title>
<meta name="description" content="Vier kurze Schritte zu deiner unverbindlichen Projektanfrage. Kostenlos, ohne Vertrag, mit Zusammenfassung vor dem Absenden." />
<meta name="robots" content="noindex, nofollow, noarchive" />
+6 -1
View File
@@ -2,7 +2,12 @@
<html lang="de">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<!-- viewport-fit=cover ist die Voraussetzung dafuer, dass env(safe-area-inset-*)
ueberhaupt einen Wert liefert. Ohne diese Angabe gibt jedes env() null zurueck
-- die Sicherheitsabstaende im CSS waeren totes Recht. Zusammen mit
apple-mobile-web-app-status-bar-style=black-translucent (siehe unten) laeuft
der Inhalt sonst installiert unter Uhr und Akkuanzeige. -->
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
<title>Diagnose — Dogfather Webdesign</title>
<meta name="robots" content="noindex, nofollow" />
<meta name="theme-color" content="#05070b" />
+6 -1
View File
@@ -2,7 +2,12 @@
<html lang="de" data-i18n-titel="seiten_titel">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<!-- viewport-fit=cover ist die Voraussetzung dafuer, dass env(safe-area-inset-*)
ueberhaupt einen Wert liefert. Ohne diese Angabe gibt jedes env() null zurueck
-- die Sicherheitsabstaende im CSS waeren totes Recht. Zusammen mit
apple-mobile-web-app-status-bar-style=black-translucent (siehe unten) laeuft
der Inhalt sonst installiert unter Uhr und Akkuanzeige. -->
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
<title>Häufige Fragen — Dogfather Webdesign</title>
<meta name="description" content="Preise, Dauer, Inhalte, Änderungen, Hosting, Rechte, Zahlung und Veröffentlichung — offen beantwortet." />
<meta name="robots" content="noindex, nofollow, noarchive" />
+15 -2
View File
@@ -2,7 +2,12 @@
<html lang="de" data-i18n-titel="seiten_titel">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<!-- viewport-fit=cover ist die Voraussetzung dafuer, dass env(safe-area-inset-*)
ueberhaupt einen Wert liefert. Ohne diese Angabe gibt jedes env() null zurueck
-- die Sicherheitsabstaende im CSS waeren totes Recht. Zusammen mit
apple-mobile-web-app-status-bar-style=black-translucent (siehe unten) laeuft
der Inhalt sonst installiert unter Uhr und Akkuanzeige. -->
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
<title>Dogfather Webdesign — individuelle Webseiten, persönlich umgesetzt</title>
<meta name="description" content="Individuell gebaute Webseiten statt Baukasten: Onepager ab 300 €, professionelle Websites ab 500 €, Shops ab 1.000 €. Klare Preise, klare Zeitrahmen, eine feste Ansprechperson." />
<meta name="robots" content="noindex, nofollow, noarchive" />
@@ -45,7 +50,15 @@
animation: wd-intro-auf .9s cubic-bezier(.22,1,.36,1) both .45s;
}
.wd-intro-skip {
position: absolute; bottom: 2rem; left: 50%; transform: translateX(-50%);
/* Der Abstand nach unten muss die Gestenleiste einrechnen.
Mit festen 2rem (32px) lag der Knopf auf einem iPhone 14 Pro
praktisch AUF dem Strich zum Entsperren -- der ist 34px hoch.
Man haette daneben getippt und waere aus der App geflogen, statt
den Vorspann zu ueberspringen. */
position: absolute;
bottom: calc(2rem + var(--wd-sicher-unten, 0px));
left: 50%; transform: translateX(-50%);
background: none; border: 1px solid var(--wd-rand); color: var(--wd-text-soft);
border-radius: 999px; padding: .55rem 1.2rem; min-height: 44px; cursor: pointer; font-size: .88rem;
}
+6 -1
View File
@@ -2,7 +2,12 @@
<html lang="de" data-i18n-titel="seiten_titel">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<!-- viewport-fit=cover ist die Voraussetzung dafuer, dass env(safe-area-inset-*)
ueberhaupt einen Wert liefert. Ohne diese Angabe gibt jedes env() null zurueck
-- die Sicherheitsabstaende im CSS waeren totes Recht. Zusammen mit
apple-mobile-web-app-status-bar-style=black-translucent (siehe unten) laeuft
der Inhalt sonst installiert unter Uhr und Akkuanzeige. -->
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
<title>Leistungen — Dogfather Webdesign</title>
<meta name="description" content="Onepager, professionelle Website, Shop und Verwaltungsseiten: was jeweils enthalten ist, was extra kostet und wo die Grenze verläuft." />
<meta name="robots" content="noindex, nofollow, noarchive" />
+6 -1
View File
@@ -2,7 +2,12 @@
<html lang="de" data-i18n-titel="seiten_titel">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<!-- viewport-fit=cover ist die Voraussetzung dafuer, dass env(safe-area-inset-*)
ueberhaupt einen Wert liefert. Ohne diese Angabe gibt jedes env() null zurueck
-- die Sicherheitsabstaende im CSS waeren totes Recht. Zusammen mit
apple-mobile-web-app-status-bar-style=black-translucent (siehe unten) laeuft
der Inhalt sonst installiert unter Uhr und Akkuanzeige. -->
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
<title>Kundenportal — Dogfather Webdesign</title>
<meta name="robots" content="noindex, nofollow, noarchive" />
<link rel="icon" type="image/png" href="/assets/img/favicon.png" />
+6 -1
View File
@@ -2,7 +2,12 @@
<html lang="de" data-i18n-titel="seiten_titel">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<!-- viewport-fit=cover ist die Voraussetzung dafuer, dass env(safe-area-inset-*)
ueberhaupt einen Wert liefert. Ohne diese Angabe gibt jedes env() null zurueck
-- die Sicherheitsabstaende im CSS waeren totes Recht. Zusammen mit
apple-mobile-web-app-status-bar-style=black-translucent (siehe unten) laeuft
der Inhalt sonst installiert unter Uhr und Akkuanzeige. -->
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
<title>Portfolio — Dogfather Webdesign</title>
<meta name="description" content="Echte Projekte statt erfundener Beispiele: Dogfather Universe und Van's DIY & Bastelbedarf — mit Ausgangslage, Lösung und Ergebnis." />
<meta name="robots" content="noindex, nofollow, noarchive" />
+6 -1
View File
@@ -2,7 +2,12 @@
<html lang="de">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<!-- viewport-fit=cover ist die Voraussetzung dafuer, dass env(safe-area-inset-*)
ueberhaupt einen Wert liefert. Ohne diese Angabe gibt jedes env() null zurueck
-- die Sicherheitsabstaende im CSS waeren totes Recht. Zusammen mit
apple-mobile-web-app-status-bar-style=black-translucent (siehe unten) laeuft
der Inhalt sonst installiert unter Uhr und Akkuanzeige. -->
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
<title>Impressum, AGB &amp; Datenschutz — Dogfather Webdesign</title>
<meta name="description" content="Impressum, Allgemeine Geschäftsbedingungen, Widerrufsbelehrung und Datenschutzerklärung für Dogfather Webdesign." />
<link rel="icon" type="image/png" href="/assets/img/favicon.png" />
+1 -1
View File
@@ -34,7 +34,7 @@
Start alle alten Zwischenspeicher weg. Muss bei jeder Änderung an den
Dateien unten hochgezählt werden, sonst hängen Nutzer auf einem alten
Stand fest. */
const CACHE_NAME = "dogfather-webdesign-v21";
const CACHE_NAME = "dogfather-webdesign-v22";
/* Bausteine, die die Oberfläche zum Anzeigen braucht. Bewusst KEINE
HTML-Datei in dieser Liste. */
+6 -1
View File
@@ -2,7 +2,12 @@
<html lang="de" data-i18n-titel="seiten_titel">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<!-- viewport-fit=cover ist die Voraussetzung dafuer, dass env(safe-area-inset-*)
ueberhaupt einen Wert liefert. Ohne diese Angabe gibt jedes env() null zurueck
-- die Sicherheitsabstaende im CSS waeren totes Recht. Zusammen mit
apple-mobile-web-app-status-bar-style=black-translucent (siehe unten) laeuft
der Inhalt sonst installiert unter Uhr und Akkuanzeige. -->
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
<title>Über Dogfather — Dogfather Webdesign</title>
<meta name="description" content="Keine Agentur, keine Ticketnummer: wer hier baut, wie gearbeitet wird und woran das gelernt wurde." />
<meta name="robots" content="noindex, nofollow, noarchive" />
+86 -6
View File
@@ -2,7 +2,12 @@
<html lang="de">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<!-- viewport-fit=cover ist die Voraussetzung dafuer, dass env(safe-area-inset-*)
ueberhaupt einen Wert liefert. Ohne diese Angabe gibt jedes env() null zurueck
-- die Sicherheitsabstaende im CSS waeren totes Recht. Zusammen mit
apple-mobile-web-app-status-bar-style=black-translucent (siehe unten) laeuft
der Inhalt sonst installiert unter Uhr und Akkuanzeige. -->
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
<title>Verwaltung — Dogfather Webdesign</title>
<meta name="robots" content="noindex, nofollow, noarchive" />
<link rel="icon" type="image/png" href="/assets/img/favicon.png" />
@@ -53,10 +58,16 @@
padding-top: .2rem;
}
@media (max-width: 560px) {
/* Auf dem Handy darf der Name weichen -- der Platz gehört dem Titel. */
.vw-leiste { grid-template-columns: 1fr; }
.vw-leiste .vw-wer { grid-column: 1; grid-row: 3; justify-content: flex-start; }
.vw-leiste .vw-tabs { grid-row: 2; }
/* Titel und Abmelden bleiben zusammen in Zeile 1.
Die erste Fassung schob den Abmelden-Knopf in eine dritte Zeile.
Zusammen mit den damals zweizeiligen Reitern gingen so 190px
verloren, bevor die erste Zahl kam -- fast der halbe sichtbare
Bereich eines Handys, nur fuer die Kopfzeile. */
.vw-leiste { gap: .5rem .6rem; }
.vw-leiste h1 { font-size: 1.35rem; }
/* Der Name steht schon in der App-Leiste; hier kostet er nur Platz. */
.vw-leiste .vw-wer #vw-name { display: none; }
}
.vw-wer { display: flex; justify-content: flex-end; align-items: center; gap: .6rem; font-size: .9rem; color: var(--wd-text-soft); }
@@ -99,6 +110,18 @@
grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
margin-bottom: .4rem;
}
@media (max-width: 560px) {
/* Zwei Spalten statt einer.
Mit einer Kachel pro Zeile war die Uebersicht auf dem Handy
2635px lang -- man musste an allem vorbeiwischen, um das Geld zu
sehen, und der Sinn einer UEBERSICHT ist, dass man nicht wischen
muss. Zwei Spalten halbieren das. Die Schrift bleibt gleich
gross; verkleinert wuerde sie schwerer lesbar, und lesbar ist
hier wichtiger als kompakt. */
.vw-ub-gitter { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: .55rem; }
.vw-ub-kachel { padding: .8rem .75rem; }
}
.vw-ub-kachel {
display: flex; flex-direction: column; align-items: flex-start; gap: .18rem;
@@ -512,6 +535,41 @@
.vw-notiz p { margin: 0; font-size: .93rem; white-space: pre-wrap; }
.vw-tabs { display: flex; flex-wrap: wrap; gap: .4rem; }
@media (max-width: 700px) {
/* Sechs Reiter brauchen umgebrochen zwei bis drei Zeilen. Statt in
die Hoehe zu wachsen, wird daraus EIN Streifen zum Wischen.
overflow-x statt Umbruch, scroll-snap damit ein Reiter nie halb
abgeschnitten stehen bleibt, und ein Auslauf am rechten Rand
(die Maske unten), damit man SIEHT, dass es weitergeht -- ein
harter Schnitt sieht aus wie das Ende der Liste. */
.vw-tabs {
flex-wrap: nowrap;
overflow-x: auto;
scroll-snap-type: x proximity;
scrollbar-width: none;
/* Der Streifen darf ueber den Containerrand hinauslaufen und
nimmt den Innenabstand selbst mit -- sonst endet er optisch
mitten auf der Seite. */
margin-inline: calc(var(--wd-sicher-links, 0px) * -1 - 4px)
calc(var(--wd-sicher-rechts, 0px) * -1 - 4px);
padding-inline: 4px;
/* scroll-padding zusaetzlich zu padding.
Ohne das richtet scroll-snap den ersten Reiter am SCROLLRAND
aus und schluckt den Innenabstand: Der Knopf sass dann bei 12px
statt bei 16px und stand damit vier Pixel links neben dem Titel
darueber -- eine Fehlstellung, die man sieht, aber schwer
benennen kann. scroll-padding verschiebt die Einrastkante nach
innen, sodass Titel und erster Reiter buendig sind. */
scroll-padding-inline: 4px;
padding-bottom: 2px;
-webkit-overflow-scrolling: touch;
mask-image: linear-gradient(90deg, #000 0, #000 calc(100% - 26px), transparent 100%);
}
.vw-tabs::-webkit-scrollbar { display: none; }
.vw-tabs > * { scroll-snap-align: start; flex: 0 0 auto; }
}
.vw-link-anzeige {
padding: 1rem; border-radius: 14px;
background: rgb(var(--wd-gold-rgb) / .08); border: 1px solid rgb(var(--wd-gold-rgb) / .35);
@@ -972,8 +1030,17 @@
<div class="vw-pf">
<div id="vw-pf-liste"><div class="vw-laedt">Wird geladen…</div></div>
<div id="vw-pf-verlauf" class="wd-karte">
<!-- Bewusst OHNE Richtungsangabe.
Vorher stand hier "Waehle links einen Verlauf aus".
Auf dem Handy gibt es kein links: Dort liegt die Liste
UEBER diesem Kasten, nicht daneben. Der Satz schickte
den Leser also an eine Stelle, an der nichts ist.
Richtungswoerter setzen ein Layout voraus, das es nur
auf einem breiten Bildschirm gibt -- und sie helfen
ohnehin niemandem, der die Seite vorgelesen bekommt. -->
<p class="wd-leise" style="text-align:center;padding:2rem 0">
Wähle links einen Verlauf aus.
Tippe einen Verlauf an, um ihn hier zu lesen.
</p>
</div>
</div>
@@ -1996,6 +2063,19 @@
document.querySelectorAll("[data-tab]").forEach(function (x) {
x.classList.toggle("vw-an", x.dataset.tab === aktiverTab);
});
/* Auf dem Handy sind die Reiter ein Wischstreifen. Wer ueber eine
Kachel nach "Postfach" springt, landet sonst in einer Ansicht,
deren Reiter ausserhalb des Streifens liegt -- man sieht dann
nirgends, wo man ist. Deshalb den aktiven Reiter heranholen.
Nur waagerecht, damit die Seite nicht zusaetzlich springt. */
var aktiv = document.querySelector('[data-tab="' + aktiverTab + '"]');
if (aktiv && aktiv.scrollIntoView) {
try {
aktiv.scrollIntoView({ block: "nearest", inline: "center", behavior: "smooth" });
} catch (e) {
aktiv.scrollIntoView(); // aeltere Browser kennen die Angaben nicht
}
}
/* Vorher war das eine Ja/Nein-Umschaltung zwischen zwei Bereichen.
Mit vier Reitern geht das nicht mehr: Jede neue Ansicht haette
eine weitere Zeile "hidden = ..." gebraucht, und beim naechsten
+6 -1
View File
@@ -2,7 +2,12 @@
<html lang="de" data-i18n-titel="wr_titel">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<!-- viewport-fit=cover ist die Voraussetzung dafuer, dass env(safe-area-inset-*)
ueberhaupt einen Wert liefert. Ohne diese Angabe gibt jedes env() null zurueck
-- die Sicherheitsabstaende im CSS waeren totes Recht. Zusammen mit
apple-mobile-web-app-status-bar-style=black-translucent (siehe unten) laeuft
der Inhalt sonst installiert unter Uhr und Akkuanzeige. -->
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
<title>Vertrag widerrufen — Dogfather Webdesign</title>
<meta name="description" content="Elektronische Widerrufsfunktion nach § 356a BGB — Vertrag online widerrufen, mit sofortiger Eingangsbestätigung." />
<meta name="robots" content="noindex, follow" />
+6 -1
View File
@@ -2,7 +2,12 @@
<html lang="de" data-i18n-titel="seiten_titel">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<!-- viewport-fit=cover ist die Voraussetzung dafuer, dass env(safe-area-inset-*)
ueberhaupt einen Wert liefert. Ohne diese Angabe gibt jedes env() null zurueck
-- die Sicherheitsabstaende im CSS waeren totes Recht. Zusammen mit
apple-mobile-web-app-status-bar-style=black-translucent (siehe unten) laeuft
der Inhalt sonst installiert unter Uhr und Akkuanzeige. -->
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
<title>Zugang — Dogfather Webdesign</title>
<!-- Doppelt abgesichert: server/webdesign-gate.js schickt zusätzlich einen
X-Robots-Tag-Header. Der Header wirkt auch dann, wenn die Seite gar