diff --git a/src/BlazorWebView/src/Maui/Android/BlazorWebViewHandler.Android.cs b/src/BlazorWebView/src/Maui/Android/BlazorWebViewHandler.Android.cs index ff348f135250..b17cbf20af75 100644 --- a/src/BlazorWebView/src/Maui/Android/BlazorWebViewHandler.Android.cs +++ b/src/BlazorWebView/src/Maui/Android/BlazorWebViewHandler.Android.cs @@ -49,6 +49,8 @@ protected override AWebView CreatePlatformView() blazorAndroidWebView.Settings.JavaScriptEnabled = true; blazorAndroidWebView.Settings.DomStorageEnabled = true; + blazorAndroidWebView.Settings.MinimumFontSize = 1; + blazorAndroidWebView.Settings.MinimumLogicalFontSize = 1; } _webViewClient = new WebKitWebViewClient(this); diff --git a/src/BlazorWebView/tests/DeviceTests/Elements/BlazorWebViewTests.Behaviors.cs b/src/BlazorWebView/tests/DeviceTests/Elements/BlazorWebViewTests.Behaviors.cs index 561f29063fe0..dd08c6158925 100644 --- a/src/BlazorWebView/tests/DeviceTests/Elements/BlazorWebViewTests.Behaviors.cs +++ b/src/BlazorWebView/tests/DeviceTests/Elements/BlazorWebViewTests.Behaviors.cs @@ -1,4 +1,6 @@ +using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Components.WebView.Maui; @@ -43,4 +45,75 @@ await InvokeOnMainThreadAsync(async () => }); } #endif + +#if ANDROID + const string SmallFontSpanId = "smallFontSpan"; + const string SmallFontCssValue = "4.87761px"; + + static class SmallFontTestStaticFilesContents + { + public const string SmallFontIndexHtmlContent = @" + + + + + + Blazor app + + + + + tiny span text +
+ +
+ An unhandled error has occurred. + Reload + 🗙 +
+ + + + + +"; + } + + /// + /// Regression test for https://github.com/dotnet/maui/issues/26924 - verifies that + /// BlazorWebViewHandler.Android.cs sets MinimumFontSize/MinimumLogicalFontSize to 1 so + /// small CSS font sizes (below the Android WebView's default 8px minimum) aren't clamped up. + /// + [Fact] + public async Task BlazorWebViewDoesNotClampSmallCssFontSizes() + { + EnsureHandlerCreated(additionalCreationActions: appBuilder => + { + appBuilder.Services.AddMauiBlazorWebView(); + }); + + var bwv = new BlazorWebViewWithCustomFiles + { + HostPage = "wwwroot/index.html", + CustomFiles = new Dictionary + { + { "index.html", SmallFontTestStaticFilesContents.SmallFontIndexHtmlContent }, + }, + }; + bwv.RootComponents.Add(new RootComponent { ComponentType = typeof(NoOpComponent), Selector = "#app", }); + + await InvokeOnMainThreadAsync(async () => + { + var bwvHandler = CreateHandler(bwv); + var platformWebView = bwvHandler.PlatformView; + await WebViewHelpers.WaitForWebViewReady(platformWebView); + var computedFontSizeJson = await WebViewHelpers.ExecuteScriptAsync( + platformWebView, + $"parseFloat(window.getComputedStyle(document.getElementById('{SmallFontSpanId}')).fontSize)"); + var computedFontSize = double.Parse(computedFontSizeJson, CultureInfo.InvariantCulture); + + Assert.True(computedFontSize < 8, $"Expected computed font size to be under the 8px clamp, but was {computedFontSize}px."); + }); + } +#endif } diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Issue26924.cs b/src/Controls/tests/TestCases.HostApp/Issues/Issue26924.cs new file mode 100644 index 000000000000..b610ef46e652 --- /dev/null +++ b/src/Controls/tests/TestCases.HostApp/Issues/Issue26924.cs @@ -0,0 +1,69 @@ +namespace Maui.Controls.Sample.Issues +{ + [Issue(IssueTracker.Github, 26924, "Font Size of span Element Not Rendering Correctly in Mobile Mode in .NET MAUI Blazor", PlatformAffected.All)] + public class Issue26924 : TestContentPage + { + WebView _webView; + Label _resultLabel; + Button _checkButton; + + const string SmallFontSpanId = "smallFontSpan"; + internal const string SmallFontCssValue = "4.87761px"; + + protected override void Init() + { + var html = $@" + + + + +

Hi, this is a paragraph.

+ tiny span text + + "; + + _webView = new WebView + { + Source = new HtmlWebViewSource { Html = html }, + HeightRequest = 100, + AutomationId = "SmallFontWebView" + }; + + _resultLabel = new Label + { + Text = "Not checked yet", + AutomationId = "ComputedFontSizeLabel" + }; + + _checkButton = new Button + { + Text = "Get computed font size of span", + AutomationId = "CheckFontSizeButton", + Command = new Command(async () => await CheckComputedFontSizeAsync()) + }; + + // Update the result label once the WebView finishes loading the HTML, so the test + // can wait for "WebView loaded" before tapping the button instead of racing navigation. + _webView.Navigated += (_, __) => _resultLabel.Text = "WebView loaded"; + + Content = new VerticalStackLayout + { + Children = + { + new Label { Text = $"Expected computed font-size to stay close to {SmallFontCssValue} (i.e. under 8px), not be clamped up by the platform WebView's minimum font size." }, + _webView, + _checkButton, + _resultLabel + } + }; + } + + async Task CheckComputedFontSizeAsync() + { + var computedFontSize = await _webView.EvaluateJavaScriptAsync( + $"window.getComputedStyle(document.getElementById('{SmallFontSpanId}')).fontSize"); + + _resultLabel.Text = computedFontSize?.Trim('"') ?? string.Empty; + } + } +} diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue26924.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue26924.cs new file mode 100644 index 000000000000..5a8225c43ca6 --- /dev/null +++ b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue26924.cs @@ -0,0 +1,30 @@ +using System.Globalization; +using NUnit.Framework; +using UITest.Appium; +using UITest.Core; + +namespace Microsoft.Maui.TestCases.Tests.Issues; + +public class Issue26924 : _IssuesUITest +{ + public Issue26924(TestDevice device) : base(device) + { + } + + public override string Issue => "Font Size of span Element Not Rendering Correctly in Mobile Mode in .NET MAUI Blazor"; + + [Test] + [Category(UITestCategories.WebView)] + public void SmallFontSizeSpanIsNotClampedByMinimumFontSize() + { + // The result label is updated to "WebView loaded" once the WebView finishes loading + // the HTML, so wait for that before tapping the button to avoid racing navigation. + App.WaitForTextToBePresentInElement("ComputedFontSizeLabel", "WebView loaded"); + App.Tap("CheckFontSizeButton"); + App.WaitForTextToBePresentInElement("ComputedFontSizeLabel", "px"); + var computedFontSizeText = App.WaitForElement("ComputedFontSizeLabel").GetText(); + Assert.That(computedFontSizeText, Is.Not.Null); + Assert.That(float.Parse(computedFontSizeText!.Trim().TrimEnd('p', 'x'), CultureInfo.InvariantCulture), Is.LessThan(8f)); + } +} + diff --git a/src/Core/src/Platform/Android/WebViewExtensions.cs b/src/Core/src/Platform/Android/WebViewExtensions.cs index f09cd7397f23..10635091583a 100644 --- a/src/Core/src/Platform/Android/WebViewExtensions.cs +++ b/src/Core/src/Platform/Android/WebViewExtensions.cs @@ -39,6 +39,10 @@ public static void UpdateSettings(this AWebView platformWebView, IWebView webVie platformWebView.Settings.JavaScriptEnabled = javaScriptEnabled; platformWebView.Settings.DomStorageEnabled = domStorageEnabled; + // Android WebView defaults MinimumFontSize to 8, which silently + // clamps up any CSS font-size below 8px. + platformWebView.Settings.MinimumFontSize = 1; + platformWebView.Settings.MinimumLogicalFontSize = 1; } public static void UpdateUserAgent(this AWebView platformWebView, IWebView webView)