PHP Classes

How to Use a PHP Browser Detection to Determine User Presentation Preferences Using the Package Theme Sync - Server-Side UI Preference Detector: Detect dark mode, contrast and motion preferences

Recommend this page to a friend!
  Info   Example   Screenshots   View files Files   Install with Composer Install with Composer   Download Download   Reputation   Support forum   Blog    
Last Updated Ratings Unique User Downloads Download Rankings
2026-07-20 (14 days ago) RSS 2.0 feedNot yet rated by the usersTotal: Not yet counted Not yet ranked
Version License PHP version Categories
theme-sync 1.0MIT/X Consortium ...7.4HTTP, User Management, PHP 7
Description 

Author

This package detects a visitor's web browser user interface preferences, like the use of dark mode, contrast, reduced motion, and reduced transparency, on the server side before any HTML is sent.

It provides a class that can get HTTP headers from the user's browser to detect preferences like the use of the dark mode, page contrast level, minimization of animations on the page, and reduction of transparent elements on the pages.

The class also supports using a cookie with information stored using the JSON format for browsers that do not yet support browser hints about the users' preferences on the use of the page's dark mode, contrast, animation, and transparency usage.

It also provides functions to let applications know what the current user preferences are on the server side.

Innovation Award
PHP Programming Innovation award nominee
July 2026
Nominee
Vote
Adapting Web site's pages to the user preferences is an important action that developers should be concerned to make their Web sites and applications user-friendly.

The modern web browsers let users control preference values like the use of the dark mode, high contrast, reduced motion, and reduced transparency.

This class can detect if the users have set those preferences using only HTTP headers and cookies to reduce the dependency on the use of JavaScript on the Web pages to detect these user preferences.

Manuel Lemos
Picture of AKONO Metsam Nathan
Name: AKONO Metsam Nathan <contact>
Classes: 1 package by
Country: Cameroon Cameroon
Innovation award
Innovation award
Nominee: 1x

Instructions

Example

<?php

declare(strict_types=1);

require
__DIR__ . '/../src/ThemePreferenceDetector.php';

use
ThemeSync\ThemePreferenceDetector;

// 1) Instantiate as early as possible in your request lifecycle.
$theme = new ThemePreferenceDetector([
   
// Optional: override the fallback values used before any
    // Client Hint or cookie is available (e.g. very first visit).
   
'color-scheme' => ThemePreferenceDetector::SCHEME_LIGHT,
]);

// 2) Opt in to Client Hints for future requests (Chromium browsers).
// Safe to call even if headers can't be sent in this context.
$theme->sendAcceptCHHeader();

// 3) Use the detected preferences however you like.
$htmlClass = $theme->isDarkMode() ? ' class="dark"' : '';
$motionClass = $theme->prefersReducedMotion() ? ' reduced-motion' : '';

?>
<!doctype html>
<html<?= $htmlClass ?>>
<head>
  <meta charset="utf-8">
  <?= $theme->getAcceptCHMetaTag() ?>

  <style>
    <?= $theme->toCssVariables() ?>

    body {
      background: light-dark(#ffffff, #111318);
      color: light-dark(#111318, #f2f2f2);
      font-family: system-ui, sans-serif;
    }
  </style>

  <?php // Only needed for browsers without Client Hints support. ?>
<?= $theme->getBootstrapScript() ?>
</head>
<body class="<?= trim($motionClass) ?>">

  <h1>Theme Sync demo</h1>

  <p>Detected preferences:</p>
  <pre><?= htmlspecialchars(print_r($theme->all(), true)) ?></pre>

  <p>
    Source:
    <?php if ($theme->wasDetectedFromClientHints()): ?>
HTTP Client Hints (no JS involved)
    <?php elseif ($theme->wasDetectedFromCookie()): ?>
fallback cookie (set by a previous visit)
    <?php else: ?>
defaults (first visit, JS about to run to set the cookie for next time)
    <?php endif; ?>
</p>

</body>
</html>


Details

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.


Screenshots (2)  
  • theme-sync-dark.png
  • theme-sync-light.png
  Files folder image Files (7)  
File Role Description
Files folder imagesrc (1 file)
Files folder imageexamples (1 file)
Files folder imagetests (1 file)
Accessible without login Plain text file README.md Doc. Package documentation: problem statement, usage, full API reference.
Accessible without login Plain text file LICENSE Lic. MIT License text.

  Files folder image Files (7)  /  src  
File Role Description
  Plain text file ThemePreferenceDetector.php Class Main class: detects color-scheme, contrast, reduced-motion and reduced-transparency preferences via Client Hints and cookie fallback, and outputs them as CSS variables.

  Files folder image Files (7)  /  examples  
File Role Description
  Accessible without login Plain text file example.php Example Full working example demonstrating theme detection and FOUC-free rendering. Run with: php -S localhost:8000 -t examples

  Files folder image Files (7)  /  tests  
File Role Description
  Accessible without login Plain text file run-tests.php Example Dependency-free automated test suite covering Client Hints detection, cookie fallback, and CSS output sanitization.

The PHP Classes site has supported package installation using the Composer tool since 2013, as you may verify by reading this instructions page.
Install with Composer Install with Composer
 Version Control Unique User Downloads  
 0%
Total:0
This week:0