Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow changing the webview background color #1564

Open
mallendeo opened this issue Apr 21, 2021 · 18 comments
Open

Allow changing the webview background color #1564

mallendeo opened this issue Apr 21, 2021 · 18 comments
Labels
status: backlog Issue is ready and we can work on it type: feature request

Comments

@mallendeo
Copy link

mallendeo commented Apr 21, 2021

Describe the bug
Window flashes a white background before rendering app content on macOS Big Sur.

The css for the index.html is:

html, body {
  width: 100%; height: 100%;
  background: rgb(231, 232, 232);
}

@media (prefers-color-scheme: dark) {
  html, body {
    background: rgb(37, 38, 40);
  }
}

To Reproduce
Steps to reproduce the behavior:

  1. Create an index.html with <style>html, body { background: black; }</style>
  2. Run the app (dev, or dist bundle)
  3. Screen will flash a white background before rendering the content.

Expected behavior
The main window should wait for the content to load, or it should apply the page's background color on open.

Screenshots

default.mp4

Platform and Versions (please complete the following information):

OS: Mac OS, version 11.2.3 X64
Node: 15.13.0
NPM: 7.7.6
Yarn: 1.22.10
Rustc: 1.51.0

Additional context
This is running the app with the default values (no transparent window mode). When using transparent window mode, it doesn't flash, but the window loses all shadows and borders until it is resized.

transparent.mp4
@mallendeo mallendeo changed the title Screen flashes a white background before rendering app App window flashes a white background before rendering content Apr 21, 2021
@kinghat
Copy link

kinghat commented Apr 23, 2021

also experiencing this on linux:

Peek.2021-04-23.12-23.mp4

@chippers
Copy link
Member

I suspected this is the browser's default background color, so I made a small edit to wry to set the background manually to red (linux only) to see this a bit easier. The initial color (dark/light) is the OS window's default color, then the webview is loaded with whatever background color is set (red here), and then the application loads.

2021-04-23.11-55-56.mp4

This is a change needed in wry to support setting the webview background color. I've opened up a ticket at tauri-apps/wry#197.

If/when that is implemented, then we can look at expanding the tauri::Attributes trait to include setting the background color, and maybe add a hex string backgroundColor field to the window config inside tauri.config.json.

@happyshovels
Copy link

Since I also ran into this issue today, I am sharing my hacky workaround in case someone is also bothered by the white flashing. The idea is to start the window as hidden and then show it after the html is hopefully rendered.

It works somehow like this:

.setup(|app| {

      let main_window = app.get_window("main").unwrap();
      // we perform the initialization code on a new task so the app doesn't freeze
      tauri::async_runtime::spawn(async move {
        // adapt sleeping time to be long enough
        sleep(Duration::from_millis(500));
        main_window.show().unwrap();
      });

      Ok(())
    })

and win the tauri.conf.json

"windows": [
  {
    ...
    "visible": false
  }
]

@martpie
Copy link

martpie commented May 17, 2022

I faced the same issue building Museeks with Electron. I am not sure there is much Tauri can do about it.

How I actually solved it is by hiding the window by default, and showing it only after my frontend app has loaded (via an event) (instead of using an arbitrary sleep that may need different values on different systems)

@isopterix
Copy link

@martpie: would you mind sharing your code?

@martpie
Copy link

martpie commented Jun 5, 2022

Of course:

Tauri conf:

"windows": [
  {
    "title": "Your app",
+   "visible": false,
    "fullscreen": false,
    "resizable": true
  }
 ]

Rust side:

#[tauri::command]
pub async fn show_main_window(window: tauri::Window) {
    window.get_window("main").unwrap().show().unwrap(); // replace "main" by the name of your window
}

From your front-end, once you know your app is instantialized (for example with SolidJS):

import { invoke } from '@tauri-apps/api';

// Solid JS speicifc, `componentDidMount` for React, etc...
onMounted(() => {
  invoke('show_main_window');
})

you just have to find the equivalent of Vue, React etc if you use any other

@JonasKruckenberg
Copy link
Contributor

Of course:

Tauri conf:

"windows": [

  {

    "title": "Your app",

+   "visible": false,

    "fullscreen": false,

    "resizable": true

  }

 ]

Rust side:

#[tauri::command]

pub async fn show_main_window(window: tauri::Window) {

    window.get_window("main").unwrap().show().unwrap(); // replace "main" by the name of your window

}

From your front-end, once you know your app is instantialized (for example with SolidJS):

import { invoke } from '@tauri-apps/api';



onMounted(() => {

  invoke('show_main_window');

})

you just have to find the equivalent of Vue, React etc if you use any other

This is in fact the recommendations solution to this problem. And optimizing your Frontend rendering (through ssg or similar) so the delay to first-content is very small. Something like the app-shell architecture helps here as well.

@mantou132

This comment was marked as outdated.

@jlgerber
Copy link

jlgerber commented Aug 1, 2022

Unfortunately, this doesn't seem to work for dynamically created windows. At least with in Sveltekit. If you create a window using WebveiwWindow and set display: false in the options, then the onMount function never gets called for the widget with the supplied route.

@Raduc4
Copy link

Raduc4 commented May 8, 2023

Has anyone solved this?

cguedes added a commit to refstudio/refstudio that referenced this issue Jul 18, 2023
…enders

Note that the webkit white background is a pending tauri issue: tauri-apps/tauri#1564
cguedes added a commit to refstudio/refstudio that referenced this issue Jul 18, 2023
* Rename EmptyView to WelcomeView

* Add splashscreen and load settings and project structure before app renders

Note that the webkit white background is a pending tauri issue: tauri-apps/tauri#1564

* Fix imports

* Add splash.tsx to the entry list of knip

* Fix PR comments and move AppStartup to own file

* Add unit tests

* Make transparent splashscreen

* Revert "Make transparent splashscreen"

This reverts commit 0b267ce.
@reanimatedmanx
Copy link

reanimatedmanx commented Sep 3, 2023

Hey 👋 What if we extend the tauri config to support setting a background color from one single place to both the shell's background color and the webview's background color? So whenever the initial load happens, there would be no "flash granade" thrown into your face.

Then, if needed, it can be overriden by the webview's CSS styles.

So it would be:

  1. Tauri's Config -> appBackgroundColor
  • Sets the background color for the app shell
  • Sets the background color for the webview's browser default background color
  1. Application specific css overrides
  • This would override the webview's browser defaults with whatever color you've picked

@KirillTregubov
Copy link

Just wanted to check in on what the status of this is in 2024. I am still experiencing the issue outlined by the author on Windows 11. The maintainers of wry have added set_background_color to wry::Webview in version 0.21.0. I just checked my Cargo.lock file and the latest version of Tauri seems to be using wry 0.24.7.

Unfortunately, from my research, there seems to be no way for us to accesss this wry API in our Rust code. Is there any plan on exposing this functionality for Tauri users? Alternatively, has anyone found a solution to this issue?

@thnee
Copy link

thnee commented Mar 9, 2024

It's an interesting problem, that is hard to solve. Even some major products still have the white flash on startup problem, like Google Chrome for example.

If we just define a color through a static config file, then it would still flash in the wrong color for users that prefer a different theme. This is less than ideal, but I guess that in general it's at least less annoying with black than white.

A somewhat better solution would be if Tauri could detect light/dark system theme, and set a configurable light/dark background color when creating the initial window. But if an app supports multiple themes, besides just light and dark, then it would still flash in the wrong color for users that prefer a different theme.

There is always going to be a delay between the initial window being created, and frontend code rendering colors. As long as the app is applying any customizable colors through frontend code, there will be a flash of a different color. So ideally there would be some more sophisticated solution here.

One option would be to add some kind of argument or hook to the window creation where a color can be provided as input. So that the app has a chance to read user and system settings and make a decision based on some custom logic, and pass that into the window creation.

It would be really cool if there was a whole theme system in Tauri, where we could define custom themes in config, and it would be integrated, so it applies automatically to window background and decorations, and is made available to the app code as variables in Rust, JS, and CSS.


For Tauri v2, I am using the following workaround. However, I belive this only works for desktop, and there is no equivalent thing for mobile, so the white flash still remains an issue there.

Tauri tauri.conf.json

{
	"app": {
		"windows": [
			{
				"title": "MyTitle",
				"visible": false
			}
		],
	},

SvelteKit +layout.svelte

<script>
	import { onMount } from "svelte";

	import { WebviewWindow } from "@tauri-apps/api/webviewWindow";
	import { PhysicalSize } from "@tauri-apps/api/dpi";

	import globals from "$lib/globals.svelte";

	function setPreferedTheme() {
		let prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
		let value = prefersDark ? "dark" : "light";
		document.documentElement.setAttribute("data-theme", value);
	}

	async function initWindow() {
		if (globals.windowInited) {
			return;
		}

		setPreferedTheme();

		// Sleep because it takes a split second for colors to update after setting theme,
		// which leads to a white flash if using dark theme.
		await new Promise(r => setTimeout(r, 42));

		let window = WebviewWindow.getCurrent();
		await window.setTitle("MyTitle");
		await window.setSize(new PhysicalSize(1400, 800));
		await window.setMinSize(new PhysicalSize(300, 400));
		await window.center();
		await window.show();

		globals.windowInited = true;
	}

	onMount(() => {
		initWindow();
	});
</script>

@pronebird
Copy link
Contributor

pronebird commented Apr 12, 2024

It would be great to expose the background color setting in the Webview API. Spent about an hour trying to set background color here and there and even used some sample from with_webview which returns a platform webview but nothing really worked and the app still flashes white background at open.

@FabianLars
Copy link
Member

but nothing really worked and the app still flashes white background at open.

Likely because it's not (only) the webview flashing but also the native window itself which makes this quite a bit harder.

@pronebird
Copy link
Contributor

but nothing really worked and the app still flashes white background at open.

Likely because it's not (only) the webview flashing but also the native window itself which makes this quite a bit harder.

Good point. I will set the background colour on both and see if it helps.

@pronebird
Copy link
Contributor

I can create a window without webview and change the color. That works fine.

But webview doesn't seem to react to the change of color:

pub trait WebviewExt {
    #[cfg(target_os = "macos")]
    fn set_background_color(&self, color: &tauri::window::Color) -> tauri::Result<()>;
}

impl WebviewExt for tauri::Webview {
    #[cfg(target_os = "macos")]
    fn set_background_color(&self, color: &tauri::window::Color) -> tauri::Result<()> {
        use crate::color_ext::ColorExt;
        let (r, g, b, a) = color.as_nscolor_tuple();

        self.with_webview(move |platform_webview| {
            unsafe {
                let nscolor: cocoa::base::id =
                    msg_send![class!(NSColor), colorWithDeviceRed:r green:g blue:b alpha:a];
                let id = platform_webview.ns_window();
                let () = msg_send![id, setBackgroundColor: nscolor];
            }
        })
    }
}

@rogue-ninja-creative
Copy link

It seems apps using Electron have fixed this. I've been using MongoDB Compass for a long time and it had the same issue; a flash of white before the content loads and the background colour updates. But that seems to have been fixed with the latest update.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: backlog Issue is ready and we can work on it type: feature request
Projects
Status: 📬Proposal
Development

No branches or pull requests