experiments in a post-browser web
10
fork

Configure Feed

Select the types of activity you want to include in your feed.

docs: research notes on webview background flash fix

Transparent WKWebView works (eliminates white flash), but CSS
background-color transitions don't animate in WKWebView — they snap
instantly. Tried offsetHeight reflow, double requestAnimationFrame,
and slow timings. Recommends trying native UIView overlay fade next.

+136 -28
+1 -1
backend/tauri-mobile/BUILD_NUMBER
··· 1 - 1062 1 + 1066
+15 -11
backend/tauri-mobile/src-tauri/gen/apple/Sources/peek-save/WebviewPlugin.swift
··· 231 231 } 232 232 var r = m[0], g = m[1], b = m[2]; 233 233 document.documentElement.style.backgroundColor = 'rgba('+r+','+g+','+b+',0)'; 234 - document.documentElement.style.transition = 'background-color 0.25s ease'; 235 - document.documentElement.offsetHeight; 236 - document.documentElement.style.backgroundColor = 'rgba('+r+','+g+','+b+',1)'; 237 - hackStyle.textContent = 'body{transition:background-color 0.25s ease}'; 238 - setTimeout(function() { 239 - document.documentElement.style.cssText = ''; 240 - var h = document.getElementById('__peek_bg'); 241 - if (h) h.remove(); 242 - }, 350); 234 + document.documentElement.style.transition = 'background-color 3s ease'; 235 + requestAnimationFrame(function() { 236 + requestAnimationFrame(function() { 237 + document.documentElement.style.backgroundColor = 'rgba('+r+','+g+','+b+',1)'; 238 + hackStyle.textContent = 'body{transition:background-color 3s ease}'; 239 + setTimeout(function() { 240 + document.documentElement.style.cssText = ''; 241 + var h = document.getElementById('__peek_bg'); 242 + if (h) h.remove(); 243 + }, 3500); 244 + }); 245 + }); 243 246 } 247 + function delayedReveal() { setTimeout(reveal, 2000); } 244 248 if (document.readyState === 'loading') { 245 - document.addEventListener('DOMContentLoaded', reveal); 249 + document.addEventListener('DOMContentLoaded', delayedReveal); 246 250 } else { 247 - reveal(); 251 + delayedReveal(); 248 252 } 249 253 })(); 250 254 """
+18 -15
backend/tauri-mobile/src-tauri/gen/apple/assets/index.html
··· 1 - <!doctype html> 2 - <html lang="en"> 3 - <head> 4 - <meta charset="UTF-8" /> 5 - <link rel="icon" type="image/svg+xml" href="/vite.svg" /> 6 - <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover" /> 7 - <meta name="color-scheme" content="light dark" /> 8 - <title>Tauri + React + Typescript</title> 9 - <script type="module" crossorigin src="/assets/index-CnILxkhd.js"></script> 10 - <link rel="stylesheet" crossorigin href="/assets/index-akJGesdg.css"> 11 - </head> 12 - 13 - <body> 14 - <div id="root"></div> 15 - </body> 1 + <!DOCTYPE html> 2 + <html> 3 + <head> 4 + <meta charset="UTF-8"> 5 + <meta name="viewport" content="width=device-width, initial-scale=1.0"> 6 + <title>Loading...</title> 7 + <script> 8 + // Redirect to dev server on localhost 9 + // iOS simulator can access Mac's localhost 10 + // Vite is guaranteed running before app launch (dev-ios-sim.sh waits for it) 11 + window.location.href = 'http://localhost:58813/'; 12 + </script> 13 + </head> 14 + <body> 15 + <div style="display: flex; align-items: center; justify-content: center; height: 100vh; font-family: system-ui;"> 16 + Loading dev server... 17 + </div> 18 + </body> 16 19 </html>
+1 -1
backend/tauri-mobile/src-tauri/tauri.conf.json
··· 6 6 "build": { 7 7 "beforeBuildCommand": "npm run build", 8 8 "frontendDist": "../dist", 9 - "devUrl": "http://192.168.50.143:57521" 9 + "devUrl": "http://192.168.50.143:58813" 10 10 }, 11 11 "app": { 12 12 "windows": [
+101
notes/research-webview-background-flash.md
··· 1 + # Research: Webview Background Flash Fix 2 + 3 + ## Problem 4 + 5 + When opening a web page in the inline WKWebView on mobile, there's a white flash before the page renders. The WKWebView defaults to white background regardless of the app's color scheme, which is jarring in dark mode. 6 + 7 + ## Goal 8 + 9 + Start with the app's background visible behind the page as it loads. Detect the page's actual background as early as possible (DOMContentLoaded at latest). If different, smoothly animate to it. 10 + 11 + ## Approach Tried: Transparent Webview + CSS Transition Fade-In 12 + 13 + ### What We Did 14 + 15 + **Step 1: Make WKWebView transparent** (works) 16 + 17 + ```swift 18 + webView.isOpaque = false 19 + webView.backgroundColor = .clear 20 + webView.scrollView.backgroundColor = .clear 21 + ``` 22 + 23 + This successfully makes the WKWebView transparent so the app's Tauri webview background shows through. The white flash is eliminated — the app's dark/light background is visible during load. 24 + 25 + **Step 2: Inject document-start script** to manage the transition 26 + 27 + Injected via `WKUserScript` at `.atDocumentStart`, `.forMainFrameOnly`: 28 + 29 + 1. Set `document.documentElement.style.backgroundColor = 'transparent'` immediately 30 + 2. Inject `<style id="__peek_bg">body{background-color:transparent!important}</style>` to force body transparent 31 + 3. At DOMContentLoaded, read the page's intended body bg (temporarily disable override, read `getComputedStyle`), parse RGB values 32 + 4. Set html bg to `rgba(r,g,b,0)`, add `transition: background-color Xs ease`, then set `rgba(r,g,b,1)` to animate the fade-in 33 + 5. Clean up injected styles after transition completes 34 + 35 + ### What Works 36 + 37 + - **Transparent WKWebView**: The app background shows through correctly during load. No white flash. 38 + - **Document-start injection**: The script runs and the transparent override is applied. 39 + - **Background color detection**: The `getComputedStyle` read works — we can detect the page's intended background. 40 + 41 + ### What Doesn't Work 42 + 43 + - **CSS transition is ignored**: The background-color transition from `rgba(r,g,b,0)` to `rgba(r,g,b,1)` does not animate. The change appears instant — the page's background just snaps in. 44 + 45 + ### Variations Tried 46 + 47 + 1. **`offsetHeight` forced reflow** between setting start/end states — no effect 48 + 2. **Double `requestAnimationFrame`** to guarantee paint before setting end state — no effect 49 + 3. **3-second transition duration + 2-second delay** before reveal — the delay works (app bg visible longer), but when the transition fires it's still instant, not animated 50 + 4. **`transition` on both html element (inline) and body (via stylesheet)** — neither animates 51 + 52 + ### Theories on Why Transitions Fail 53 + 54 + 1. **WKWebView compositing**: When `isOpaque = false`, WKWebView may use a different compositing path that doesn't support CSS transitions on the root element's background, or the transparency is handled at a layer level that bypasses CSS animation. 55 + 56 + 2. **Page stylesheet race**: The page's own stylesheets may be applying background-color to `html` or `body` in a way that overrides our inline transition mid-flight. Many sites set `html { background: #fff }` which would conflict. 57 + 58 + 3. **Background-color on `<html>` may not be transitionable in WebKit** in the same way as on regular elements — the root element's background has special rendering behavior (it paints the canvas). 59 + 60 + 4. **`transparent` → `rgba(r,g,b,1)` may not interpolate** in all WebKit versions. Some engines don't interpolate from `transparent` (which is `rgba(0,0,0,0)`) to a colored value smoothly. 61 + 62 + ## Alternative Approaches to Explore 63 + 64 + ### A. Native UIView overlay fade 65 + 66 + Instead of CSS transitions, use a native UIView with the app's background color overlaid on top of the WKWebView. Fade the overlay out using `UIView.animate()` after `didFinish` navigation delegate fires. This avoids CSS transition issues entirely. 67 + 68 + ```swift 69 + let overlay = UIView(frame: webView.bounds) 70 + overlay.backgroundColor = .systemBackground 71 + overlay.autoresizingMask = [.flexibleWidth, .flexibleHeight] 72 + webView.addSubview(overlay) 73 + 74 + // In didFinish delegate: 75 + UIView.animate(withDuration: 0.3) { 76 + overlay.alpha = 0 77 + } completion: { _ in 78 + overlay.removeFromSuperview() 79 + } 80 + ``` 81 + 82 + **Pros**: Fully native, guaranteed to animate, no CSS hacks. 83 + **Cons**: Overlay hides page content during load (but that's arguably fine — content isn't ready yet anyway). Need to use `didFinish` which fires late (after all resources load), or use `didCommit` for earlier reveal. 84 + 85 + ### B. WKWebView `underPageBackgroundColor` 86 + 87 + iOS 15+ has `webView.underPageBackgroundColor` which sets the color shown behind the page content (for overscroll, etc). Setting this to match the app's background might reduce the flash without needing transparency tricks. However, this requires knowing dark/light mode and doesn't solve the transition. 88 + 89 + ### C. Opacity animation on the WKWebView itself 90 + 91 + Start the WKWebView at `alpha = 0`, then animate to `alpha = 1` after content loads. Simple, but fades in ALL content (not just background), which may look different than desired. 92 + 93 + ### D. JavaScript `opacity` transition instead of `background-color` 94 + 95 + Instead of transitioning background-color, wrap all body content in a div, set the real background immediately, but transition the wrapper's opacity from 0 to 1. This avoids the root-element background transition issue. 96 + 97 + ## Current State 98 + 99 + The code in `WebviewPlugin.swift` has the transparent WKWebView + CSS injection approach implemented with debug timing (2s delay, 3s transition, 3.5s cleanup). The transparent WKWebView part works well. The CSS transition part does not animate — it snaps instantly. 100 + 101 + **Recommendation**: Try approach **A (native UIView overlay fade)** next. It sidesteps all CSS/WebKit quirks by using UIKit animation which is reliable and well-understood.