[Bug] The dark theme fails the contrast bar the app applies to the user own slides #606
Labels
No labels
accepted
bug
declined
docs
duplicate
enhancement
good first issue
in-progress
needs-info
privacy
security
triage
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
LibreKAT/Ocideck#606
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Found in the pre-publication accessibility review.
Evidence:
lib/theme/app_theme.dartmakes colours mode-dependent via_m(light, dark)— but 25 tokens areconstand therefore do not flip. Measured against the dark backgroundpaper = #181B21(line 57), 21 of the 25 fail WCAG AA 4.5:1:severityCritical/danger700/checklistAnomaly/scopeUnreachable#B91C1C→ 2.67:1severityNone#64748B→ 2.28:1success800→ 2.42:1accent#2563EB→ 3.34:1success700/severityLow/checklistTested#15803D→ 3.44:1They are used as text colours, not fills:
lib/widgets/shell/status_bar.dart:196(the seal-intact indicator),lib/widgets/editors/asset_overview_editor.dart:225,lib/l10n/slide_quality_localization.dart:272. In presentation mode there are a further 24 uses ofColors.white24/38/54/70as a text colour inlib/widgets/presentation/;Colors.white24on black is roughly 2.0:1 atfontSize: 11-12(presenter_overlays.dart:383).No test checks the app own UI for contrast —
theme_profile_contrast_warning_test.dartandtitle_contrast_test.dartare about the user deck.Why this matters now: OciDeck checks the contrast of your slides against WCAG AA and reports what fails — a feature most presentation tools lack, and one the README names as a differentiator. That the app itself misses that bar on 21 of 25 colours in dark mode is the easiest "physician, heal thyself" a reviewer can find, and the arithmetic takes them five minutes.
Proposal: first, a test that applies the contrast calculation the app already owns to a list of (colour, background) pairs from
AppThemein both modes, with the current outcome as an explicit ratchet baseline — then the number lives in the repository rather than in a critic notebook. Then give the four worst tokens (#B91C1C,#15803D,#64748B,#2563EB) a_m()counterpart, as the slate palette already has. Put the real number indocs/ACCESSIBILITY.mdafterwards.Opgepakt. Tak:
fix/donker-thema-contrast-606. Reikwijdte: een ratchet-testtest/app_theme_contrast_test.dart, de drie call sites die je noemt, endocs/ACCESSIBILITY.md. De volledige audit van alle ~200 tokengebruiken past hier niet in; ik laat het issue open met wat er dan nog ligt.Gedeeltelijk opgelost in
f336166a(PR #682), op main. Het issue blijft open voor de rest; hieronder staat wat dat is.Wat er is.
test/app_theme_contrast_test.dartmeet elk kleurtoken dat de interface als tékst gebruikt tegen het oppervlak dat de modus werkelijk schildert, in beide modi, met de uitkomst als ratchet — stap 1 uit je voorstel. Hij faalt twee kanten op: een nieuw geval erbij, én een geval dat gerepareerd is maar in de lijst blijft staan. Plus de drie call sites die je bij naam noemt, nu opdangerFg/successFg.De meting corrigeert je issue op twee punten. Donker telt 17 tokens onder 4,5:1, niet 21 — het verschil zit in vul- en randkleuren die de tekstlat niet hoeven te halen. En licht is niet in orde:
severityHigh(#EA580C) haalt 3,6:1 op wit,severityMedium(#D97706) 3,3:1. Je mat alleen tegen de donkere achtergrond en noemde licht impliciet goed.Waarom de rest niet in één keer kan. Je voorstel was de vier ergste tokens een
_m()-tegenhanger geven. Dat kan niet zomaar: die tokens zijn bewust vast. Een bevinding moet in een headless export-isolate identiek renderen aan de preview (PENTEST_MIAUW §11), en een kleur die met de app-modus meebeweegt breekt dat — dan gaat het zegel over twee verschillende PDF's.Wat er dus nog ligt: elk van de ~200 gebruiken van die tokens lezen als óf dia-inhoud (laten staan) óf interface-chrome (mode-afhankelijk maken). Dat is een audit, geen omzetting, en daar blijft dit issue voor open.
docs/ACCESSIBILITY.mddraagt de getallen en die tweedeling nu, zodat de stand in de repo staat.De merkkleuren-audit staat op main:
7e73c9a9(PR #712).accent,navyentealwerden op zeventig plekken als tekst-/icoonkleur gebruikt en haalden in de donkere modus de lat niet. Ze hebben nu mode-afhankelijke tegenhangers (accentFg/brandFg/tealFg); de merkkleuren zélf blijven const. De scheidslijn is chroom-tegen-inhoud: tekst die je ín de app leest volgt de app, inkt die óp een dia landt niet — want een dia moet in de preview identiek zijn aan een headless export. De goldens bevestigen dat de dia's byte-identiek blijven, en de beeldkeuring keurde beide modi met eigen ogen goed.Donker zakt daarmee van 17 naar 14 tokens onder de lat. De ratchet kreeg een tweede toets: de nieuwe tokens moeten de lat wél halen, anders is de verhuizing een stille no-op.
Wat overblijft, en dit is de kern van je oorspronkelijke voorstel dat níét zomaar kan: de ernst-, checklist- en scopepaletten (de 14 resterende donkere tokens). Díé renderen werkelijk in dia's, dus een
_m()-tegenhanger geven zou het zegel over twee verschillende PDF's laten gaan. Ze vragen dezelfde lezing per gebruik als de merkkleuren nu kregen — dia-inhoud laten staan, chroom mode-afhankelijk maken.ACCESSIBILITY.mddraagt die stand en de tweedeling.Ik laat het issue daarvoor open.
Volledig opgelost in PR #715, op main — de audit met beeldcontrole in beide thema's.
De regel die eruit kwam is niet licht-tegen-donker maar chrome tegen inhoud. Tekst die je ín de app leest volgt de app; inkt die óp een dia landt niet, want een dia moet identiek renderen in de preview en in een headless export-isolate.
37 chrome-plekken naar de mode-afhankelijke varianten. 43 plekken in
previews/naar nieuwe vaste dia-inkt — en dát was de grootste vondst, uit de beeldkeuring: de previews schilderden hun grijzen met de mode-afhankelijke slate-schaal op een canvas dat wit blijft. In donkere modus werdslate7001,3:1; de tekst van een checklist, scope-matrix en bevindingenoverzicht verdween zo goed als helemaal. En het week af van de export, die zonder thema draait en altijd de lichte waarden schrijft — terwijl het exportdialoog belooft dat de export exact de weergave uit de editor gebruikt. Alle 33 goldens bleven byte-identiek.En de meting klopte niet, en dat was van mij. De eerste ronde legde elk vast token naast het interface-oppervlak en noteerde zeventien tekortkomingen. Maar een ernstkleur wordt op een witte dia gelezen. Tegen de juiste achtergrond en de juiste lat haalt alles het: veertien tokens zijn diatekst (4,5:1 op wit), twee zijn nooit tekst maar een tint, een randstreep en een badge-vulling met groot vet label (3:1). Er staat geen basislijn meer open — grotendeels een categoriefout, de rest gerepareerd.
Drie kleinere uit de keuring, twee door mij veroorzaakt: het exportdialoog was half omgezet (faaltak op 3,1:1 in donker terwijl de succes-tak schreeuwde), de gebruikersnotities-kop was zwakker geworden dan zijn eigen ondertitel, en
dangerFgwas in licht zo bleek dat hij op de scorecard-chip naar 4,2:1 zakte — onder AA, voor de kleur die alarm betekent.Twee bronwachten zetten dit vast: geen vaste merk-/ernstkleur als tekst buiten de dia-renderende code, en geen mode-afhankelijk grijs binnen
previews/. Beide lezen de bron en zijn eerst rood gemaakt met een geplante overtreding.Los hiervan gemeld: een gebroken PDF-export (#714).