Skip to content

[accessibility] CSS forced colors mode (e.g., Windows high contrast) requires updated handling #4049

Description

@GeeLaw

Previous issue is #716. Related #3974.

Steps to reproduce

Use MSEdge 136.0.3240.50 (Official build) (64-bit) Chromium version 136.0.7103.49 on Windows 11 (24H2 if that matters) to visit KaTeX website, and enter

\begin{aligned}
&
\f\relax{x} = \int_{-\infty}^\infty
    \f\hat\xi\,e^{2 \pi i \xi x}
    \,d\xi
\\&
{\color{red}\text{ Hey}}
\\&
\textcolor{blue}{F=ma}
\textcolor{#228B22}{F=ma}
\\&
\colorbox{aqua}{$F=ma$}
\fcolorbox{red}{aqua}{$F=ma$}
\end{aligned}

we see

Image

This is expected. Now switch to a high contrast theme, e.g., "Aquatic", we see

Image

where the issue #716 reappears --- formula components cut into each other. Also, the text/box colors are incorrect (although what color it should be is debatable).

Analysis

For fashion reasons, Microsoft decided to unsupport -ms-high-contrast media query and -ms-high-contrast-adjust property: https://blogs.windows.com/msedgedev/2024/04/29/deprecating-ms-high-contrast/

Mandatory rant: There's almost no cost to continue supporting these rules. It appears fashion is more important than accessibility to Microsoft.

The standard is forced-colors media query and forced-color-adjust property. According to the documentation, there are 3 choices of forced-color-adjust:

  • auto, which yields the screenshot;
  • none, which would create other incorrect results;
  • preserve-parent-color, which behaves crazy and is not what the documentation says.

Why preserve-parent-color is not good for now. If we choose preserve-parent-color:

  • In usual descendants, we get rid of backplates (good) and inherit CanvasText color (good).
  • In \textcolor{...}{...} or {\color{...}...}, we have the custom color over Canvas background. This is bad because we don't know if the colors are in contrast.
  • In \colorbox{...}{...}, we have the custom background under CanvasText text. This is again bad due to unknown contrast.
  • In \fcolorbox{...}{...}{...}, we have the custom background under CanvasText text. This is again bad.
  • In \colorbox{...}{...} or \fcolorbox{...}{...}{...}, where the content is fully colored using \textcolor{...}{...} or {\color{...}...}, then we respect the typesetter's colors. This is good. Hopefully those colors are already contrasty enough.

That's 2 good cases and 3 bad cases.

One possible solution. In forced-color mode:

  1. All usual formulae become CanvasText color on Canvas background.
  2. All custom-color formulae are highlighted using a fixed color (regardless of typesetter's choice), still on Canvas background.
  3. All custom-color boxes are highlighted using a fixed color (regardless of typesetter's choice).

For 2, we can only use LinkText or ActiveText or VisitedText, because they're still on Canvas background and those three colors are the only ones known to contrast it (aside from CanvasText used for usual formulae).

For 3, we can use HighlightText and Highlight, and we must sacrifice any custom colors inside the boxes. (Alternatively, we can use MarkText and Mark, but they're usually used for <mark>.)

For 2, it's the best to use ActiveText:

  1. In the examples, those three colors are the same, so they're tie from this perspective.
  2. If a user sets them different, the only way to differentiate non-link LinkText-/VisitedText-colored text from links, is to hover or try focusing them.
  3. If a user sets them different, by not doing any action on the page, the user knows any text that's ActiveText must represent a highlighted formula --- this is a learnable and no-interaction differentiable option.

One possible implementation:

/* Some !important's are used to override style in HTML attribute. */
@media (forced-colors: active)
{
  .katex
  {
    forced-color-adjust: none;
    color: CanvasText;
    background: Canvas;
  }
  .katex *
  {
    forced-color-adjust: none;
    color: inherit;
    background: transparent !important;
  }
  .katex, .katex *
  {
    border-color: currentcolor !important;
    outline-color: currentcolor !important;
    text-decoration-color: currentcolor !important;
    text-emphasis-color: currentcolor !important;
  }
  .katex [style*="color"]
  {
    color: ActiveText !important;
  }
  .katex .colorbox, .katex .fcolorbox,
  .katex [style*="background-color"],
  .katex *:has(>.colorbox), .katex *:has(>.fcolorbox),
  .katex *:has(>.fcolorbox) + *,
  .katex *:has(>.colorbox) + *
  {
    color: HighlightText !important;
    background: Highlight !important;
  }
}

After applying the aforementioned style to KaTeX website:

Image

Do not remove -ms-high-contrast-adjust: none etc. There's no harm to keep them there and KaTeX readme says it wants to support IE 11.

Caveats

  1. If a user uses both blue and red and refers to the colored terms, they will not be visible in forced-colors mode.
  2. I don't know if forced-colors mode can apply to print media.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions