Skip to content

Commit 9c49d6a

Browse files
committed
fix(capture): disable WebKit text autosizer inside foreignObject. See #327
1 parent f35d24d commit 9c49d6a

2 files changed

Lines changed: 33 additions & 1 deletion

File tree

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { describe, it, expect } from 'vitest'
2+
import { snapdom } from '../src/api/snapdom.js'
3+
4+
// #327: iOS WebKit re-applies text-size-adjust when rasterizing the SVG,
5+
// inflating font-size inside the foreignObject while container heights
6+
// stay fixed. Emit `text-size-adjust: 100%` as a CSS rule in the SVG
7+
// <style> so it overrides the `all: initial` reset on the container.
8+
describe('capture — text-size-adjust in SVG output (#327)', () => {
9+
function svgFromDataURL(url) {
10+
const i = url.indexOf(',')
11+
return i >= 0 ? decodeURIComponent(url.slice(i + 1)) : ''
12+
}
13+
14+
it('emits text-size-adjust:100% with !important in the SVG style rule', async () => {
15+
const el = document.createElement('div')
16+
el.textContent = 'hi'
17+
el.style.cssText = 'width:80px;height:40px;font-size:14px'
18+
document.body.appendChild(el)
19+
const url = await snapdom.toRaw(el)
20+
document.body.removeChild(el)
21+
const svg = svgFromDataURL(url)
22+
// Must have both the -webkit- prefix (WebKit only accepts prefixed) and
23+
// the unprefixed standard name, both with !important to beat inline styles.
24+
expect(svg).toMatch(/-webkit-text-size-adjust\s*:\s*100%\s*!important/)
25+
expect(svg).toMatch(/[^-]text-size-adjust\s*:\s*100%\s*!important/)
26+
})
27+
})

src/core/capture.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -349,8 +349,13 @@ export async function captureDOM(element, options) {
349349

350350
const styleTag = document.createElement('style')
351351
// #349/#351: handled per-element in inlineAllStyles (#406) instead of blanket foreignObject rules
352+
// #327: disable WebKit text autosizer inside the foreignObject. iOS WebKit re-applies
353+
// text-size-adjust during drawImage, inflating font-size while inlined container heights
354+
// stay fixed → text crowding. Rule form (not inline) because WebKit expands `all:initial`
355+
// on the container last and clobbers inline overrides. 100% (not `none`) preserves zoom.
352356
const foNormalize =
353-
'svg{overflow:visible;} foreignObject{overflow:visible;}'
357+
'svg{overflow:visible;} foreignObject{overflow:visible;} ' +
358+
'foreignObject>div{-webkit-text-size-adjust:100%!important;text-size-adjust:100%!important;}'
354359
styleTag.textContent =
355360
(state.scrollbarCSS || '') + state.baseCSS + state.fontsCSS + foNormalize + state.classCSS
356361
fo.appendChild(styleTag)

0 commit comments

Comments
 (0)