flutter_html_css_font_size 0.2.0
flutter_html_css_font_size: ^0.2.0 copied to clipboard
A flutter_html extension that renders a relative CSS font-size. flutter_html 3.0.0 drops rem and compounds em and percentages.
Example #
flutter_html 3.0.0 gets four relative font sizes wrong. The rem branch of
ExpressionMapping.expressionToFontSize is commented out, so font-size: 2rem
is dropped at parse time and the element renders at the size it inherits. An
em or a percentage parses, and is then applied once per level of the tree
below the element that declares it, so font-size: 2em renders its text at 56
where CSS says 28. A tag with a per-tag default inside such an element is
resolved against the parent's raw 2em, so an h1 there renders at 4 where
CSS says 56. A relative <font size="+2"> renders at 14 rather than at step 5.
There is no error and no warning in any of the four. This extension writes the
CSS size into the element and its subtree.
import 'package:flutter/material.dart';
import 'package:flutter_html/flutter_html.dart';
import 'package:flutter_html_css_font_size/flutter_html_css_font_size.dart';
class ExampleApp extends StatelessWidget {
const ExampleApp({super.key});
@override
Widget build(BuildContext context) => MaterialApp(
home: Scaffold(
body: Html(
data: '''
<div style="font-size: 2rem;">
Twice the root size, which is 28 logical pixels.
</div>
<div style="font-size: 0.875rem;">
Seven eighths of it, at 12.25.
</div>
<div style="font-size: 1.5rem;">
A heading size, with
<span style="font-size: 0.875rem;">a smaller run inside it.</span>
</div>
<div style="font-size: 2em;">
Twice the parent size, at 28, and
<span style="font-size: 1.5em;">1.5 times that, at 42.</span>
</div>
<div style="font-size: larger;">
One step up from the inherited size.
</div>
<div style="font-size: 2em;">
<h1>A heading here renders at 56, not at 4.</h1>
<small>And this run at 23.24, not at 1.66.</small>
</div>
''',
extensions: const [CssFontSizeHtmlExtension()],
),
),
);
}
The root size #
rem resolves against the document's root font size. flutter_html takes that
from the ambient DefaultTextStyle, and uses FontSize.medium, which is 14,
where that states none. A browser uses 16, so the same HTML renders smaller
here than it does on the web.
Pass the browser's number to get the browser's sizes:
const CssFontSizeHtmlExtension(rootFontSize: 16);
With a utility-class extension #
Bootstrap's fs-1 to fs-6 and every Vuetify text-* typography class state
their size in rem. Register either package with this one and those classes
render at their real size. Order does not matter.
Html(
data: '<p class="fs-3">Bootstrap fs-3, 1.75rem</p>',
extensions: const [
BootstrapUtilitiesHtmlExtension(),
CssFontSizeHtmlExtension(),
],
);
Order matters against an extension that reads Style.fontSize at the
preProcessing step, such as flutter_html_css_text_metrics. List this
one first, or that one resolves its em lengths against the old size.
flutter_html_bootstrap 0.1.1 and
flutter_html_vuetify 0.1.0 need no change for this. Both treat
font-size as a property flutter_html renders. So both emit the declaration,
and neither reports the class as unsupported. Only the rem value goes
missing.
Bootstrap 0.1.2 and Vuetify 0.1.1 differ. From those versions on they suppress
a font-size whose value is rem, smaller or larger. Bootstrap then
reports fs-1 to fs-6 as unsupported classes. Vuetify reports its typography
classes as partly rendered. Both reports go to FlutterError.reportError.
Neither throws. Registering CssFontSizeHtmlExtension stops the suppression
and the report, because each package reads it from its companion registry as a
fontSizeUnits entry.
Register this extension either way. Against bootstrap 0.1.1 and vuetify 0.1.0 it renders the size. From bootstrap 0.1.2 and vuetify 0.1.1 it also keeps the declaration.
Reading a font size from another extension #
resolvedFontSizeOf answers what size an element should render at. It works at
every step, including the ones that run before flutter_html resolves relative
sizes.
import 'package:flutter/foundation.dart';
import 'package:flutter_html/flutter_html.dart';
import 'package:flutter_html_css_font_size/flutter_html_css_font_size.dart';
class MyExtension extends HtmlExtension {
const MyExtension();
@override
Set<String> get supportedTags => const {};
@override
bool matches(ExtensionContext context) =>
context.currentStep == CurrentStep.preStyling;
@override
void beforeStyle(ExtensionContext context) {
final styledElement = context.styledElement;
if (styledElement == null) return;
// An `em` length of your own can now be resolved.
final fontSize = resolvedFontSizeOf(styledElement);
debugPrint('${styledElement.name} renders at $fontSize');
}
}
It reads the DOM: the inline style="" of the element and of every ancestor,
plus flutter_html's own per-tag defaults, such as 2em for h1. A size set
through Html(style: ...) or by another extension is invisible to it.
What is left alone #
px, a unitless 0 and xx-small to xx-large all reach Style.fontSize
without this extension, and none of them compounds, so it does not touch them.
calc(), inherit and units such as pt and vw are not handled by either.
One case stays wrong with this extension registered. It is measured against
flutter_html 3.0.0 and it is in
doc/relative-sizes.md.
An em resolves against the inline sizes of the ancestor chain. A size set
through Html(style: ...) or in a <style> block is invisible there, so a
2em under a 20px div renders at 28 where CSS says 40. There is no error and
no warning.
Every size on this page is a Flutter logical pixel, the unit Style.fontSize
holds. It is not a physical device pixel.