Mastering Dark Mode for WeChat Articles: Techniques, Algorithms & Performance
This article explores how to implement Dark Mode in WeChat public platform articles, covering detection methods, challenges of custom inline styles, comparative algorithms from Chrome and Outlook, a custom color‑processing solution, and performance optimizations for first‑screen rendering.
Introduction
The WeChat public platform article editor is highly extensible and hosts a large plugin ecosystem, allowing users to create rich styles. This openness results in many custom DOM nodes and styles, making Dark Mode support difficult. The article documents the exploration of Dark Mode for WeChat articles.
1. What is Dark Mode
Dark Mode (deep‑color mode) was introduced by Apple in macOS 10.14 (2018) and later adopted by Android, iOS 13, etc. It reduces overall screen brightness, eases eye strain, and on OLED screens saves power because dark pixels consume less current.
2. Detecting Dark Mode
If the browser supports Dark Mode, CSS media query @media (prefers-color-scheme: dark) { … } can be used. In JavaScript, window.matchMedia('(prefers-color-scheme: dark)') returns a MediaQueryList that can be listened to with addListener or addEventListener.
@media (prefers-color-scheme: dark) {</code><code> /* Dark Mode Styles */</code><code>} const mql = window.matchMedia('(prefers-color-scheme: dark)');</code><code>const switchToDarkmode = ({ matches }) => {</code><code> if (matches) {</code><code> // … apply Dark Mode styles</code><code> }</code><code>};</code><code>mql.addListener(switchToDarkmode);</code><code>switchToDarkmode(mql);3. Challenges in the Article Scenario
The editor allows rich‑text editing with inline styles, producing many unpredictable elements and styles that cannot be covered by a single Dark Mode stylesheet. Research on similar products revealed two typical approaches:
3.1 Similar Products
Force color and background-color to specific values.
Overlay a gray mask on images to lower brightness.
Problems observed include loss of user‑defined colors, unmet expectations (e.g., keeping brand colors in Dark Mode), and potential political issues when important colors disappear.
3.2 Google Chrome Inversion Algorithm
Chrome’s source implements a full‑inversion algorithm (C++ and JavaScript). The flowchart is shown below.
The algorithm was adapted to process inline styles instead of stylesheets.
3.3 Dark Mode for Email (Outlook)
Outlook’s approach, described in “Dark Mode for Email: What it is and How to Cope”, uses color‑difference checks and selective inversion, supporting opacity. The original TypeScript gist was forked to add opacity handling.
4. Custom Solution (Open‑Source)
The custom solution aims to avoid DOM manipulation during mode switching and preserve original colors. Two main problems are addressed:
Avoid DOM operations when toggling Dark Mode.
Retain as many original colors as possible.
4.1 Writing Dark Mode Styles
Instead of traversing nodes on each toggle, the script traverses the DOM once, generates CSS for each node, assigns a unique class, and inserts a stylesheet like:
@media (prefers-color-scheme: dark) { .${class} { ${css} } }The stylesheet is injected after traversal, so only the initial load performs DOM work.
4.2 Color‑Processing Algorithm
All colors are converted to HSL. Based on perceived brightness, rules adjust lightness:
Background colors: high‑brightness (>40) are dimmed; very bright (>250) become white; very dark (<22) are lifted.
Font and border colors: high‑brightness fonts stay unchanged; otherwise, contrast with background is measured and adjusted to a threshold (65).
Font shadows follow the same rules as backgrounds.
Additional handling:
Gradients are mixed into a single color before processing.
SVG nodes are currently skipped.
Background‑image nodes receive a light‑mode overlay and a gray mask; border-image cannot receive a mask.
IMG nodes get a CSS filter to lower brightness, noting that filters create new stacking contexts.
5. Performance Optimizations
Even with CSS media queries, the initial DOM traversal adds latency. Measured processing times (approximate): Chrome algorithm ~20 ms, Outlook ~50 ms, custom algorithm ~30 ms.
5.1 First‑Screen Load Optimization
Using visibility: hidden on the content container allows the first‑screen nodes to become visible earlier. Example:
<div style="border: 1px solid black; padding: 0 16px;"></code><code> <!-- visibility --></code><code> <div style="visibility: hidden;"></code><code> <p style="visibility: visible;">Para 1</p></code><code> <p>Para 2</p></code><code> </div></code><code> <!-- display --></code><code> <div style="display: none;"></code><code> <p style="display: block;">Para 3</p></code><code> <p>Para 4</p></code><code> </div></code><code></div>By recording first‑screen nodes during traversal and inserting their Dark Mode styles early, the first view appears faster.
5.2 Optimizing Non‑Dark Mode Paths
If the page is not in Dark Mode, the heavy processing is delayed until the user switches, avoiding unnecessary work.
5.3 Optimizing for Weak Networks
Because the Dark Mode logic resides in JavaScript, a slow network can keep the article hidden for seconds. The solution moves the logic into the HTML (inline) so the page can render immediately, with a small increase in bundle size.
6. Conclusion
Each algorithm has trade‑offs; the custom solution still has edge cases, and ongoing improvements are welcome via issue submissions.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
