Context. In a Capacitor 8 iOS app (WKWebView shell), the web layer handles prefers-color-scheme: dark. Two native surfaces don't, and dark-mode users see a bright flash on launch:
Launch screen. The
Splash.imagesetgenerated by Capacitor's iOS template already declaresappearances: [{appearance: luminosity, value: dark}]entries (Default@{1,2,3}x~universal~anyany-dark.png). The plumbing is there, but asset generators and hand-made splashes usually write the same picture into both slots. iOS picks the dark slot at launch on its own, so the fix is only to supply real dark images. Note that iOS caches launch-screen snapshots; to see a change on a device you may need to delete and reinstall the app.Web view background before first paint (and the overscroll area).
ios.backgroundColorincapacitor.config.tsis one hex string. In@capacitor/iosCAPBridgeViewController.swift,loadView()callsprepareWebView(...), which does:
if let backgroundColor = configuration.backgroundColor {
aWebView.backgroundColor = backgroundColor
aWebView.scrollView.backgroundColor = backgroundColor
} else {
aWebView.backgroundColor = UIColor.systemBackground // dynamic, but white/black
aWebView.scrollView.backgroundColor = UIColor.systemBackground
}Then capacitorDidLoad() runs, still inside loadView(). loadWebView() only runs later, in viewDidLoad(). So a subclass can install a trait-dynamic colour that wins:
class AppBridgeViewController: CAPBridgeViewController {
override open func capacitorDidLoad() {
let bg = UIColor { $0.userInterfaceStyle == .dark
? UIColor(red: 0x12/255, green: 0x10/255, blue: 0x14/255, alpha: 1)
: UIColor(red: 0xff/255, green: 0xdf/255, blue: 0xc2/255, alpha: 1) }
webView?.backgroundColor = bg
webView?.scrollView.backgroundColor = bg
}
}Dropping ios.backgroundColor instead gives you systemBackground. That does follow dark mode, but it's plain white in light mode, which flashes against a branded web background.
Verified by reading the @capacitor/ios 8 source for the call order; not yet run on a device.