fix: Dokumenten- und Download-Menü klappen auf Mobil wieder auf (D50)

Gemeldet: „Dokumente aufklappen/auswählen funktioniert in Mobilansicht nicht."
Regression aus D47, einen Tag alt.

Ursache: Das dort eingeführte `overflow-x:auto` macht aus der Titelzeile einen
Scroll-Container — und beide Aufklapp-Menüs hängen als absolut positionierte
Kinder genau darin (`#docMenu` im Editor-Kopf, `.dlmenu` im Diagramm-Kopf).
Übersehen war dabei eine CSS-Regel: `overflow-x` auf etwas anderes als
`visible` hebt ein `visible` der ANDEREN Achse auf `auto`. Geklippt wurde also
nicht seitlich, sondern nach unten — dorthin, wo die Menüs aufklappen. Und ein
Scroll-Container klippt, ob er überläuft oder nicht: Der Fehler traf jede
Mobilbreite, nicht nur die schmalen, für die die Regel gedacht war.

Nachgestellt bei 375 px: Das Dokumenten-Menü ist 153 px hoch und beginnt
156 px unterhalb der Kopfunterkante (clientHeight 43, scrollHeight 200);
`elementFromPoint` an seiner Stelle liefert das Textfeld. Beim Download-Menü
dasselbe. Das Menü war also nicht schwer zu treffen, sondern gar nicht da.

Behoben durch Wegnahme: kein `overflow` mehr an der Zeile. An seine Stelle
tritt Umbrechen, aber nur unter 360 px, wo neun Fingerziele arithmetisch nicht
nebeneinander passen; darüber bleibt `nowrap`. Erwogen und verworfen war,
die Menüs per `position:fixed` aus dem Container zu heben — JS-Geometrie für
etwas, das CSS allein konnte, und der Preis stand in keinem Verhältnis: Das
`overflow` diente nur Breiten unter 360 px, kaputt waren die Menüs überall.
`flex:0 0 auto` gegen den zerdrückten Modus-Wähler bleibt.

Nachgemessen — und zwar die Bedienung, nicht die Geometrie, denn genau darin
war der Fehler unsichtbar (die Zeile war weiter 49 px hoch, alle Knöpfe an
ihrem Platz): Bei 375 px und 320 px trifft `elementFromPoint` im geöffneten
Menü `.docitem` bzw. `.dlmenu`, und ein Klick wechselt das Dokument wirklich
(Werkbaum -> Example: Titel, `werkbaum-active`, neu gebauter Baum). Kopfzeile
375 px eine Reihe zu 49 px, 320 px zwei Reihen zu 78 px mit allen neun
Elementen vollständig sichtbar. Desktop unverändert. 236 Tests grün.

D47 bekommt den Verweis, dass sein `overflow` zurückgenommen ist; gelöscht
wird dort nichts. frontend/CLAUDE.md warnt jetzt vor `overflow` an Leisten,
die Menüs tragen — samt dem Hinweis, dass man das nicht an Maßen sieht.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
mhoennig
2026-08-23 14:40:30 +02:00
co-authored by Claude Fable 5
parent 1b8bf06973
commit ec338eb558
3 changed files with 88 additions and 9 deletions
+63
View File
@@ -3076,6 +3076,12 @@ wieder 40 px breit). Das ist die ehrliche Fortschreibung der D17-Regel: Der
Riegel sollte einen unbemerkten Layout-Wechsel verhindern, nicht ein Riegel sollte einen unbemerkten Layout-Wechsel verhindern, nicht ein
Bedienelement opfern. Bedienelement opfern.
*(Das `overflow-x:auto` war ein Fehler und ist zurückgenommen — es machte aus
der Kopfzeile einen Scroll-Container und klippte damit die beiden
Aufklapp-Menüs, die als absolut positionierte Kinder darin hängen. Was an
seine Stelle tritt und warum es niemandem auffiel: **D50**. `flex:0 0 auto`
gegen den zerdrückten Modus-Wähler bleibt.)*
## D48 — Der Werkbaum-Plan erklärt sich selbst: ID und Beschreibung an jedem Knoten ## D48 — Der Werkbaum-Plan erklärt sich selbst: ID und Beschreibung an jedem Knoten
Der mitgelieferte Plan (D27) ist zugleich Vorzeigedokument und Projektübersicht Der mitgelieferte Plan (D27) ist zugleich Vorzeigedokument und Projektübersicht
— und war für Fremde weitgehend stumm. Ein Knoten wie „Stay greedy, but say so" — und war für Fremde weitgehend stumm. Ein Knoten wie „Stay greedy, but say so"
@@ -3184,3 +3190,60 @@ rund 53 Zeichen und muss schieben. Wer dort viel liest, zieht den Splitter auf
oder wechselt in die Textansicht. Ein Umschalter dafür wurde nicht gebaut — aus oder wechselt in die Textansicht. Ein Umschalter dafür wurde nicht gebaut — aus
demselben Grund wie in D33: ein Bedienelement plus neun Übersetzungen für einen demselben Grund wie in D33: ein Bedienelement plus neun Übersetzungen für einen
Zustand, den kaum jemand umstellen will. Zustand, den kaum jemand umstellen will.
## D50 — Kein `overflow` an der Titelzeile: sie trägt die Aufklapp-Menüs
Gemeldet: „Dokumente aufklappen/auswählen funktioniert in Mobilansicht nicht."
Eine Regression aus D47, einen Tag alt.
**Ursache.** D47 gab der Titelzeile auf Mobil `overflow-x:auto`, damit bei
320 px alle neun Bedienelemente erreichbar bleiben. Damit wird sie zum
**Scroll-Container** — und beide Aufklapp-Menüs hängen als absolut
positionierte Kinder genau darin: `#docMenu` (Dokumente) im Editor-Kopf,
`.dlmenu` (Download) im Diagramm-Kopf. Beide standen anschließend im
abgeschnittenen Bereich.
**Der Teil, der beim Bauen übersehen wurde, ist eine CSS-Regel:** `overflow-x`
auf etwas anderes als `visible` zu setzen hebt ein `visible` der **anderen
Achse** auf `auto`. Gemessen: `overflow-x:auto``overflow-y:auto`. Geklippt
wurde also nicht seitlich, wo man es beabsichtigt hatte, sondern **nach
unten** — dorthin, wo die Menüs aufklappen. Deshalb war der Fehler auch nicht
auf schmale Geräte beschränkt: Ein Scroll-Container klippt, ob er überläuft
oder nicht, also auf **jeder** Mobilbreite.
Nachgestellt bei 375 px: Das Dokumenten-Menü ist 153 px hoch und beginnt 156 px
unterhalb der Kopfunterkante (`clientHeight` 43, `scrollHeight` 200);
`elementFromPoint` an seiner Stelle liefert das Textfeld. Das Download-Menü
ebenso — dort kam der Diagramm-Hintergrund zurück. Aufklappen ging also nicht
bloß „nicht gut", das Menü war gar nicht da.
**Behoben durch Wegnahme, nicht durch einen Umweg.** Erwogen war, die Menüs per
`position:fixed` aus dem Container zu heben und beim Öffnen aus dem
Trigger-Rechteck zu positionieren — das hätte beides gerettet, aber JS-Geometrie
für etwas eingeführt, das CSS bisher allein konnte, samt Nachführen bei jeder
Größenänderung. Der Preis stand in keinem Verhältnis zum Gewinn: Das `overflow`
diente **ausschließlich** Breiten unter rund 360 px, kaputt waren die Menüs
**überall**.
**An seine Stelle tritt Umbrechen — aber nur dort, wo es rechnerisch nicht
passt.** Unter 360 px (`@media (max-width:360px)`) darf die Zeile umbrechen;
darüber bleibt `nowrap` als Riegel. Das nimmt D17-Nachtrag 5 nicht zurück: Der
Riegel sollte einen **unbemerkten** Layout-Wechsel verhindern, und ein Umbruch
bei einer Breite, bei der neun Fingerziele arithmetisch nicht nebeneinander
passen, ist keine Überraschung, sondern die einzige ehrliche Möglichkeit.
Nachgemessen: 375 px eine Reihe zu 49 px, alles innerhalb; 320 px zwei Reihen zu
78 px, alle neun Elemente vollständig sichtbar, Modus-Wähler weiterhin 40 px
breit (`flex:0 0 auto` aus D47 bleibt und ist unabhängig richtig).
**Geprüft ist jetzt die Bedienung, nicht die Geometrie.** Der D47-Nachweis
bestand aus Breiten und Höhen — und genau darin war der Fehler unsichtbar, weil
die Kopfzeile ja weiterhin 49 px hoch war und alle Knöpfe an ihrem Platz saßen.
Gemessen wird deshalb jetzt, ob das Menü nach dem Öffnen an seiner eigenen
Stelle auch **getroffen** wird (`elementFromPoint` landet auf `.docitem` bzw.
`.dlmenu`) und ob ein Klick darauf das Dokument wirklich wechselt (Werkbaum →
Example: Titel, `werkbaum-active` und der neu gebaute Baum). Beides bei 375 px
und bei 320 px.
**Lehre, im selben Geist wie D25 und D17-Nachtrag 4:** Wer einer Leiste
`overflow` gibt, entscheidet damit über alles, was aus ihr herausragen soll —
Menüs, Tooltips, Overlays. In `frontend/CLAUDE.md` steht das jetzt bei der
Kopfzeilen-Stolperfalle.
+15 -5
View File
@@ -504,11 +504,21 @@ verworfene Elemente. Quelle sind ES-Module unter `src/`; `index.html` ist der
Hash-Rückfall, der Marker-Pfad ist nur zu prüfen, wenn man einen echten Hash-Rückfall, der Marker-Pfad ist nur zu prüfen, wenn man einen echten
`commit/<sha>` in `index.html` einspritzt (danach zurücknehmen!) und `commit/<sha>` in `index.html` einspritzt (danach zurücknehmen!) und
`window.fetch` überschreibt. `window.fetch` überschreibt.
- **Diagramm-Kopfzeile auf Mobil (D17-Nachtrag 5, D47):** Die Zeile ist voll — - **Titelzeilen tragen die Aufklapp-Menüs — kein `overflow` daran (D50):**
bei 375 px bleiben mit neun Bedienelementen noch 14 px Luft, bei 320 px passt `#docMenu` und `.dlmenu` hängen als absolut positionierte Kinder im
es arithmetisch nicht mehr und die Zeile **schiebt** (`overflow-x:auto`). `.panel-head`. Ein `overflow` dort macht ihn zum Scroll-Container und klippt
Wer ein zehntes Element hinzufügt, misst nach (`scrollWidth - clientWidth` sie; `overflow-x` hebt dabei das `visible` der **anderen** Achse auf `auto`,
am `.panel-head`) und rechnet damit, dass auf 375 px etwas weichen muss. geklippt wird also nach unten — genau dorthin, wo die Menüs aufklappen. Ein
Scroll-Container klippt unabhängig davon, ob er überläuft, der Fehler trifft
also jede Breite. Er ist rein geometrisch **nicht** zu sehen: Kopfhöhe und
Knopfpositionen bleiben korrekt. Prüfen heißt hier: Menü öffnen und mit
`elementFromPoint` nachsehen, ob man es trifft.
- **Diagramm-Kopfzeile auf Mobil (D17-Nachtrag 5, D47, D50):** Die Zeile ist
voll — bei 375 px bleiben mit neun Bedienelementen noch 14 px Luft, bei
320 px passt es arithmetisch nicht mehr und die Zeile **bricht um**
(`@media (max-width:360px)`, zwei Reihen zu 78 px). Wer ein zehntes Element
hinzufügt, misst nach (`scrollWidth - clientWidth` am `.panel-head`) und
rechnet damit, dass auf 375 px etwas weichen muss.
Nicht anfassen: die 29 px Knopfgröße (Fingerziel) und `flex:0 0 auto` an den Nicht anfassen: die 29 px Knopfgröße (Fingerziel) und `flex:0 0 auto` an den
Kindern — ohne das schrumpft bei Platzmangel ausgerechnet der Modus-Wähler Kindern — ohne das schrumpft bei Platzmangel ausgerechnet der Modus-Wähler
(das einzige Element ohne feste Größe) auf einen 2-px-Strich, während sein (das einzige Element ohne feste Größe) auf einen 2-px-Strich, während sein
+10 -4
View File
@@ -1128,10 +1128,16 @@
/* Unterhalb von rund 360 px ist es reine Arithmetik: neun Bedienelemente à /* Unterhalb von rund 360 px ist es reine Arithmetik: neun Bedienelemente à
29 px plus Lücken brauchen mehr, als dort überhaupt da ist (bei 320 px 29 px plus Lücken brauchen mehr, als dort überhaupt da ist (bei 320 px
fehlen 41 px). Kleiner als 29 px darf ein Fingerziel nicht werden fehlen 41 px). Kleiner als 29 px darf ein Fingerziel nicht werden
(D17-Nachtrag 5), also schiebt die Zeile. Bei 375 px bleiben 14 px Luft (D17-Nachtrag 5) dort darf die Zeile deshalb umbrechen.
dort ändert die Regel nichts, weil nichts überläuft. */ **Kein `overflow` an dieser Stelle** (D50): Die Kopfzeile trägt die beiden
body.mobile .panel-head{overflow-x:auto;scrollbar-width:none} Aufklapp-Menüs (Dokumente, Download) als absolut positionierte Kinder. Ein
body.mobile .panel-head::-webkit-scrollbar{display:none} Scroll-Container klippt sie und weil `overflow-x` das `visible` der
anderen Achse auf `auto` hebt, klippt er auch nach unten, wo die Menüs
stehen. Sie waren damit auf **jeder** Mobilbreite unerreichbar, nicht nur
auf den schmalen. */
@media (max-width:360px){
body.mobile .panel-head{flex-wrap:wrap}
}
/* Inhalte rund 25 % kleiner, damit mehr Plan auf die Fläche passt /* Inhalte rund 25 % kleiner, damit mehr Plan auf die Fläche passt
(D17-Nachtrag 2). Das Diagramm macht das über den CSS-`zoom` (Faktor auf (D17-Nachtrag 2). Das Diagramm macht das über den CSS-`zoom` (Faktor auf
den Nutzer-Zoom, siehe MOBILE_ZOOM in app.js); der Text über die den Nutzer-Zoom, siehe MOBILE_ZOOM in app.js); der Text über die