flutter_html_css_units

pub version pipeline license GitLab

A flutter_html extension that renders the CSS absolute and viewport length units flutter_html 3.0.0 reads wrong. 12pt renders 12 pixels, 1in renders 1, 50vw renders 0 and font-size: 5vw is dropped. There is no error and no warning.

Contents

Features

Declaration flutter_html alone With this extension
width: 12pt 12 16
width: 1in 1 96
width: 2cm 2 75.59
width: 5mm 5 18.90
width: 3pc 3 48
width: 50vw 0 400
width: 10dvh 10 60
font-size: 5vw dropped 40
border: 1pt solid red 1 1.33
transform: translate(1in, 0) 0 96
flex: 0 0 2in 14.25 192

Every number is measured against flutter_html 3.0.0 in a viewport of 800 by 600 logical pixels, and pinned by a test.

One rewrite of the style attribute at the preStyling step covers every length flutter_html reads: width, height, font-size, line-height, margin, padding, border and text-shadow. It also covers the lengths a sibling extension reads, such as max-width, border-width, letter-spacing, text-decoration-thickness, transform, flex and grid-template-columns.

Getting started

dependencies:
  flutter_html: ^3.0.0
  flutter_html_css_units: ^0.3.0

Usage

import 'package:flutter_html/flutter_html.dart';
import 'package:flutter_html_css_units/flutter_html_css_units.dart';

Html(
  data: '''
    <p style="font-size: 12pt; margin: 0 5mm; width: 50vw;">
      Sixteen pixels of text, half the window wide
    </p>
  ''',
  extensions: const [CssUnitsHtmlExtension()],
);

A viewport unit resolves against MediaQuery.sizeOf, read through the parser's own BuildContext at the preStyling step. Pass viewportSize to resolve against a size of your own:

Html(
  data: '<div style="height: 50vh">Half the card</div>',
  extensions: const [CssUnitsHtmlExtension(viewportSize: Size(400, 300))],
);

Before you register it

List this extension after flutter_html_css_stylesheet and after flutter_html_bootstrap or flutter_html_vuetify. All of them write into the inline style at the preStyling step, where flutter_html runs every extension in registration order. A declaration written after this extension has run keeps its unit, and flutter_html discards it.

Html(
  data: '<style>.card { width: 1in }</style><div class="card vh-100">Card</div>',
  extensions: const [
    CssStylesheetHtmlExtension(),
    BootstrapUtilitiesHtmlExtension(),
    CssUnitsHtmlExtension(), // after both, or width is 1 and height is 0
  ],
);

Measured: with this extension listed first, width: 1in from the stylesheet renders 1 and vh-100 renders 0.

List this extension before flutter_html_css_border. That package reads every length unit as its bare number at the same step, so 3pt becomes 3px before this extension sees it. Measured on border-width: 3pt: 4 listed first, 3 listed second.

Order against flutter_html_css_color, flutter_html_css_size_constraints, flutter_html_css_font_size and flutter_html_css_percent_size does not matter. All four are measured in both orders.

Order against flutter_html_css_transform, flutter_html_css_flex and flutter_html_css_text_metrics does not matter either. All three read the inline style after the preStyling step, so this extension always writes first.

Limitations

  • ex, ch, cap, ic and lh still render 0. They need font metrics no step exposes.
  • calc(), min(), max() and clamp() stay dropped. The lengths inside them are converted, but flutter_html drops the function whole.
  • A viewport unit resolves once, when the Html widget first parses its document. A window resize does not re-resolve it; a new widget key does.
  • A <style> block and an external stylesheet are not read.
  • text-decoration-thickness needs flutter_html_css_text_metrics 0.2.0, which is not on pub.flutter-io.cn yet. Against its 0.1.0 the rewritten length is still dropped. Measured on a red underline at font-size: 40px: 30pt paints 79 red pixels, one row tall, without this extension, and 720 pixels, nine rows tall, with it and with text-metrics 0.2.0, which is what 40px paints on its own.

The measurement table records every case and every order.

Additional information

Issues and merge requests go to the GitLab repository.

CI, publishing and Renovate are described in CONTRIBUTING.md.