fix: Linie zum einzigen Kind riss ab (D29-Nachtrag 4)

Der Stiel aus dem Elternknoten sitzt bei 50 % der Gruppe, der Stiel zum
Kind bei `--stem-x` (der gemessenen Knotenmitte, Nachtrag 2). Für
`li:only-child` ist die waagerechte Sammelleiste abgeschaltet — richtig,
solange beide zusammenfallen, und das tun sie nur, solange der Knoten in
seiner Zelle zentriert steht. Bei einer Treppe darunter sind es gemessen
8,5 px Versatz, bei einem `li.has-or` als einzigem Kind 41,8 px.

Jetzt verbindet ein Leiterstück genau zwischen 50 % und `--stem-x` die
beiden — dieselbe L-Form wie bei einem äußeren Kind einer größeren
Gruppe; ohne `--stem-x` ist es 0 px breit und unsichtbar.

Dabei aufgefallen: `:only-child::after{border-left}` stand vor
`:last-child::after{border:0 none}` und war bei gleicher Spezifität seit
jeher wirkungslos. Der ganze Block steht nun dahinter.

Kein Rückschritt von D61 — mit ausgeschaltetem Pfad derselbe Versatz;
die Zugabe steht seither nur in voller Farbe statt blass da. Der
Grafikexport war nie betroffen (die Leiste schließt dort die Elternmitte
ein).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
mhoennig
2026-08-24 14:20:26 +02:00
co-authored by Claude Opus 5
parent 36b78efa53
commit a60c466d82
4 changed files with 81 additions and 3 deletions
+1
View File
@@ -19,6 +19,7 @@ reverse.
## 2026-08-24 ## 2026-08-24
- Fix: the line to an only child was torn where the child does not sit centred in its cell
- An optional node (`+`) joins the cheapest path while it is being worked on — started work is the open front - An optional node (`+`) joins the cheapest path while it is being worked on — started work is the open front
- Fix: a started alternative lost its `|`/`=` group to an untouched cheaper one, although the choice was already made - Fix: a started alternative lost its `|`/`=` group to an untouched cheaper one, although the choice was already made
- A node written as an id alone (`- #US-123`) is now titled by that id, instead of being ignored - A node written as an id alone (`- #US-123`) is now titled by that id, instead of being ignored
+51
View File
@@ -1304,6 +1304,57 @@ Geprüft wurde im Browser — auch der Moduswechsel hin und zurück, mehrfach: D
Gruppe entsteht und löst sich rückstandsfrei auf, Knotenzahl und Dokumentordnung Gruppe entsteht und löst sich rückstandsfrei auf, Knotenzahl und Dokumentordnung
bleiben in allen drei Modi gleich. bleiben in allen drei Modi gleich.
**Nachtrag 4 — beim einzigen Kind riss die Linie ab: `--stem-x` ohne
Sammelleiste.** Gemeldet als „die Linie zwischen `#fe` und `#fe.rel` ist
abgerissen" an einem Baum mit genau einem Zerlegungsknoten und einer Treppe
darunter. Nachgemessen sind es zwei Stiele an **verschiedenen** Stellen:
- `ul.and::before` — der Stiel aus dem Elternknoten — sitzt bei **50 % der
Gruppe** (gemessen `left: 136,2px`);
- der Stiel zum Kind sitzt bei **`--stem-x`** (gemessen `127,7px`), also auf der
Knotenmitte, die Nachtrag 2 eigens misst.
Dazwischen lag nichts: Für `li:only-child` wird die waagerechte Sammelleiste
ausdrücklich abgeschaltet (`border-top:none`) — richtig, solange beide Stiele
zusammenfallen, und das tun sie, solange der Knoten in seiner Zelle **zentriert**
steht. Genau diese Voraussetzung hebt Nachtrag 2 auf, und der `:only-child`-Fall
ist dabei übersehen worden: Er stammt aus der Zeit, als es `--stem-x` noch nicht
gab.
**Es ist nicht auf die Treppe beschränkt** — an einem `li.has-or` als einzigem
Kind (Knoten linksbündig, Zelle so breit wie der any-of-Teilbaum) sind es
gemessen **41,8 px** Versatz. Dass es bisher niemandem auffiel, liegt daran,
dass der Fall selten ist: Ein Elternknoten hat meist mehrere Kinder, und dann
trägt die Leiste. Aufgefallen ist er jetzt, weil eine angefangene Zugabe seit
D61 in voller Farbe dasteht statt blass.
**Behoben mit einem kurzen Leiterstück genau zwischen den beiden** —
`left:min(50%, var(--stem-x))` bis `right:calc(100% - max(50%, var(--stem-x)))`,
darunter der Abgang bei `--stem-x`. Also dieselbe L-Form, mit der ein äußeres
Kind einer größeren Gruppe angeschlossen ist; ohne `--stem-x` ist das Stück null
Pixel breit und damit unsichtbar (nachgemessen: `0.0`, gerade Linie wie bisher).
Erwogen und verworfen: **den Stiel des Elternknotens auf `--stem-x` zu ziehen.**
Eine Zeile weniger, aber er träte dann nicht mehr aus der Mitte des
Elternknotens aus — bei 8 px unauffällig, bei den gemessenen 42 px nicht mehr,
und bei einem schmalen Elternknoten käme er neben ihm heraus.
**Dabei aufgefallen: `ul.and>li:only-child::after{border-left:…}` war seit jeher
wirkungslos.** Die Regel stand **vor** `ul.and>li:last-child::after{border:0
none}`, und bei gleicher Spezifität gewinnt die spätere — ein einziges Kind ist
auch das letzte. Gezeichnet wurde der Abgang stattdessen von der
`border-right`-Kante des `::before` (aus `:last-child::before`), 16 px lang bei
14 px Innenabstand, also 2 px über den Knoten hinaus. Der ganze `:only-child`-
Block steht jetzt **hinter** den first/last-Regeln, und die Absicht der Zeile
gilt endlich.
**Der Grafikexport hatte den Fehler nie:** `diagramToSvg()` spannt die
Sammelleiste über `kids.map(cx).concat(p.cx)` — die Elternmitte ist immer
Teil der Strecke. Betroffen war allein das CSS. Nicht durch Tests gedeckt (wie
der Rest dieser Geometrie), geprüft im Browser an allen drei Fällen: einziges
Kind mit Versatz (Stück 41,8 px breit, Linie durchgehend), gewöhnliches
einziges Kind (0 px, gerade), zwei Kinder (unverändert).
## D30 — `[x]``[^]` per Beförderungs-Commit vor dem Deploy ## D30 — `[x]``[^]` per Beförderungs-Commit vor dem Deploy
Der mitgelieferte Werkbaum-Plan (D27) behauptete `[^]` („in Produktion") für Der mitgelieferte Werkbaum-Plan (D27) behauptete `[^]` („in Produktion") für
Funktionen, die nur auf der automatisch deployten Pages-Instanz lagen, nicht auf Funktionen, die nur auf der automatisch deployten Pages-Instanz lagen, nicht auf
+7
View File
@@ -458,6 +458,13 @@ verworfene Elemente. Quelle sind ES-Module unter `src/`; `index.html` ist der
der any-of-Teilbaum. `alignStems()` misst deshalb nach jedem `render()` (und der any-of-Teilbaum. `alignStems()` misst deshalb nach jedem `render()` (und
in `applyLayout`) die Knotenmitte und setzt `--stem-x`; Fallback im CSS ist in `applyLayout`) die Knotenmitte und setzt `--stem-x`; Fallback im CSS ist
`50%`. Messwerte durch `zoom` zurückrechnen, sonst stimmt es nur bei 100 %. `50%`. Messwerte durch `zoom` zurückrechnen, sonst stimmt es nur bei 100 %.
**Beim einzigen Kind trägt keine Sammelleiste** (`:only-child` schaltet sie
ab): Der Stiel aus dem Elternknoten sitzt bei 50 % der Gruppe, der zum Kind
bei `--stem-x` — fallen die auseinander, riss die Linie ab (D29-Nachtrag 4).
Die `:only-child`-Regeln ziehen deshalb ein Leiterstück zwischen beide und
müssen **hinter** den first/last-Regeln stehen: Ein einziges Kind ist auch
das letzte, und bei gleicher Spezifität gewinnt die spätere Regel — genau
daran war `:only-child::after` jahrelang wirkungslos.
- Kleiner Bildschirm: `body.mobile` (per `matchMedia`, ≤ 640 px) zeigt **genau - Kleiner Bildschirm: `body.mobile` (per `matchMedia`, ≤ 640 px) zeigt **genau
einen** Bereich — `body.pane-diagram` bzw. `body.pane-text`, umgeschaltet über einen** Bereich — `body.pane-diagram` bzw. `body.pane-text`, umgeschaltet über
je einen festen Knopf pro Titelzeile (`#paneToText`/`#paneToDiagram`, je einen festen Knopf pro Titelzeile (`#paneToText`/`#paneToDiagram`,
+22 -3
View File
@@ -1021,13 +1021,32 @@
border-top:2px solid var(--line);height:16px; border-top:2px solid var(--line);height:16px;
} }
ul.and>li::after{left:var(--stem-x, 50%);right:0;border-left:2px solid var(--line)} ul.and>li::after{left:var(--stem-x, 50%);right:0;border-left:2px solid var(--line)}
ul.and>li:only-child{padding-top:14px}
ul.and>li:only-child::before,ul.and>li:only-child::after{border-top:none}
ul.and>li:only-child::after{border-left:2px solid var(--line);height:14px}
ul.and>li:first-child::before, ul.and>li:first-child::before,
ul.and>li:last-child::after{border:0 none} ul.and>li:last-child::after{border:0 none}
ul.and>li:last-child::before{border-right:2px solid var(--line);border-radius:0 6px 0 0} ul.and>li:last-child::before{border-right:2px solid var(--line);border-radius:0 6px 0 0}
ul.and>li:first-child::after{border-radius:6px 0 0 0} ul.and>li:first-child::after{border-radius:6px 0 0 0}
/* Einziges Kind: Normalerweise fallen der Stiel aus dem Elternknoten
(`ul.and::before`, 50 % der Gruppe) und der Stiel zum Kind (`--stem-x`)
zusammen — eine gerade Linie, keine Leiste nötig. Steht der Knoten aber
nicht mittig in seiner Zelle (`li.has-or`, Treppe — dort misst
`alignStems()` die Knotenmitte, D29-Nachtrag 2), liegen die beiden
auseinander, und ohne Geschwister gibt es keine Sammelleiste, die sie
verbände: die Linie riss ab (gemessen: 8,5 px). Deshalb hier ein kurzes
Leiterstück genau zwischen den beiden — dieselbe L-Form, mit der ein
äußeres Kind einer größeren Gruppe angeschlossen ist. Ohne `--stem-x` ist
es null Pixel breit und damit unsichtbar. Diese Regeln müssen NACH den
first/last-Regeln stehen: `li:only-child` ist beides, und bei gleicher
Spezifität gewinnt die spätere. */
ul.and>li:only-child{padding-top:14px}
ul.and>li:only-child::before{
border:0 none;border-top:2px solid var(--line);border-radius:0;height:14px;
left:min(50%, var(--stem-x, 50%));
right:calc(100% - max(50%, var(--stem-x, 50%)));
}
ul.and>li:only-child::after{
border:0 none;border-left:2px solid var(--line);border-radius:0;height:14px;
left:var(--stem-x, 50%);right:0;
}
/* --- ANY OF: durchgehend gestrichelte graue Linien (Haupt- + Abzweige) --- */ /* --- ANY OF: durchgehend gestrichelte graue Linien (Haupt- + Abzweige) --- */
li.has-or{align-items:flex-start} li.has-or{align-items:flex-start}