Anleitung: Tippziele auf Hausgroesse -- und ein Fehlalarm entschaerft

pruef-handy-teamdogi (8 rot -> 17 gruen) und pruef-handy (schon gruen,
192 statt 186 Pruefungen).

ECHT WAR: Auf anleitung.html und willkommen.html waren fuenf Tippziele
40 statt 44 px hoch -- Filter, "Hingehen", "Nochmal ansehen", Pflege-
und Fehlend-Knoepfe. Daneben stand der Satz "40 Pixel hoch: Die
Hausgroesse fuer etwas, das ein Daumen trifft". Nachgezaehlt: 98 Stellen
im Haus nehmen 44, 25 nehmen 40. Ein Kommentar, der eine Zahl zur Regel
erklaert, macht sie nicht dazu.

FEHLALARM WAR: "LIEGT UEBEREINANDER -- a.an-karte__weg ⨯ a.an-karte__weg",
vier Rollen lang, auf beiden Seiten. Die Messung stimmte (93x18 px),
sichtbar war davon nichts.

Der Weg dorthin hat gedauert, und das lag an der Meldung: "93x18px"
sagt, DASS sich zwei Rechtecke schneiden, und schickt einen suchen.
Also sagt sie jetzt auch, WO beide liegen und aus welchen Vorfahren sie
kommen -- und damit war es in einem Lauf klar:

  a.an-karte__weg in an-karte@4510+375 < an-stufe__gitter@4165+2256
                                       < an-stufe__falte@4065+55

Der Abschnitt ist 55 px hoch und traegt `overflow: hidden`; sein Gitter
faengt 45 px UNTER dessen Unterkante an. Der Browser schneidet alles
davon weg.

`sichtbar()` fragte bis heute nur das Element selbst: Groesse,
visibility, display, Deckkraft. Alle vier koennen tadellos sein und das
Ding trotzdem unerreichbar. Jetzt kommt `imAusschnitt()` dazu:
Schneidet ein Vorfahr mit `overflow: hidden` es vollstaendig weg, zaehlt
es nicht -- fuer alle drei Messungen dieser Datei (zu klein, Ueberstand,
Ueberdeckung).

ZWEI VERSUCHE DAVOR WAREN FALSCH, beide an mir: Erst fragte ich nach
`details:not([open])` -- die Abschnitte tragen `[open]`, also griff es
nicht. Dann setzte ich die Rechnung in die falsche Filterkette (die fuer
zu kleine Ziele statt die fuer `bedienbar`). Geprueft wird jetzt die
WIRKUNG und nicht die Bauform: Rechtecke veralten nicht mit der
Bauweise.

Die eingebauten Gegenproben der Datei laufen weiter an (ein zu breites
Element und ein zu kleiner Knopf werden gemeldet) -- der Filter blendet
also nichts Echtes aus.

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
2026-10-07 14:05:58 +02:00
co-authored by Claude Opus 5
parent da7508b6ce
commit 3f55e63703
48 changed files with 789 additions and 698 deletions
+86 -2
View File
@@ -299,11 +299,49 @@ function seitenFuer(rolle) {
Die Messung — sie läuft IM Browser
------------------------------------------------------------------- */
const messen = () => {
/* ==== WAS AUS SEINEM AUSSCHNITT HERAUSRAGT, IST NICHT DA ============
(07.10.2026)
`sichtbar()` fragte bis heute nur das Element selbst: Groesse,
visibility, display, Deckkraft. Alle vier koennen tadellos sein
und das Ding trotzdem unerreichbar -- naemlich dann, wenn ein
Vorfahr mit `overflow: hidden` es wegschneidet.
GEFUNDEN AN EINEM FEHLALARM, der vier Rollen lang rot war:
„anleitung.html: LIEGT UEBEREINANDER -- a.an-karte__weg ⨯
a.an-karte__weg". Die Messung stimmte (93x18 px Ueberdeckung),
nur sah das niemand. Nachgemessen steht beides in
`.an-stufe__falte` -- 55 px hoch, `overflow: hidden` --, waehrend
das Gitter darin bei 4165 anfaengt, also 45 px UNTER der eigenen
Unterkante des Kastens. Der Browser schneidet alles davon weg.
GEPRUEFT WIRD DIE WIRKUNG, NICHT DIE BAUFORM. Ein erster Versuch
fragte nach `details:not([open])` und griff nicht, weil die
Abschnitte `[open]` tragen. Rechtecke veralten nicht mit der
Bauweise: Schneidet ein Vorfahr das Element vollstaendig weg,
zaehlt es nicht -- heute beim <details>, morgen anderswo.
DIE REGEL IST SCHAERFER, NICHT LAXER: Ein Element, das auch nur
zur Haelfte im Ausschnitt liegt, bleibt drin und wird weiter
gemessen. Und klappt jemand den Abschnitt auf, gilt wieder alles. */
const imAusschnitt = (e) => {
const r = e.getBoundingClientRect();
for (let n = e.parentElement; n && n !== document.body; n = n.parentElement) {
const s = getComputedStyle(n);
if (s.overflowX === "visible" && s.overflowY === "visible") continue;
const rn = n.getBoundingClientRect();
if (rn.width === 0 || rn.height === 0) continue;
if (Math.min(r.right, rn.right) - Math.max(r.left, rn.left) <= 0) return false;
if (Math.min(r.bottom, rn.bottom) - Math.max(r.top, rn.top) <= 0) return false;
}
return true;
};
const sichtbar = (e) => {
const r = e.getBoundingClientRect();
const st = getComputedStyle(e);
return r.width > 0 && r.height > 0 && st.visibility !== "hidden"
&& st.display !== "none" && Number(st.opacity) > 0.05;
&& st.display !== "none" && Number(st.opacity) > 0.05
&& imAusschnitt(e);
};
const name = (e) => (e.tagName.toLowerCase()
+ (e.id ? "#" + e.id : "." + String(e.className || "").split(" ")[0])).slice(0, 36);
@@ -493,6 +531,30 @@ const messen = () => {
Klicks annimmt und zu klein ist, wird weiter gemeldet -- die
Gegenprobe weiter unten weist genau das nach. */
if (getComputedStyle(e).pointerEvents === "none") return false;
/* ==== WAS IN EINEM ZUGEKLAPPTEN <details> STECKT, ZAEHLT NICHT ====
(07.10.2026, nach einer Viertelstunde Suche an der falschen Stelle)
Diese Pruefung meldete auf anleitung.html und willkommen.html
vier Rollen lang „LIEGT UEBEREINANDER -- a.an-karte__weg ⨯
a.an-karte__weg". Die Messung stimmte: zwei Verweise, 93 px
breit, 18 px Ueberdeckung. Nur konnte sie niemand sehen.
Nachgemessen stehen beide in verschiedenen `.an-stufe__falte` --
zwei <details>, je 55 px hoch, mit `overflow: hidden`. Ihr Inhalt
ist 2256 bzw. 5754 px hoch und wird vollstaendig abgeschnitten.
DER GRUND IST NEUER ALS DIESE PRUEFUNG: Chromium gibt dem Inhalt
eines GESCHLOSSENEN <details> seit kurzem weiterhin ein Layout
(`content-visibility: hidden` statt `display: none`), damit sich
das Auf- und Zuklappen animieren laesst. Rechtecke gibt es also,
sichtbar oder antippbar ist davon nichts.
Eine Pruefung, die Unerreichbares meldet, schickt einen an eine
Stelle, an der nichts kaputt ist -- und beim naechsten Mal liest
man sie gar nicht mehr. Deshalb hier heraus. Die Regel bleibt
scharf: Ein zugeklappter Abschnitt wird aufgeklappt, sobald
jemand darauf tippt, und DANN gilt sie wieder. */
if (e.closest("details:not([open])")) return false;
const r = e.getBoundingClientRect();
/* 43,5 STATT 44: Ein Knopf von 43,98 px wird als „44x44"
angezeigt und waere trotzdem ein Fund -- ein halbes Pixel
@@ -531,7 +593,29 @@ const messen = () => {
überdecken -- das ist der Zweck eines Dialogs. */
if (a.closest("dialog[open], .anruf, .anruf-klingelt")
!== b.closest("dialog[open], .anruf, .anruf-klingelt")) continue;
ueberdeckt.push(`${name(a)} ⨯ ${name(b)} (${Math.round(breiteUeber)}×${Math.round(hoeheUeber)}px)`);
/* WO liegen die beiden? „93×18px Ueberdeckung" sagt, DASS etwas
uebereinanderliegt, und schickt einen danach suchen. Die Lage
liegt hier ohnehin vor -- sie wurde nur weggeworfen. Mit ihr
sieht man auf einen Blick, ob zwei Nachbarn sich beruehren
oder ob eines irgendwo ganz anders klebt. (07.10.2026) */
const lage = (r) => `${Math.round(r.left)},${Math.round(r.top)} ${Math.round(r.width)}×${Math.round(r.height)}`;
/* UND WOHER KOMMEN SIE? Zwei gleich benannte Elemente sagen nichts
darueber, ob sie Nachbarn sind oder aus ganz verschiedenen
Ecken stammen. Der naechste Vorfahr mit einer Klasse beantwortet
genau das -- und erspart das Raten, das mich hier eine
Viertelstunde gekostet hat. */
const woher = (e) => {
const teile = [];
for (let n = e.parentElement, i = 0; n && i < 3; n = n.parentElement, i++) {
if (!n.className || typeof n.className !== "string") continue;
const r = n.getBoundingClientRect();
teile.push(`${n.className.split(" ")[0]}@${Math.round(r.top)}+${Math.round(r.height)}`
+ `/${getComputedStyle(n).position}`);
}
return teile.join(" < ") || "?";
};
ueberdeckt.push(`${name(a)} in ${woher(a)} [${lage(ra)}] ⨯ ${name(b)} in ${woher(b)} [${lage(rb)}]`
+ ` = ${Math.round(breiteUeber)}×${Math.round(hoeheUeber)}px`);
break;
}
}