From 69f4f20a04ca796756b9ad3882abc792d2d96e0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niklas=20Lindstr=C3=B6m?= Date: Tue, 1 Apr 2025 09:19:44 +0200 Subject: [PATCH] Support dark mode toggle for SVGs and highlight.js Syntax highlighting already works with automatic preferences, but has not played well with neither default (no dark mode) settings, nor worked with the manual scheme toggle. (See also #4871.) This fixes that using CSS (so that default behavior works without JS). SVG behavior is by default based on user-agent preferences, and has therefore also not played well with the manual toggle. With this change, that is now handled by setting `color-scheme: light` or `dark` on the body element, based on the sidebar-provided manual scheme toggle. If no meta element indicating dark color-scheme support is present, light mode is set on the body. This instructs SVGs to render in light mode when embedded in documents with no dark mode support, even when the user agent indicates dark mode. (The `color-scheme` CSS property can of course still be set to other values for various sections in a document, if so desired.) A darkmode example document is also added, containing syntax-highlighted code and embedding an SVG document supporting light/dark color-scheme preferences. --- examples/darkmode.html | 85 ++++++++++++++++++++++++++++++++++ examples/figure1-lightdark.svg | 37 +++++++++++++++ src/styles/highlight.css.js | 39 ++++++++++------ src/styles/respec.css.js | 13 ++++++ 4 files changed, 160 insertions(+), 14 deletions(-) create mode 100644 examples/darkmode.html create mode 100644 examples/figure1-lightdark.svg diff --git a/examples/darkmode.html b/examples/darkmode.html new file mode 100644 index 0000000000..bcafdf944e --- /dev/null +++ b/examples/darkmode.html @@ -0,0 +1,85 @@ + + + + + + Replace me with a real title + + + + +
+

This is required.

+
+
+

This is required.

+
+
+

Introduction

+

Some informative introductory text.

+ +
+ +
A figure
+
+
+
+

A section

+ +
+

I'm a sub-section

+

+ +

+
+
+
+

Start your spec!

+
+        [Exposed=Window]
+        interface Foo {
+        attribute DOMString bar;
+        undefined doTheFoo();
+        };
+      
+

The Foo interface represents a {{Foo}}.

+

+ The doTheFoo() method does the foo. Call it by running + {{Foo/doTheFoo()}}. +

+
    +
  1. A |variable:DOMString| can be declared like this.
  2. +
+
+
+

+ This is required for specifications that contain normative material. +

+
+
+ + diff --git a/examples/figure1-lightdark.svg b/examples/figure1-lightdark.svg new file mode 100644 index 0000000000..b992b1f928 --- /dev/null +++ b/examples/figure1-lightdark.svg @@ -0,0 +1,37 @@ + + + + + + + + + + + + + Foo + + + bar + + + + + Baz + + + + diff --git a/src/styles/highlight.css.js b/src/styles/highlight.css.js index 3f52eb7e71..3fa7d22676 100644 --- a/src/styles/highlight.css.js +++ b/src/styles/highlight.css.js @@ -6,10 +6,29 @@ Original One Light Syntax theme from https://github.com/atom/one-light-syntax const css = String.raw; +// Repeatably used in media rule and selector-based override. +const hljsDarkVars = ` + --base: #282c34; + --mono-1: #abb2bf; + --mono-2: #818896; + --mono-3: #5c6370; + --hue-1: #56b6c2; + --hue-2: #61aeee; + --hue-3: #c678dd; + --hue-4: #98c379; + --hue-5: #e06c75; + --hue-5-2: #be5046; + --hue-6: #d19a66; + --hue-6-2: #e6c07b; +`; + // Prettier ignore only to keep code indented from level 0. // prettier-ignore export default css` -.hljs { +/* Use light by default, when no dark scheme present, or light scheme is checked. */ +.hljs, +head:not(:has(meta[name='color-scheme'][content~='dark'])) + body .hljs, +body:has(input[name='color-scheme'][value='light']:checked) .hljs { --base: #fafafa; --mono-1: #383a42; --mono-2: #686b77; @@ -24,23 +43,15 @@ export default css` --hue-6-2: #9a6a01; } -/* There's no way to adapt this to "manual" theme toggle yet. */ +/* Use dark by default when preferred, or when dark scheme is checked. */ @media (prefers-color-scheme: dark) { .hljs { - --base: #282c34; - --mono-1: #abb2bf; - --mono-2: #818896; - --mono-3: #5c6370; - --hue-1: #56b6c2; - --hue-2: #61aeee; - --hue-3: #c678dd; - --hue-4: #98c379; - --hue-5: #e06c75; - --hue-5-2: #be5046; - --hue-6: #d19a66; - --hue-6-2: #e6c07b; + ${hljsDarkVars} } } +body:has(input[name='color-scheme'][value='dark']:checked) .hljs { + ${hljsDarkVars} +} .hljs { display: block; diff --git a/src/styles/respec.css.js b/src/styles/respec.css.js index 66763af1c4..56bc4a66b5 100644 --- a/src/styles/respec.css.js +++ b/src/styles/respec.css.js @@ -179,4 +179,17 @@ aside.example .marker > a.self-link { display: none; } } + +/** + * Control prefers-color-scheme behavior in linked SVGs: + * - use light when no dark scheme present, or light scheme is checked. + * - use dark when dark scheme is checked. + */ +head:not(:has(meta[name='color-scheme'][content~='dark'])) + body, +body:has(input[name='color-scheme'][value='light']:checked) { + color-scheme: light; +} +body:has(input[name='color-scheme'][value='dark']:checked) { + color-scheme: dark; +} `;