dvFallbackCss top-level constant

String const dvFallbackCss

The fallback's own stylesheet, and the rules that print it.

The crawler-visible block is real semantic HTML -- headings, links, code blocks -- and it shipped with none. Viewed with scripting off, or by anything that does not run the app, every line ran the full width of the window in the browser's default serif.

Every rule is scoped to .dv-fallback, so none of it reaches the running application: a max-width on body would break every Dartvel app's own layout, and nothing here sets one.

On the screen the block is a clipped box one pixel square: laid out, so the browser's find searches it, and painting nothing, so the application keeps the screen. It used to be display:none, which is the one kind of hidden find skips, and is why Ctrl+F on a Dartvel page found nothing. Each paragraph inside is hidden="until-found" besides (see dvFindableHtml), which is what makes the browser say which one it matched.

It is shown again in two places. A reader with scripting off gets it from the <noscript> override, which is the one thing noscript is still needed for. A printer gets it from the @media print rules, which also take away what Flutter paints into: a canvas prints as one bitmap the width of the window -- clipped, at screen resolution, with no text to select and no page break anywhere sensible. Both turn the until-found paragraphs on as well, and by [data-dv-anchor] rather than by the attribute's value: a browser that does not know until-found reads it as plain hidden, and a page that opted out of find keeps its paragraphs plainly hidden.

A reading column, a system font, and the reader's colour scheme. Nothing decorative: this is the page someone sees when the app cannot run, and it should look like a document rather than like a broken site.

Implementation

const String dvFallbackCss =
    '.dv-fallback{max-width:44rem;margin:0 auto;padding:2rem 1.25rem;'
    'font:16px/1.65 -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;'
    'color:#0b1020;background:#fff}'
    '.dv-fallback h1{font-size:1.9rem;line-height:1.2;margin:0 0 1rem}'
    '.dv-fallback h2{font-size:1.35rem;line-height:1.25;margin:2rem 0 .75rem}'
    '.dv-fallback h3{font-size:1.1rem;margin:1.5rem 0 .5rem}'
    '.dv-fallback p{margin:0 0 1rem}'
    '.dv-fallback a{color:#2f6bff}'
    '.dv-fallback pre{overflow-x:auto;padding:1rem;border-radius:8px;'
    'background:#0b1020;color:#c0caf5}'
    '.dv-fallback code{font:13.5px/1.6 ui-monospace,Menlo,Consolas,monospace}'
    '@media (prefers-color-scheme:dark){'
    '.dv-fallback{color:#f2f5fa;background:#0a0d13}'
    '.dv-fallback a{color:#7ba2ff}}'
    // In the document, off the screen. The application is what the reader
    // came for; this is what the crawler, the printer, the browser's find
    // and a browser with no scripting get instead. Fixed, so a find that
    // scrolls to it moves nothing the reader can see.
    '@media screen{.dv-fallback{position:fixed;top:0;left:0;width:1px;'
    'height:1px;max-width:none;margin:0;padding:0;border:0;overflow:hidden;'
    'clip-path:inset(50%);white-space:normal;pointer-events:none}}'
    // What the printer is given. Flutter's own host elements go first: they
    // are what the page looks like and not what it says.
    '@media print{'
    'flutter-view,flt-glass-pane,flt-scene-host,flt-semantics-host,canvas'
    '{display:none!important}'
    '.dv-fallback{display:block!important;position:static!important;'
    'width:auto!important;height:auto!important;overflow:visible!important;'
    'clip-path:none!important;max-width:none;margin:0;padding:0;'
    'color:#000;background:#fff;font-size:11pt}'
    '.dv-fallback [data-dv-anchor]{display:block!important;'
    'content-visibility:visible!important}'
    '.dv-fallback a{color:#000;text-decoration:underline}'
    // Nobody clicks a printed link, so it has to say where it went.
    '.dv-fallback a[href]::after{content:" (" attr(href) ")";font-size:.85em}'
    '.dv-fallback pre{background:#fff;color:#000;border:1px solid #999;'
    'white-space:pre-wrap}'
    '.dv-fallback h1,.dv-fallback h2,.dv-fallback h3{break-after:avoid}'
    '@page{margin:18mm}'
    '}';