We are currently experiencing an issue related to initial page load styling in a Blazor Server application using LeptonX theme. To better demonstrate the behavior, I tested under Slow 4G network throttling, where the issue becomes clearly visible.
Issue Description Before applying any optimizations, the application exhibited a Flash of Unstyled Content (FOUC) during initial load. The layout and styles appeared with a noticeable flash (https://screenapp.io/app/v/KEO2mHHQOm). I implemented several optimizations on our side as well, this reduced the impact, but a slight flash was still noticeable.
Analysis & Findings After investigation, this behavior appears to be primarily caused by delayed loading/injection of ABP/LeptonX CSS, rather than an issue in our application code. I found a similar issue discussed here: https://abp.io/support/questions/4809/Stylesheets-are-loaded-very-late https://gist.github.com/realLiangshiwei/70e19e34389ce7e567b5078a42db230a
Workaround Applied I applied the suggested workaround by adding: <leptonx-theme-appearance />
Current Behavior (After Fix) After applying this:
- The layout shift / FOUC issue is resolved ✅
- However, I now observe a brief black screen before the UI renders (https://screenapp.io/app/v/FVG7x2k5AP)
Concern While the workaround improves styling consistency, the black screen introduces a different UX issue (perceived delay before content appears).
Questions
- Are there any recommended approaches to Avoid both FOUC and black screen, and improve perceived loading performance?
- Has this issue been addressed or improved in newer ABP/LeptonX versions?
14 Answer(s)
-
0
In ABP Blazor Server + LeptonX, the FOUC you saw is typically caused by theme-appearance/theme CSS being applied only after the Blazor circuit starts and LeptonX determines the active appearance (light/dark/system). Adding
<leptonx-theme-appearance />fixes the FOUC by applying appearance early, but it can also produce a brief black screen because the page background/appearance is set immediately (often to dark) before the rest of the UI/LeptonX layout finishes rendering under slow networks.The practical way to avoid both effects is to make the initial HTML render with a stable background + minimal critical CSS, so the browser never shows an unstyled/incorrect theme, and it never shows a black blank page either.
What to do (Blazor Server, ABP 9.1.3, LeptonX)
Keep using
<leptonx-theme-appearance />(it’s the correct direction to prevent late theme injection/FOUC).Add a tiny “critical” inline style (or a very small local CSS loaded before everything else) that:
- sets
html, bodybackground to the expected color (or at least a neutral non-black color), - hides the app root until LeptonX appearance is applied, but shows a lightweight placeholder/skeleton instead of a black screen.
Conceptually:
- show a placeholder immediately (fast paint),
- once the theme/appearance class/attribute is applied, reveal the real app.
- sets
Ensure your LeptonX/ABP global CSS bundle is emitted as early as possible in the host page (
_Host.cshtml/ layout). In ABP, this is normally done via the theme’s recommendedAbpStylesbundle usage (per the LeptonX Blazor doc). If you’ve customized the host markup, revert to the recommended placement so styles are in<head>and not deferred.If the “black screen” is specifically because the appearance resolves to dark on first load under throttling, set a deterministic default appearance (e.g., Light) instead of “System”, or persist the user preference and apply it immediately. (This prevents an initial “dark background” paint on devices where system preference is dark.)
Has it been improved in newer versions?
No verified source available that explicitly states this specific FOUC vs black-screen behavior was fixed in a particular ABP/LeptonX version. The only verified guidance available is the general LeptonX Blazor integration approach and the known “late styles” discussion you already found.
Links (validated):
- https://abp.io/support/questions/4809/Stylesheets-are-loaded-very-late
- https://abp.io/docs/latest/ui-themes/lepton-x/blazor
This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
I want support team to jump in and help. Need some verified solution/information on this.
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
Hi,
Could you share the following details so we can better assist you?
- What ABP version are you using?
- Are you using the
_Host.cshtmlhosting model or the newerApp.razor(Blazor Web App) pattern?
Thanks
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
- ABP version - 9.1.3
- Yes I am using
_Host.cshtml
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
Hi,
The root cause is that you are using the old
_Host.cshtmlhosting model withrender-mode="Server", which does not have server-side prerendering. This means the page body is empty until the Blazor SignalR circuit is established.- Without
<leptonx-theme-appearance />: The LeptonX theme variant CSS (dark/dim/light) is loaded dynamically after Blazor connects, causing the FOUC. - With
<leptonx-theme-appearance />: The theme CSS is loaded in the initial HTML (including background color), but the body content is still empty waiting for Blazor to connect, which causes the black screen.
ABP 9.x uses the new Blazor Web App pattern with
App.razorinstead of_Host.cshtml. The new pattern uses@rendermode="InteractiveServer"which has SSR prerendering by default — the initial HTML response already contains both the CSS and the rendered content, so there is no FOUC or black screen.Here is the
App.razorstructure used in ABP 9.x Blazor Server projects with LeptonX:I'd recommend creating a fresh ABP 9.1.3 Blazor Server project using ABP CLI or ABP Studio, then compare its structure with your current project. The new project will use
App.razorby default and should not have the FOUC / black screen issue. You can use it as a reference to migrate your existing project.Thanks
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) - Without
-
0
I migrated to App.razor but still getting the same issue - https://screenapp.io/app/v/L80XhRnWZw Do I still have to use <leptonx-theme-appearance />?
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
Applying
<Volo.Abp.AspNetCore.Components.Server.LeptonXTheme.Components.AppearanceStyles />resolved the issue.Could you please share any documentation that can help me optimize
App.razoreven further? There's still a scope for improvement - https://share.zight.com/d5uq69KzMarkdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
Hi,
Glad to hear
<AppearanceStyles/>resolved the issue! That's the correct approach for theApp.razorhosting model — it renders all LeptonX theme CSS links during SSR prerendering, so the styles are included in the initial HTML response.Your current
App.razorsetup should already match the official ABP template structure:<head> <AbpStyles BundleName="@BlazorLeptonXThemeBundles.Styles.Global" /> <link href="YourProject.Blazor.styles.css" rel="stylesheet"/> <HeadOutlet @rendermode="InteractiveServer" /> <AppearanceStyles/> </head>For Blazor Server, the
AbpStylescomponent resolves and renders CSS links at runtime on the server side, so noabp bundlecommand is needed.For further optimization, you can enable bundle & minify mode in production to merge multiple CSS/JS files into fewer requests. Configure it in your module's
ConfigureServices:Configure<AbpBundlingOptions>(options => { options.Mode = BundlingMode.BundleAndMinify; });Some useful references:
- Migration guide for the new
App.razorhosting model: https://abp.io/docs/latest/release-info/migration-guides/abp-8-2-blazor-web-app - Bundling & Minification configuration: https://abp.io/docs/latest/framework/ui/mvc-razor-pages/bundling-minification
- Blazor global scripts & styles: https://abp.io/docs/latest/framework/ui/blazor/global-scripts-styles
Thanks
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) - Migration guide for the new
-
0
Hi Thanks!
According to ABP best practices, should I keep
App.razorclean and move all the styles and scripts to MainBlazor Module and minify it using theAbpBundlingOptions?I am unable to share my final code here, can I email at <liming.ma@volosoft.com>?
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
Hi,
The
App.razorin the ABP template is already clean —<AbpStyles>and<AbpScripts>just reference a bundle name, and the actual CSS/JS files are managed throughBundleContributorin your modules. You don't need to move anything out ofApp.razor.I'd suggest creating a new ABP 9.1.3 Blazor Server project with the same configuration as yours:
Then compare the new project's
App.razorand module configuration with your current project. The new template is the best reference for best practices.Thanks
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
By default ABP CLI (I have the latest version) creates .NET10 project with App.razor. Should I follow that? If I uninstall and install older ABP CLI version, it gives version compatibility warnings.
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
Hi,
You can just create a new project with your current CLI version:
abp new BookStore -t app -u blazor-serverThe
App.razorstructure is the same across versions — you can use the new project as a reference to migrate your existing project from_Host.cshtmltoApp.razor.Thanks
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
While testing these changes, I encountered a
System.InvalidOperationException Message=JavaScript interop calls cannot be issued at this time. This is because the component is being statically rendered. When prerendering is enabled, JavaScript interop calls can only be performed during the OnAfterRenderAsync lifecycle method.on full page reloads related to JavaScript interop during prerendering. As a temporary workaround, I have disabled prerendering. Can you help in this?
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
Hi,
This error happens because the new
App.razormodel uses SSR prerendering by default. During prerendering, JavaScript interop is not available — it can only be called inOnAfterRenderAsync.In your old
_Host.cshtmlsetup withrender-mode="Server", there was no prerendering, so JS interop calls inOnInitializedAsyncworked fine. After migrating, those same calls will fail during the prerendering phase.To help you fix this, could you share the following files:
App.razor- Your Blazor module class (e.g.,
MyProjectNameBlazorModule.cs) - The full stack trace of the exception
- Are you using any third-party Blazor component libraries?
Thanks
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
