flutter_html_css_units 0.3.0
flutter_html_css_units: ^0.3.0 copied to clipboard
A flutter_html extension that renders the CSS absolute and viewport length units flutter_html 3.0.0 reads as pixels or as zero: pt, pc, in, cm, mm, Q, vw, vh, vmin and vmax.
Example #
flutter_html 3.0.0 maps every length unit it does not know to pixels and reads a
viewport unit as zero. 12pt renders 12 logical pixels, 1in renders 1, 2cm renders
2, 50vw renders 0 and font-size: 5vw is dropped. This extension rewrites those tokens
in the inline style to px before flutter_html parses it.
import 'package:flutter/material.dart';
import 'package:flutter_html/flutter_html.dart';
import 'package:flutter_html_css_units/flutter_html_css_units.dart';
class ExampleApp extends StatelessWidget {
const ExampleApp({super.key});
@override
Widget build(BuildContext context) => MaterialApp(
home: Scaffold(
body: Html(
data: '''
<p style="font-size: 12pt; line-height: 18pt;">
Body text at sixteen pixels. Without this extension, twelve.
</p>
<div style="width: 50vw; height: 10vh; padding: 5mm;
border: 1pt solid #333;">
Half the window wide. Without this extension, zero wide.
</div>
<p style="font-size: 5vw;">
Scales with the window. Without this extension, dropped.
</p>
<div style="margin: 1cm 0; height: 1in;">
A centimetre of margin, an inch tall.
</div>
''',
extensions: const [CssUnitsHtmlExtension()],
),
),
);
}
void main() => runApp(const ExampleApp());
What it corrects #
pt,pc,in,cm,mmandQ, whichflutter_htmlreads as their bare number.vw,vh,vminandvmax, which it reads as zero, and which drop afont-size.svh,lvh,dvhand the other small, large and dynamic variants, whichcsslibcannot lex andflutter_htmlreads as the bare number.!importanton any of those declarations.
The correction reaches width, height, font-size, line-height, margin, padding,
border and text-shadow, plus the lengths a sibling extension renders.
Behaviour #
The extension rewrites the element's inline style attribute at the preStyling step,
before flutter_html parses it. Each absolute length is converted by the CSS ratios,
where 1in is 96px. Each viewport length is converted against the viewport. Everything
else in the attribute is copied through unchanged, including a quoted string, a url()
and a declaration in a property this package does not handle.
flutter_html's own cascade does the rest. The extension writes no Style field and
walks no subtree, so an inherited font-size reaches a descendant exactly as it does for
a size flutter_html reads by itself.
A value the extension cannot convert is left alone, byte for byte. ex, ch, fr,
px, em, rem and % are all in that group, and the element renders exactly as it
would without the extension.
The viewport #
The viewport is MediaQuery.sizeOf, read through ExtensionContext.buildContext at the
preStyling step. It resolves once, when the widget first parses its document, because
the rewrite replaces 50vw in the DOM with 400px and a later parse reads that DOM.
Pass viewportSize when the basis is not the window. Under a LayoutBuilder the
constraints of the Html widget itself are one such basis:
LayoutBuilder(
builder: (context, constraints) => Html(
key: ValueKey(constraints.biggest), // re-parse when the basis changes
data: '<div style="width: 50vw; height: 25vh">A quarter of the card</div>',
extensions: [CssUnitsHtmlExtension(viewportSize: constraints.biggest)],
),
);
The key is what makes a resize take effect. Without it the widget keeps the DOM of its first parse, and the first width stays. A side the builder reports as infinite, such as the height under a scroll view, leaves that axis alone.
Pairing with other extensions #
List this extension after CssStylesheetHtmlExtension and after a utility-class
extension, and before CssBorderHtmlExtension:
Html(
data: '<style>.card { width: 1in }</style>'
'<div class="card vh-100" style="border-width: 1pt; border-style: solid">'
'Card</div>',
extensions: const [
CssStylesheetHtmlExtension(),
BootstrapUtilitiesHtmlExtension(),
CssUnitsHtmlExtension(), // after those two, before the border extension
CssBorderHtmlExtension(),
],
);
Listed before the stylesheet, width: 1in renders 1; listed before Bootstrap, vh-100
renders 0; listed after the border extension, 1pt renders 1. Every one is measured
against the released sibling and recorded in doc/units.md.