You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Found while reviewing the comment rewrite in #200, which restates the footer's contrast reasoning.
styles/quantecon.css fades the whole site footer with opacity: 0.7 on .article .qe-site-footer, reproducing the lecture footer's own opacity. The declared colours pass AA, but the composited ones are what the reader sees, and in light mode two of them do not. The footer renders at 0.9rem (14.4px) normal weight, so the 4.5:1 normal-text floor applies — the 3:1 large-text allowance does not.
Element
Declared
Composited on white @ 0.7
Contrast
AA
footer body text
#444444
rgb(124 124 124)
4.17:1
✗
footer links
#0072bc
rgb(77 156 208)
3.01:1
✗
Both come straight from the rules as written — .article .qe-site-footer { color: #444; opacity: 0.7 } at (0,2,0) with no light-mode override, and .article .qe-site-footer a { color: #0072bc } — so nothing else in the cascade changes them.
Dark mode already got this treatment. The comment directly above the dark rule does exactly this arithmetic and acts on it:
#0072bc drawn at the footer's 70% opacity on the #222 content panel is about 2.2:1; blue-300 lands near 5.0:1 at the same opacity.
which is why .dark .article .qe-site-footer a is #93c5fd (5.04:1 composited, confirmed). The same two lines of arithmetic were never run for light mode.
Is this inherited? Partly. The opacity: .7 and the 14.4px size are the lecture footer's, measured off python-programming.quantecon.org, so in the strict sense this is the same two-theme question as #172. But this theme has already diverged from the inherited values in this exact block, for this exact reason, on the dark side — alongside three other deliberate accessibility divergences (the outline's undimmed resting entries at 10.3:1 where the Sphinx panel composites to 4.47:1; the outline's active state carrying weight and a rule so it is not colour-only, per WCAG 1.4.1; the flat 18px content size with a rem root, avoiding the Sphinx px-root's 1.4.4 problem). So the working rule this codebase already follows is match the lecture builds, except where matching them fails WCAG — and the light footer is the one place that rule was written down and then not applied.
Options
Fix light to match the standard dark already meets. Minimum-change candidates that keep the faded look, since the opacity is doing the design work — each is the value whose composited result clears 4.5:1, the blue held to #0072bc's own hue and saturation:
Element
Today
Composited today
Candidate
Composited candidate
body text
#444444
4.17:1
#3b3b3b
4.54:1
links
#0072bc
3.01:1
#00436f
4.55:1
Those are minimum-change values, not a design proposal — #00436f is a much darker blue than the brand #0072bc, and at 70% opacity there is no way around that. If it reads too dark, the alternative is to lift the opacity on the text while keeping it on the badge.
Or drop opacity: 0.7 and declare the faded colours directly — but the badge image is meant to fade with everything else, which is why the opacity is on the element in the first place, so this changes the badge too.
Accept and record. The footer is secondary chrome — licence text and attribution, not reading copy. If that is the call, the comment should say so explicitly rather than leaving the arithmetic done for dark only.
Two things I could not settle without a render, both worth checking before deciding:
Dark footer body text. The element carries dark:text-qetext-dark-muted (#a6a6a6) while .article .qe-site-footer sets color: #444. Both are (0,2,0), so Tailwind's layer order decides, and the comment on the component rule claims it "overrides the element's utilities outright". If #444 really wins in dark mode it composites to 1.4:1, which the screenshots suggest is not what renders — so the utility is presumably winning and the true figure is #a6a6a6 @ 0.7 = 3.92:1, still under AA. Worth confirming either way, since one of those two readings is a bug and the other is a third row for the table above.
Whether real lecture footers carry text links at all, or only the licence badge image. The fixture footer is badge-plus-prose; the a rule exists, so links are expected, but the 3.01:1 figure only bites where there is link text. An image-only badge link is exempt.
Where it fits: not a parity gate — like #172 this is a deliberate-divergence decision, not a mismatch with the current sites. No dependency on #200, which only describes these values; it changes none of them.
Found while reviewing the comment rewrite in #200, which restates the footer's contrast reasoning.
styles/quantecon.cssfades the whole site footer withopacity: 0.7on.article .qe-site-footer, reproducing the lecture footer's own opacity. The declared colours pass AA, but the composited ones are what the reader sees, and in light mode two of them do not. The footer renders at0.9rem(14.4px) normal weight, so the 4.5:1 normal-text floor applies — the 3:1 large-text allowance does not.#444444rgb(124 124 124)#0072bcrgb(77 156 208)Both come straight from the rules as written —
.article .qe-site-footer { color: #444; opacity: 0.7 }at (0,2,0) with no light-mode override, and.article .qe-site-footer a { color: #0072bc }— so nothing else in the cascade changes them.Dark mode already got this treatment. The comment directly above the dark rule does exactly this arithmetic and acts on it:
which is why
.dark .article .qe-site-footer ais#93c5fd(5.04:1 composited, confirmed). The same two lines of arithmetic were never run for light mode.Is this inherited? Partly. The
opacity: .7and the 14.4px size are the lecture footer's, measured off python-programming.quantecon.org, so in the strict sense this is the same two-theme question as #172. But this theme has already diverged from the inherited values in this exact block, for this exact reason, on the dark side — alongside three other deliberate accessibility divergences (the outline's undimmed resting entries at 10.3:1 where the Sphinx panel composites to 4.47:1; the outline's active state carrying weight and a rule so it is not colour-only, per WCAG 1.4.1; the flat 18px content size with a rem root, avoiding the Sphinx px-root's 1.4.4 problem). So the working rule this codebase already follows is match the lecture builds, except where matching them fails WCAG — and the light footer is the one place that rule was written down and then not applied.Options
Fix light to match the standard dark already meets. Minimum-change candidates that keep the faded look, since the opacity is doing the design work — each is the value whose composited result clears 4.5:1, the blue held to
#0072bc's own hue and saturation:#444444#3b3b3b#0072bc#00436fThose are minimum-change values, not a design proposal —
#00436fis a much darker blue than the brand#0072bc, and at 70% opacity there is no way around that. If it reads too dark, the alternative is to lift the opacity on the text while keeping it on the badge.Or drop
opacity: 0.7and declare the faded colours directly — but the badge image is meant to fade with everything else, which is why the opacity is on the element in the first place, so this changes the badge too.Fix in both themes, as option 1 of Five light-mode code token colours fall short of WCAG AA contrast #172 proposes for the code palette. Keeps strict parity, costs a coordinated PR and a baseline refresh in both.
Accept and record. The footer is secondary chrome — licence text and attribution, not reading copy. If that is the call, the comment should say so explicitly rather than leaving the arithmetic done for dark only.
Two things I could not settle without a render, both worth checking before deciding:
dark:text-qetext-dark-muted(#a6a6a6) while.article .qe-site-footersetscolor: #444. Both are (0,2,0), so Tailwind's layer order decides, and the comment on the component rule claims it "overrides the element's utilities outright". If#444really wins in dark mode it composites to 1.4:1, which the screenshots suggest is not what renders — so the utility is presumably winning and the true figure is#a6a6a6@ 0.7 = 3.92:1, still under AA. Worth confirming either way, since one of those two readings is a bug and the other is a third row for the table above.arule exists, so links are expected, but the 3.01:1 figure only bites where there is link text. An image-only badge link is exempt.Where it fits: not a parity gate — like #172 this is a deliberate-divergence decision, not a mismatch with the current sites. No dependency on #200, which only describes these values; it changes none of them.