Nichts wird mehr nach links oder rechts geschoben
Filipe, 28.09.2026: "ich will auch nicht dass man sachen nach links
und rechts schieben muss. perfektion das untereinander. ich will
niemals irgendwas nach links oder rechts swippen muessen." Dazu ein
Bildschirmfoto der Tafel "Gestaltung" mit waagerechter Rollleiste.
GEMESSEN, NICHT GERATEN
Ein grep nach `overflow-x` findet nur die absichtlichen Roller. Er
findet nicht die Stelle, an der ein Inhalt breiter ist als sein
Kasten und der Browser von sich aus eine Rollleiste anhaengt -- und
genau das war auf dem Bild zu sehen. `server/mess-quer.mjs` geht
deshalb im echten Browser jedes Element durch, auf fuenf
Bildschirmgroessen, in allen sieben Registern, bei offener und
zugeklappter Regie und in allen fuenf Anordnungen.
Erster Lauf: 78 Stellen. Davon waren 54 KEINE -- `overflow-x: hidden`
ist abgeschnittener Text, dort laesst sich nichts schieben. Die
Messung trennt das jetzt; wer es mitzaehlt, findet die echten nicht
mehr. Uebrig blieben vier Ursachen:
1. DIE REGISTER rollten absichtlich waagerecht. Auf 412 px standen
von 605 px Registern 193 rechts ausserhalb -- dass es
"Gestaltung" und "Spenden" gibt, erfuhr man nur beim Wischen auf
Verdacht. Sie brechen jetzt um. Das kostet oben rund 45 Pixel
und bringt Gewissheit dafuer.
2. `.stufen` STAND ZWEIMAL IN reaktion.css -- einmal fuer die
Stufenleiter der Spenden (`display: grid`), 600 Zeilen spaeter
fuer die Chat-Leiste Offen/Team/Zu (`display: flex`). Die
spaetere gewinnt: Die Stufenleiter stellte ihre drei Stufen
NEBENEINANDER, 572 Pixel in einer 327 Pixel schmalen Spalte.
Das ist die Rollleiste auf Filipes Bild. Die Chat-Leiste heisst
jetzt `.chatstufen` / `.chatstufe`.
Dritter Fall dieser Art nach `.tafel` und `.stufe-knopf`.
3. DIE TAFELN KONNTEN NICHT SCHRUMPFEN. Ein Gitterfeld hat von
sich aus `min-width: auto` und besteht auf seinem unteilbarsten
Inhalt. Mit `minmax(0, 1fr)` und `min-width: 0` bricht jetzt
alles um, statt hinauszulaufen.
4. DIE TRANSPORTLEISTE ragte am Handy 76 Pixel ueber beide Kanten
("Naechstes" war nur halb zu sehen). Zwei Gruende: `.transport__teil`
hatte kein `flex-wrap` (die mittlere Gruppe schon -- zwei Regeln
fuer dieselbe Sache, eine vergessen), und im Umschalter steht
ein ganzer Videotitel, der als Flex-Kind auf seiner vollen
Breite bestand.
NEBENBEFUND: EINE FESTE ZAHL VON GESTERN
Der Saal stand auf `height: calc(100dvh - 69px)` -- 69 war einmal
die gemessene Hoehe der Kopfleiste. Sie ist 73 geworden, und der
Saal endete damit 4 Pixel unter dem Fensterrand: Der Play-Knopf war
nur mit Scrollen zu erreichen. Die Antwort ist keine neue Zahl,
sondern eine Regel, die misst -- der Koerper ist jetzt eine Spalte,
die Kopfleiste nimmt, was sie braucht, der Saal bekommt den Rest.
(Dabei noch ein Spezifitaetsunfall: `.reaktion-seite` (0,1,0)
verliert gegen `body.start` (0,1,1) aus start.css.)
NEUE WACHEN
- `mess-quer.mjs` mit Gegenprobe (ohne die Reparaturen findet sie
47 px, mit ihnen nichts).
- pruef-reaktion: kein absichtliches `overflow-x: auto` mehr; und
zwei Grundregeln derselben Klasse mit verschiedenem `display`
sind ein Namensstreit. Der bisherige Waechter verglich nur
ZWISCHEN Stilvorlagen -- `.stufen` stand zweimal in DERSELBEN.
- pruef-css-klassen: jede Klammer hat ihr Gegenstueck. Beim
Umschreiben blieb heute das Ende einer Regel ohne ihren Anfang
stehen; der Browser wirft die Zeile weg und schliesst dafuer den
naechsten @media-Block zu frueh. Drei Befunde sahen daraufhin wie
Programmfehler aus.
MESSUNG NACHGEZOGEN
`mess-reaktion` stammte noch aus der Zeit vor "Regie links" und
"drei Kacheln" und meldete drei Dinge, die keine Fehler waren --
gemessen gegen den Stand von HEAD: identisch rot. Sie misst ausserdem
seit heute mit FINGER statt Mauszeiger; ohne `hasTouch` greift keine
einzige Regel aus `@media (pointer: coarse)`, und dort stehen alle
44-Pixel-Beruehrziele des Hauses.
OFFEN UND AUFGESCHRIEBEN
Am Handy bleibt bei offener Regie vom Bild nichts (0 px). Der Mangel
besteht seit dem Umbau "Regie links"; drei Versuche, ihn heute zu
loesen, haben Knoepfe verdeckt -- und ein verdeckter Knopf ist
schlimmer als ein kleines Bild. Die Versuche und der richtige Weg
(Tempo-Gruppe hinter einen Knopf, wie "Aa" im Chat) stehen in
reaktion.css. `mess-reaktion` meldet ihn als dritten Ausgang: nicht
als Fehler und nicht als bestanden.
GEPRUEFT
pruef-reaktion 384 / 0 (vorher 379)
pruef-spenden 172 / 0
pruef-buehne 36 / 0
pruef-css-klassen, -tippziele, -struktur, -handy: ohne Befund
mess-quer EXIT 0 -- 28 Stellen, fuenf Groessen, nichts rollt
mess-reaktion EXIT 0, 1 benannter offener Punkt
mess-buehne EXIT 0
This commit is contained in:
+123
-3
@@ -910,9 +910,30 @@ melde("=== 12. Die Regie ===");
|
||||
Klasse, um sie im Buehnenmodus wegzunehmen. Wer beides gleich
|
||||
behandelt, macht aus einer echten Regel eine, die staendig
|
||||
grundlos anschlaegt -- und die wird weggeklickt. */
|
||||
const eigeneAus = (datei) => new Set(
|
||||
[...roh(datei).matchAll(/(^|[\s,>+~(}])(\.(-?[a-zA-Z_][a-zA-Z0-9_-]*)[^{};,]*)\{/g)]
|
||||
.map((m) => m[3]));
|
||||
/* AM ANFANG DES SELEKTORS -- nicht irgendwo darin.
|
||||
|
||||
Der Kommentar oben sagte das schon; das Muster tat es nicht.
|
||||
Es nahm jede Klasse, der ein Trennzeichen vorausging -- also
|
||||
auch das `.kopfleiste` in `body.reaktion-seite > .kopfleiste`.
|
||||
Das ist aber genau die Bezugnahme, die erlaubt sein soll, und
|
||||
die Regel schlug am 28.09.2026 darauf an. Dass sie es bei
|
||||
`body[data-nur="buehne"] .kopfleiste` nicht tat, lag nur an
|
||||
einem Komma dahinter -- also am Zufall, nicht an der Absicht.
|
||||
|
||||
Jetzt wird jeder Selektor einzeln angesehen und gefragt, ob er
|
||||
MIT der Klasse beginnt. Das ist die Frage, um die es geht:
|
||||
„Benenne ich hier ein eigenes Bauteil?" */
|
||||
const eigeneAus = (datei) => {
|
||||
const raus = new Set();
|
||||
for (const m of roh(datei).matchAll(/([^{}]+)\{/g)) {
|
||||
for (const teil of m[1].split(",")) {
|
||||
const t = teil.trim();
|
||||
const k = t.match(/^\.(-?[a-zA-Z_][a-zA-Z0-9_-]*)/);
|
||||
if (k) raus.add(k[1]);
|
||||
}
|
||||
}
|
||||
return raus;
|
||||
};
|
||||
|
||||
const meine = eigeneAus("reaktion.css");
|
||||
const streit = [];
|
||||
@@ -935,6 +956,105 @@ melde("=== 12. Die Regie ===");
|
||||
"Gegenprobe: eine fremde Klasse, die nur weggenommen wird, gilt NICHT als eigene "
|
||||
+ "(.kopfleiste im Buehnenmodus)");
|
||||
|
||||
/* ---- Und derselbe Streit INNERHALB einer Datei -----------------
|
||||
|
||||
`.stufen` stand am 28.09.2026 zweimal in reaktion.css: einmal
|
||||
fuer die Stufenleiter der Spenden (`display: grid`), 600 Zeilen
|
||||
spaeter fuer die Chat-Leiste Offen/Team/Zu (`display: flex`).
|
||||
Die spaetere gewinnt -- und damit stand die Stufenleiter
|
||||
nebeneinander statt untereinander und rollte waagerecht.
|
||||
|
||||
GEZAEHLT WIRD NUR, WAS SICH WIDERSPRECHEN KANN: zwei Regeln,
|
||||
deren Auswahl NUR aus der Klasse besteht (kein Zustand, kein
|
||||
Kontext, kein Attribut) und die BEIDE `display` setzen. Zwei
|
||||
Regeln zu derselben Klasse sind sonst voellig normal --
|
||||
`.knopf { }` und `.knopf:hover { }` gehoeren zusammen. Wer
|
||||
jede Wiederholung meldet, baut eine Warnung, die immer kommt,
|
||||
und die wird weggeklickt. */
|
||||
/* ZWEI EINSCHRAENKUNGEN, BEIDE GEMESSEN UND NOETIG.
|
||||
|
||||
(1) Die Auswahl muss GENAU die Klasse sein. Sonst zaehlt
|
||||
`.pult[data-auf="ja"] .pult__innen { display: grid }` als
|
||||
zweite Grundregel zu `.pult__innen { display: none }` -- und
|
||||
das ist kein Streit, sondern derselbe Bauteil in zwei
|
||||
Zustaenden.
|
||||
|
||||
(2) `display: none` zaehlt nicht mit. „Erst versteckt, dann
|
||||
gezeigt" ist das haeufigste Paar im ganzen Haus. Wer es
|
||||
meldet, baut eine Warnung, die bei fuenf harmlosen Stellen
|
||||
anschlaegt -- und beim sechsten, echten Fall hat sie
|
||||
niemand mehr gelesen.
|
||||
|
||||
Uebrig bleibt genau das, was sich widersprechen KANN: zwei
|
||||
Grundregeln, die beide sagen, WIE das Bauteil gebaut ist --
|
||||
`grid` gegen `flex`, wie bei `.stufen`. */
|
||||
const positiv = (wert) => wert && wert !== "none" && !/^none/.test(wert);
|
||||
const lies = (text) => {
|
||||
const raus = {};
|
||||
for (const m of text.matchAll(/(^|[\s};])(\.(-?[a-zA-Z_][a-zA-Z0-9_-]*))\s*\{([^{}]*)\}/g)) {
|
||||
const wert = (m[4].match(/(?:^|[\s;])display\s*:\s*([^;]+)/) || [, ""])[1].trim();
|
||||
if (!positiv(wert)) continue;
|
||||
(raus[m[3]] ||= []).push(wert);
|
||||
}
|
||||
return raus;
|
||||
};
|
||||
const streitIn = (text) => Object.entries(lies(text))
|
||||
.filter(([, was]) => new Set(was).size > 1)
|
||||
.map(([name, was]) => `${name} (${[...new Set(was)].join(" vs. ")})`);
|
||||
|
||||
const grundregeln = lies(roh("reaktion.css"));
|
||||
const doppelt = streitIn(roh("reaktion.css"));
|
||||
ok(Object.keys(grundregeln).length > 20 && doppelt.length === 0,
|
||||
doppelt.length
|
||||
? `Namensstreit in reaktion.css selbst: ${doppelt.join(", ")}`
|
||||
: `${Object.keys(grundregeln).length} Klassen sagen, WIE sie gebaut sind `
|
||||
+ "-- keine davon zweimal verschieden");
|
||||
|
||||
/* GEGENPROBE: Findet die Regel einen eingeschobenen Streit? Ohne
|
||||
diese Zeile waere oben nur bewiesen, dass sie „in Ordnung"
|
||||
sagen kann. Eingeschoben wird genau der Fall vom 28.09.: eine
|
||||
zweite Grundregel mit einem anderen positiven display. */
|
||||
ok(streitIn(roh("reaktion.css") + " .pult-tafel { display: flex; } ")
|
||||
.some((z) => z.startsWith("pult-tafel (")),
|
||||
"Gegenprobe: eine zweite Grundregel mit anderem display faellt auf");
|
||||
|
||||
/* UND IN DIE ANDERE RICHTUNG: Ein Bauteil, das erst versteckt und
|
||||
dann gezeigt wird, darf NICHT anschlagen -- sonst haette man
|
||||
die Regel nur so lange geschaerft, bis sie alles meldet. */
|
||||
ok(streitIn(" .probe { display: none; } .probe { display: grid; } ").length === 0
|
||||
&& streitIn(" .probe { display: grid; } .probe { display: flex; } ").length === 1,
|
||||
"Gegenprobe: verstecken-und-zeigen ist kein Streit, grid-gegen-flex schon");
|
||||
|
||||
/* ---- Nichts rollt absichtlich waagerecht ----------------------
|
||||
|
||||
Filipe, 28.09.2026: „ich will auch nicht dass man sachen nach
|
||||
links und rechts schieben muss. perfektion das untereinander.
|
||||
ich will niemals irgendwas nach links oder rechts swippen
|
||||
muessen."
|
||||
|
||||
Bis dahin rollten die sieben Register waagerecht, mit einer
|
||||
Begruendung, die fuer sich stimmte (zwei Zeilen kosten oben 45
|
||||
Pixel). Sie kostete dafuer die Gewissheit: Auf 412 Pixeln
|
||||
standen 193 Pixel Register rechts ausserhalb, und dass es
|
||||
„Gestaltung" und „Spenden" gibt, erfuhr man nur beim Wischen
|
||||
auf Verdacht.
|
||||
|
||||
DIESE PRUEFUNG FINDET NUR DIE ABSICHTLICHEN ROLLER. Die
|
||||
entstehenden -- ein Inhalt, der breiter ist als sein Kasten --
|
||||
sieht man im Quelltext nicht; dafuer gibt es
|
||||
`server/mess-quer.mjs`, das im echten Browser jedes Element
|
||||
nachmisst. Beide zusammen, keines allein. */
|
||||
const roller = [...roh("reaktion.css")
|
||||
.matchAll(/([^{}]+)\{([^{}]*overflow-x\s*:\s*(auto|scroll)[^{}]*)\}/g)]
|
||||
.map((m) => m[1].trim().split(String.fromCharCode(10)).pop().trim());
|
||||
ok(roller.length === 0,
|
||||
roller.length ? `rollt waagerecht: ${roller.join(", ")}`
|
||||
: "nichts in reaktion.css rollt absichtlich waagerecht");
|
||||
ok(/overflow-x/.test(roh("reaktion.css") + "x{overflow-x:auto}")
|
||||
&& [...("y{overflow-x: auto}").matchAll(
|
||||
/([^{}]+)\{([^{}]*overflow-x\s*:\s*(auto|scroll)[^{}]*)\}/g)].length === 1,
|
||||
"Gegenprobe: der Sucher findet ein overflow-x, wenn eines dasteht");
|
||||
|
||||
/* Der Pegel wird gemessen und nicht gemalt. */
|
||||
ok(/createAnalyser\(\)/.test(js) && /getByteTimeDomainData/.test(js),
|
||||
"die Pegel kommen aus einer echten Messung");
|
||||
|
||||
Reference in New Issue
Block a user