Each section triggers one known limitation of
snapdom, the library
behind MarkUp's comment screenshots. Pin a comment on the marker in
each fixture, then compare the screenshot with what you see here.
Versions in play
Where
snapdom
Preview env (mar-4055-snapdom-markup-website):
proxy-bundle and markup-sdk
3.0.0
develop: markup-sdk screenshot plugin
2.24.3
Upstream latest
3.4.0
How to test
Turn on the SCREENSHOT_CLIENT_DOM workspace flag
and disable the MarkUp extension. With the
extension on, MarkUp takes a native tab screenshot and none of
this applies.
Create a website markup of this page in the preview environment.
In each fixture, click the + pin here marker.
Pin captures crop to about 55% of the viewport around the click,
so the marker sits in the middle of the fixture.
Sections tagged Picker mode also need a
Take screenshot of the named element.
Compare each screenshot with the live fixture and its "In
MarkUp" line.
Any version snapdom can't do
thisMitigated by MarkUp our
proxy works round itFixed in x.y.z broken in a
version we shipSafari
browser-specificPicker mode needs Take
screenshot
A. Can't capture, any version
These come from how snapdom works: it copies the DOM into an SVG
<foreignObject> and lets the browser re-draw the
copy. It never takes a real screenshot.
A1
Cross-origin iframes
Any versionMostly mitigated by MarkUp
snapdom can't read inside a frame from another origin, so it paints
a grey placeholder. MarkUp's proxy rewrites third-party iframes and
asks its bundle inside each one to capture itself, which hides this
in most cases. These six frames include the ways round that.
In MarkUp (preview, 3.0.0 via proxy)
example.com and YouTube: real
content (nested capture). sandbox: placeholder
(no scripts, so the frame never answers).
data: URL: placeholder (opaque origin).
frame.html: its green page shows, but the
example.com inside it is a placeholder (nested capture doesn't
recurse). srcdoc: renders.
Raw snapdom / SDK (no proxy)
Every cross-origin frame is a placeholder. frame.html and srcdoc
render, with a placeholder for the example.com inside frame.html.
snapdom re-downloads every image so it can embed it. If the image's
server sends no CORS headers, it can't, even though the browser
displays the image fine. google.com sends none; placehold.co does.
In MarkUp (preview, 3.0.0 via proxy)
All four render. MarkUp sets snapdom's useProxy to
its /__markup_cors__ relay, which fetches no-CORS
images on the server.
Raw snapdom / SDK (no proxy)
The Google <img> becomes a grey placeholder and
the Google CSS background disappears: the SDK's
captureElement passes no useProxy.
placehold.co and the local SVG render.
A canvas that has drawn a cross-origin image without CORS is
tainted: the browser stops every script from reading its
pixels, snapdom included. Charts and maps that draw remote tiles hit
this.
In MarkUp (preview, 3.0.0 via proxy)
The left canvas is blank or a placeholder. The relay can't help,
because the pixels are already locked inside the canvas. The right
canvas renders.
Draws the google.com logo (no CORS)Loading logo...
Draws only its own shapes (control)toDataURL() works
+ pin here
A4
Video and audio
Any version
snapdom grabs a video's current frame by drawing it to a canvas. A
cross-origin video without CORS taints that canvas, so snapdom falls
back to the poster image. Audio players are re-drawn, not captured.
In MarkUp (preview, 3.0.0 via proxy)
Left: the flower frame you see.
Middle: the orange POSTER, not the bunny frame
you see (MarkUp's relay only passes images, fonts and CSS).
Right: a drawn stand-in for the audio controls,
which may not match your browser's player.
snapdom copies a canvas's pixels at the moment of capture. Charts,
maps and Lottie animations that are still loading come out empty.
This canvas alternates: 5 seconds blank, 5 seconds painted.
In MarkUp (preview, 3.0.0 via proxy)
Whatever the canvas holds when you pin. Pin while the label says
Blank and the chart area is empty, even if it paints a
moment later. The label itself is ordinary text and always shows.
Fonts loaded with the JavaScript FontFace() API have no
CSS rule pointing at the file, so snapdom can't find the file to
embed. Both lines use the same Bungee font file.
In MarkUp (preview, 3.0.0 via proxy)
The top line falls back to Courier. MarkUp waits for every font in
document.fonts, but its localFonts list
only reads @font-face rules. The bottom line renders
in Bungee.
Unstyled form controls are painted by the operating system's theme.
snapdom copies their computed CSS instead, which the browser then
draws literally. The maintainer calls this a known limitation.
In MarkUp (preview, 3.0.0 via proxy)
Borders on inputs, buttons and selects look heavier or darker than
live. In Firefox, checkboxes and radios are drawn replacements. In
mobile Firefox, placeholder and select text may sit in the wrong
place.
Safari sometimes paints an SVG foreignObject before its
embedded images have decoded, so images and background images go
missing, most often on the first capture. The maintainer traces this
to a WebKit bug.
In MarkUp (preview, 3.0.0 via proxy)
Chrome and Firefox: all five tiles and the emoji present. Safari
and iOS: one or more tiles may be blank, most likely on the first
pin after loading. MarkUp runs its first capture twice as a
warm-up, which may hide this.
Raw snapdom / SDK (no proxy)
Same, and more likely to show without the warm-up.
snapdom re-draws a copy of the page rather than taking a real
screenshot, so small differences creep in.
In MarkUp (preview, 3.0.0 via proxy)
(a) Pin: fine. Picker on the purple card:
captured at 70% of its size, because its ancestor is scaled.
(b) The orange custom scrollbar is missing or
native; the scroll position should be kept.
(c) Each cyan line fits with 0.25px to spare, so
a line may wrap its last word in the capture.
Pick this card
Its parent has transform: scale(0.7).
(b) Custom scrollbar, scrolled halfway
line 01
line 02
line 03
line 04
line 05
line 06
line 07
line 08
line 09
line 10 (middle)
line 11 (middle)
line 12
line 13
line 14
line 15
line 16
line 17
line 18
line 19
line 20
(c) Lines sized to fit with 0.25px to spare
The quick brown fox jumps over the lazy dog.
Sphinx of black quartz, judge my vow, said Wilf.
Pack my box with five dozen liquor jugs, please.
+ pin here
A10
Closed shadow roots
Any versionPicker mode
A web component with a closed shadow root hides its contents from
every page script. snapdom only flattens open shadow roots. No issue
reports this; the features doc only promises open ones.
In MarkUp (preview, 3.0.0 via proxy)
Left: an empty dashed box where the card should be. The picker
can't select inside it either. Right: the open card renders.
snapdom only reads @font-face rules from a cross-origin
stylesheet if its host is on a fixed list of font CDNs (Google
Fonts, Typekit, Font Awesome, jsDelivr, unpkg, cdnjs, esm.sh) or in
the fontStylesheetDomains option, or its URL mentions
"font" or the family name. A customer's own CDN usually matches none
of those, and MarkUp's localFonts can't read the sheet
either. The stylesheet is linked without crossorigin,
so MarkUp's proxy leaves it alone. The 3.3.5 change that reads
cross-origin sheets only applies to sheets that pass this filter.
In MarkUp (preview, 3.0.0 via proxy)
The top line falls back to Courier. The bottom line (same font,
same-origin stylesheet) renders in a script face.
Raw snapdom / SDK
Same in 2.24.3, 3.0.0 and 3.4.0. With
fontStylesheetDomains set to the stylesheet's host,
all three embed the font (try &fsd=<host>
with the harness). MarkUp could pass the hosts of every
cross-origin stylesheet on the page.
These are bugs, not hard limits. Each one is fixed in a later snapdom,
so the result depends on which version captures the page. Use
?harness=3.4.0 locally to see the fixed behaviour.
B1
Font families containing __
Fixed in 3.4.0Broken in 3.0.0 and 2.24.3
next/font names fonts like __Inter_d65c78.
snapdom builds an internal key as
family__weight__style and splits it on __,
so these families never match and never get embedded. Both lines use
the same Monoton file.
In MarkUp (preview, 3.0.0 via proxy)
The top line falls back to Courier. This also shows whether
MarkUp's localFonts list gets round the bug; we
expect not. The bottom line renders in Monoton.
Raw snapdom / SDK
2.24.3 and 3.0.0: same. 3.4.0: both lines render in Monoton.
For WebGL canvases with preserveDrawingBuffer: false,
snapdom 2.24.3 waits for the next animation frame before reading the
pixels, with no timeout. Browsers don't run animation frames in a
hidden tab, so a capture started just before switching tabs hangs.
In MarkUp (preview, 3.0.0 via proxy)
Captures the spinning triangle normally. The fix is in 2.24.7, so
only develop's SDK (2.24.3) is affected.
Raw snapdom / SDK 2.24.3
Start a capture and switch tabs straight away: it doesn't finish
until you come back. The harness's
Capture in 3s button does this for you.
WebGL, preserveDrawingBuffer: false, redrawn every frame
+ pin here
B3
Blank web-font text on the first capture
Fixed in 3.1.1Broken in 3.0.0 and 3.1.0Chrome / Edge
In 3.0.0 and 3.1.0 on Chromium, snapdom draws into the canvas one
task before its embedded fonts finish loading, so web-font text
comes out invisible on the first capture. 2.24.3 doesn't have this
bug, but the preview runs 3.0.0. This font is used nowhere else on
the page.
In MarkUp (preview, 3.0.0 via proxy)
Reload the page and make this your first pin. In
Chrome or Edge the text may be missing. MarkUp runs its first
capture twice as a warm-up, which may hide it; that's worth
knowing either way.
Raw snapdom / SDK
3.0.0 in Chrome: the first capture after a reload may lose the
glyphs. 2.24.3 and 3.4.0: text renders.
The repro from #493: Google's Noto families, loaded with variable
weight ranges and picked per language with
:lang(). Up to 2.24.15 snapdom failed to embed them.
Weight 100 (thin) makes a fallback obvious.
In MarkUp (preview, 3.0.0 via proxy)
All five lines render in thin Noto. 3.0.0 includes the fix.
Raw snapdom / SDK 2.24.3
The four CJK lines disappear completely and the English line falls
back to Courier. In a local run the capture also took about 16
seconds.
MarkUp's pin capture snapshots the whole page, then crops it. These
cases would slow down or interfere with every other capture, so each one
has its own page.
About 3,000 rows plus one element 40,000px tall. Locally, a viewport
capture of the whole page took about 0.2s, so size alone may not
slow pins much. Picking the giant element hits the browser's
32,767px canvas limit, so it comes out shrunk.
A customer page with a
<meta> Content-Security-Policy. MarkUp's proxy
strips CSP headers but not meta tags, so its bundle or snapdom's
fetches may be blocked. The result is unknown; that's the
experiment.
snapdom 3 reuses earlier captures when the DOM hasn't changed. This
box changes colour through insertRule alone, so a
second capture could come back stale. In local runs it didn't, in
any version; this page checks MarkUp behaves the same.