PHP Classes

File: README.md

Recommend this page to a friend!
  Packages of AKONO Metsam Nathan   Theme Sync - Server-Side UI Preference Detector   README.md   Download  
File: README.md
Role: Documentation
Content type: text/markdown
Description: Package documentation: problem statement, usage, full API reference.
Class: Theme Sync - Server-Side UI Preference Detector
Detect dark mode, contrast and motion preferences
Author: By
Last change:
Date: 15 days ago
Size: 3,433 bytes
 

Contents

Class file image Download

Theme Sync ? Server-Side UI Preference Detector

Detect a visitor's system UI preferences ? dark mode, contrast, reduced motion, reduced transparency? on theserver, before the first byte of HTML is sent, and render the correct theme with zero flash of the wrong theme (FOUC/FOIT), even on the very first page load.

The problem

The usual way to support prefers-color-scheme in a PHP app is: render a default (usually light) theme, then run client-side JS that reads matchMedia() and swaps a class or re-fetches CSS. Every single page load flashes the wrong theme for a fraction of a second, because the server has no idea what the browser prefers until JS runs.

The approach

This package combines two detection strategies so PHP can know the answer before rendering anything:

  1. HTTP Client Hints (`Sec-CH-Prefers-Color-Scheme`, `-Contrast`, `-Reduced-Motion`, `-Reduced-Transparency`). Once the site opts in, supporting browsers attach these headers to every request automatically ? no JS, no cookie, no flash, ever.
  2. A first-party JSON cookie, written by a tiny synchronous inline script on browsers that don't support Client Hints yet. On the very first visit there's nothing to read yet, so the same script also applies the theme immediately client-side (before paint), while storing the cookie so every request from then on is rendered correctly by PHP alone ? no JS required afterward, works even with JS later disabled.

Client Hints, when present, always take priority since they cost zero round-trips and zero JavaScript.

Installation

Copy src/ThemePreferenceDetector.php into your project, or require it directly. No dependencies.

Usage

require 'src/ThemePreferenceDetector.php';

use ThemeSync\ThemePreferenceDetector;

$theme = new ThemePreferenceDetector();
$theme->sendAcceptCHHeader(); // opt in to Client Hints for next visit

echo '<html' . ($theme->isDarkMode() ? ' class="dark"' : '') . '>';
echo '<style>' . $theme->toCssVariables() . '</style>';
echo $theme->getBootstrapScript(); // put in <head>, only needed once

See examples/example.php for a full working page, runnable with:

php -S localhost:8000 -t examples
curl -H "Sec-CH-Prefers-Color-Scheme: dark" http://localhost:8000/example.php

API

| Method | Description | |---|---| | getPreference(string $key) | Raw value for color-scheme, contrast, reduced-motion, reduced-transparency | | isDarkMode() | bool | | prefersReducedMotion() | bool | | prefersMoreContrast() | bool | | prefersReducedTransparency() | bool | | all() | array of all resolved preferences | | toCssVariables(?array $map) | renders a :root { --var: value; } block | | getBootstrapScript() | inline <script> for the cookie fallback | | sendAcceptCHHeader() | opts in to Client Hints via response header | | getAcceptCHMetaTag() | opts in via <meta> tag instead | | wasDetectedFromClientHints() / wasDetectedFromCookie() / isUsingDefaults() | introspection on how the result was obtained |

Browser support

Client Hints are currently Chromium-only (Chrome, Edge, Opera, etc.). Firefox and Safari always fall through to the cookie strategy, which works everywhere matchMedia() is supported ? i.e. virtually every browser since 2015.

Tests

php tests/run-tests.php

License

MIT ? see LICENSE.