A free, open-source Safari Web Extension that adds dark mode to every website. Built with modern Safari Web Extension APIs (Manifest v3).
- Two dark modes:
- Filter — GPU-accelerated CSS filter inversion with smart media re-inversion (images, video, canvas, SVG stay normal)
- Static CSS — Comprehensive dark stylesheet with no inversion artifacts
- Per-site settings — Toggle dark mode on/off for individual websites
- Adjustable brightness & contrast sliders (Filter mode)
- Instant activation — Content script runs at
document_start, no flash of white - MutationObserver — Handles SPAs and lazy-loaded content
- Settings sync via
browser.storage.sync(syncs across devices via iCloud) - Minimal container app — Shows extension status and setup instructions
- Clone this repo
- Open
Nightowl.xcodeprojin Xcode (or runxcodegen generatefirst if regenerating) - Build and Run (Cmd+R)
- Open Safari → Settings → Extensions → Enable Nightowl
- Click the owl icon in the toolbar to configure
- macOS 13.0+
- Xcode 15+
- Safari 16+
Click the Nightowl icon in Safari's toolbar to open the popup:
- Global toggle — Enable/disable dark mode everywhere
- Site toggle — Override for the current website
- Mode — Switch between Filter and Static CSS
- Brightness — Adjust filter intensity (0.5–1.0)
- Contrast — Fine-tune contrast (0.8–1.2)
Nightowl/
├── Nightowl/ # macOS container app (SwiftUI)
│ ├── NightowlApp.swift
│ ├── ContentView.swift
│ └── Assets.xcassets/
├── Nightowl Extension/ # Safari Web Extension
│ ├── SafariWebExtensionHandler.swift
│ └── Resources/
│ ├── manifest.json # Manifest v3
│ ├── background.js # Service worker
│ ├── content.js # Dark mode engine
│ ├── popup.html/css/js # Popup UI
│ └── icon-*.png # Extension icons
└── project.yml # XcodeGen spec
Filter mode applies filter: invert(0.9) hue-rotate(180deg) to the entire page, then re-inverts media elements (img, video, canvas, svg, iframe) so they appear normal. This is GPU-accelerated and works on ~90% of websites.
Static CSS mode injects a comprehensive dark stylesheet targeting all common HTML elements with dark backgrounds and light text. No color inversion means no artifacts, but may not cover every custom-styled element.
Existing open-source Safari dark mode extensions are all abandoned (last commits 2020–2024), use legacy Safari App Extension APIs, and rely on naive CSS inversion that breaks images. Nightowl uses modern Manifest v3 Safari Web Extensions with smart media handling.
MIT