From db8dd2fbea4044e09285b7647331c4d85e68e7b8 Mon Sep 17 00:00:00 2001 From: Dogfather Date: Sat, 3 Oct 2026 12:37:05 +0200 Subject: [PATCH] 147 Zeichen je Zeile -- am Kontrast lag es nicht MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Filipe: „nur die kacheln noch viel geiler. so dass ich die texte auch besser erkenne." NAHELIEGEND WAERE GEWESEN, die Farben aufzuhellen. Erst gemessen, dann gebaut -- und die Vermutung war falsch: Kontrast .s-karte__text 15,7 : 1 (noetig 4,5) Kontrast aller zehn Textarten 7,5 bis 15,7 : 1 ZEICHEN JE ZEILE 147 (angenehm 45-75) Am Kontrast lag es nicht; der ist ueberall ueppig. Es lag an der ZEILENLAENGE. Auf 1280 px lief der Meldungstext ueber die ganze Kartenbreite: 1120 px, knapp 150 Zeichen. Beim Zeilenwechsel findet das Auge die naechste Zeile nicht mehr sicher -- man liest dieselbe zweimal oder ueberspringt eine. Das ist der groesste Hebel beim Lesen, und er kostet nichts. GEAENDERT Meldungstext 15,2 -> 17 px, max-width 72ch, Zeilenhoehe 1.6 Verlaufstext 14,4 -> 15,2 px, max-width 70ch Kartenrand 16/18/15/22 -> 18/20/16/24 px Trennlinie zwischen Meldung und Verlauf 147 -> 78 Zeichen je Zeile (PC), 39 auf dem Handy `ch` UND NICHT PIXEL: `ch` ist die Breite der Null und waechst mit der Schrift mit. Eine Angabe in Pixeln waere bei der naechsten Schriftgroesse wieder falsch -- dieselbe Falle wie jede feste Zahl. MEHR RAND, WEIL DIE SCHRIFT GEWACHSEN IST. Bei unveraendertem Rand haette sie die Kante beruehrt, und die Karte waere voller gewirkt statt lesbarer. Links bleibt es breiter: dort laeuft die Leuchtschiene in der Farbe des Stands. DIE TRENNLINIE kostet einen Pixel und beantwortet „wo hoert die Meldung auf und wo faengt die Vorgeschichte an?". Vorher lief beides ohne Zaesur ineinander. EIN FEHLER IN MEINER EIGENEN MESSUNG -- und er haette Schaden angerichtet Die erste Fassung der Kontrastrechnung meldete fuer drei gut lesbare Texte einen Kontrast von 1,04. Ich war nah dran, Farben zu „reparieren", die in Ordnung sind. Der Grund: `rgb()` zaehlt 0..255, `color(srgb …)` zaehlt 0..1 -- und genau das liefert Chrome fuer jedes `color-mix()`. 0,77 als 0,77/255 gelesen ist fast Schwarz. Aufgefallen ist es nur, weil die Zahl nicht zum Bildschirmfoto passte: Dort waren die Texte deutlich lesbar. DESHALB STEHT IN DER PRUEFUNG EINE GEGENPROBE IM BROWSER: Ein absichtlich zu blasser Absatz wird eingehaengt und MUSS auffallen (gemessen 1,23 : 1). Ohne sie waere „alle ueber 4,5" auch dann gruen, wenn die Rechnung kaputt ist -- und genau das war sie. GEPRUEFT -- pruef-support-bilder 56 -> 64 ok 9 Textarten in der Karte gemessen der Meldungstext ist 16.96 px gross (mindestens 16) und bricht nach etwa 78 Zeichen um (hoechstens 85, vorher 147) der Verlaufstext: 15.2 px, etwa 75 Zeichen jeder Text haelt die Kontrastschwelle (0 darunter) — schwaechster 7.55 : 1 Gegenprobe: ein absichtlich blasser Text faellt auf (1.23 : 1) auf 390 px ragt mit der groesseren Schrift nichts heraus (0 px) und die Zeile bleibt lesbar lang (etwa 39 Zeichen) Dazu gruen: pruef-css-klassen · pruef-fingermass. Co-Authored-By: Claude Opus 5 --- server/pruef-support-bilder.mjs | 152 +++++++++++++++++++++++++++++++ workspace/anruf-probe.html | 10 +- workspace/app.webmanifest | 8 +- workspace/assets/css/support.css | 53 ++++++++++- workspace/aufgaben.html | 38 ++++---- workspace/automation.html | 32 +++---- workspace/befinden.html | 34 +++---- workspace/bereich.html | 44 ++++----- workspace/bewerben.html | 38 ++++---- workspace/bewerbungen.html | 36 ++++---- workspace/buehne.html | 6 +- workspace/calls.html | 34 +++---- workspace/chat.html | 40 ++++---- workspace/content.html | 34 +++---- workspace/crew-index.html | 12 +-- workspace/crew.webmanifest | 8 +- workspace/dateien.html | 34 +++---- workspace/entwicklung.html | 36 ++++---- workspace/hilfe.html | 30 +++--- workspace/index.html | 10 +- workspace/kalender.html | 34 +++---- workspace/leistung.html | 32 +++---- workspace/manager-ziele.html | 28 +++--- workspace/material.html | 32 +++---- workspace/notizen.html | 28 +++--- workspace/personen.html | 32 +++---- workspace/profil.html | 36 ++++---- workspace/reaktion.html | 38 ++++---- workspace/rechte.html | 34 +++---- workspace/report.html | 36 ++++---- workspace/scouting.html | 32 +++---- workspace/start.html | 32 +++---- workspace/startcheck.html | 34 +++---- workspace/steckbrief.html | 36 ++++---- workspace/support.html | 28 +++--- workspace/tafel.html | 6 +- workspace/talente.html | 36 ++++---- workspace/team.html | 32 +++---- workspace/teamlage.html | 34 +++---- workspace/teilen.html | 30 +++--- workspace/treff-moderation.html | 32 +++---- workspace/treff-regeln.html | 32 +++---- workspace/uebersicht.html | 32 +++---- workspace/unsere-seiten.html | 30 +++--- workspace/unterstuetzen.html | 32 +++---- workspace/werdegang.html | 32 +++---- workspace/willkommen.html | 30 +++--- workspace/wissen.html | 34 +++---- 48 files changed, 885 insertions(+), 688 deletions(-) diff --git a/server/pruef-support-bilder.mjs b/server/pruef-support-bilder.mjs index d52bc5f5..3ad51714 100644 --- a/server/pruef-support-bilder.mjs +++ b/server/pruef-support-bilder.mjs @@ -656,6 +656,158 @@ melde("\n=== Eine Farbe je Runde ==="); await h.kontext.close(); } +/* ===================================================================== + 7. SIND DIE TEXTE IN DER KARTE ZU LESEN? (03.10.2026) + ===================================================================== + + Filipe: „nur die kacheln noch viel geiler. so dass ich die texte + auch besser erkenne." + + GEMESSEN, BEVOR ETWAS ANGEFASST WURDE -- und die naheliegende + Vermutung war falsch: + + Kontrast aller zehn Textarten 7,5 bis 15,7 : 1 + ZEICHEN JE ZEILE 147 + + Am Kontrast lag es nicht. Es lag an der Zeilenlaenge: Auf 1280 px + lief der Meldungstext ueber 1120 px, also knapp 150 Zeichen. + Angenehm sind 45 bis 75; darueber findet das Auge beim + Zeilenwechsel die naechste Zeile nicht mehr sicher. + + ZWEI ZAHLEN WERDEN DESHALB GEPRUEFT, und beide mussten vorher + gemessen werden, um sie ueberhaupt zu kennen. Eine Regel, die aus + einer Messung kommt, ist etwas anderes als eine, die man sich + ausdenkt. + ===================================================================== */ +melde("\n=== Sind die Texte zu lesen? ==="); +{ + const { kontext, seite } = await neueSeite(1280, keksModi); + await seite.locator(".s-karte__text").first().waitFor({ timeout: 8000 }); + + const lesbar = await seite.evaluate(() => { + /* ==== ZWEI SCHREIBWEISEN, EINE EINHEIT ====================== + + `rgb()` zaehlt 0..255, `color(srgb …)` zaehlt 0..1 -- und + genau das liefert Chrome fuer jedes `color-mix()`. Beim Bauen + dieser Messung hat mich das getaeuscht: 0,77 als 0,77/255 + gelesen ergibt fast Schwarz, und drei gut lesbare Texte + standen mit Kontrast 1,04 da. Fast haette ich Farben + repariert, die in Ordnung sind. */ + const zahl = (t) => { + const n = (t.match(/[\d.]+/g) || []).map(Number); + if (/^color\(/.test(t)) { + return [n[0] * 255, n[1] * 255, n[2] * 255, n.length > 3 ? n[3] : 1]; + } + return n; + }; + const kanal = (c) => { + const x = c / 255; + return x <= 0.03928 ? x / 12.92 : ((x + 0.055) / 1.055) ** 2.4; + }; + const hell = ([r, g, b]) => 0.2126 * kanal(r) + 0.7152 * kanal(g) + 0.0722 * kanal(b); + const mischen = (v, h, a) => v.map((x, i) => x * a + h[i] * (1 - a)); + /* DER GRUND WIRD NACH OBEN GESUCHT, bis eine undurchsichtige + Farbe kommt -- halbdurchsichtige Kaesten uebereinander sind + sonst nicht zu rechnen. */ + const grundVon = (e) => { + let n = e; const stapel = []; + while (n && n !== document.documentElement) { + const bg = zahl(getComputedStyle(n).backgroundColor); + const a = bg.length === 4 ? bg[3] : 1; + if (a > 0) stapel.push([bg.slice(0, 3), a]); + if (a === 1) break; + n = n.parentElement; + } + let farbe = [11, 15, 22]; + for (let i = stapel.length - 1; i >= 0; i--) { + farbe = mischen(stapel[i][0], farbe, stapel[i][1]); + } + return farbe; + }; + const kontrast = (e) => { + const vg = zahl(getComputedStyle(e).color); + const a = vg.length === 4 ? vg[3] : 1; + const grund = grundVon(e); + const vorne = mischen(vg.slice(0, 3), grund, a); + const l1 = hell(vorne), l2 = hell(grund); + const [h, d] = l1 > l2 ? [l1, l2] : [l2, l1]; + return (h + 0.05) / (d + 0.05); + }; + + const arten = [".s-karte__text", ".s-marke", ".s-karte__zeit", ".s-runde__nr", + ".s-runde__von", ".s-runde__zeit", ".s-schritt__schild", ".s-schritt__text", + ".s-rundenleiste__punkt"]; + const werte = []; + for (const w of arten) { + const e = document.querySelector(w); + if (!e) continue; + const st = getComputedStyle(e); + const px = parseFloat(st.fontSize); + werte.push({ + w, px: Math.round(px * 100) / 100, + k: Math.round(kontrast(e) * 100) / 100, + zeichen: Math.round(e.getBoundingClientRect().width / (px * 0.5)), + gross: px >= 24 || (px >= 18.66 && Number(st.fontWeight) >= 700), + }); + } + /* GEGENPROBE IM BROWSER: Ein absichtlich zu blasser Text MUSS + auffallen. Ohne sie waere „alle ueber 4,5" auch dann gruen, + wenn die Rechnung kaputt ist -- und genau das war sie. */ + const probe = document.createElement("p"); + probe.textContent = "Probe"; + probe.style.color = "#17202c"; + document.querySelector(".s-karte").append(probe); + const blass = Math.round(kontrast(probe) * 100) / 100; + probe.remove(); + + return { werte, blass }; + }); + + ok(lesbar.werte.length >= 8, + `${lesbar.werte.length} Textarten in der Karte gemessen`); + + const text = lesbar.werte.find((x) => x.w === ".s-karte__text"); + /* DER MELDUNGSTEXT IST DIE HAUPTSACHE DER SEITE. */ + ok(text && text.px >= 16, + `der Meldungstext ist ${text?.px} px gross (mindestens 16)`); + ok(text && text.zeichen <= 85, + `und bricht nach etwa ${text?.zeichen} Zeichen um (hoechstens 85, ` + + "vorher waren es 147)"); + + const verlauf = lesbar.werte.find((x) => x.w === ".s-schritt__text"); + ok(verlauf && verlauf.px >= 15 && verlauf.zeichen <= 85, + `der Verlaufstext: ${verlauf?.px} px, etwa ${verlauf?.zeichen} Zeichen`); + + /* UND KEIN TEXT UNTER DER KONTRASTSCHWELLE. */ + const schwach = lesbar.werte.filter((x) => x.k < (x.gross ? 3 : 4.5)); + ok(schwach.length === 0, + `jeder Text haelt die Kontrastschwelle (${schwach.length} darunter` + + (schwach.length ? `: ${schwach.map((x) => `${x.w} ${x.k}`).join(", ")}` : "") + + `) — schwaechster ${Math.min(...lesbar.werte.map((x) => x.k))} : 1`); + ok(lesbar.blass < 4.5, + `Gegenprobe: ein absichtlich blasser Text faellt auf (${lesbar.blass} : 1)`); + + /* UND AUF DEM HANDY: kurze Zeilen sind dort von selbst kurz -- die + Frage ist, ob die groessere Schrift die Seite sprengt. */ + await kontext.close(); + const h = await neueSeite(390, keksModi); + await h.seite.locator(".s-karte__text").first().waitFor({ timeout: 8000 }); + const handy = await h.seite.evaluate(() => { + const e = document.querySelector(".s-karte__text"); + const px = parseFloat(getComputedStyle(e).fontSize); + return { + px: Math.round(px * 100) / 100, + zeichen: Math.round(e.getBoundingClientRect().width / (px * 0.5)), + ueber: document.documentElement.scrollWidth - document.documentElement.clientWidth, + }; + }); + ok(handy.ueber <= 0, + `auf 390 px ragt mit der groesseren Schrift nichts heraus (${handy.ueber} px)`); + ok(handy.zeichen >= 25 && handy.zeichen <= 60, + `und die Zeile bleibt lesbar lang (etwa ${handy.zeichen} Zeichen)`); + await h.kontext.close(); +} + await browser.close(); try { rmSync(ordner, { recursive: true, force: true }); } catch { /* egal */ } diff --git a/workspace/anruf-probe.html b/workspace/anruf-probe.html index 40f89b83..0d0d8e79 100644 --- a/workspace/anruf-probe.html +++ b/workspace/anruf-probe.html @@ -16,8 +16,8 @@ verdeckt. Gefunden hat es pruef-struktur. Richtig sind `gate.css` (die Farbwerte des Hauses) und `haus.css`. --> - - + + - +