Skip to content

Commit 10bc2cd

Browse files
committed
fix(inline-css): stop reformatting inline style attributes
The post-process pass added a space after every `:` and `;`, which broke URLs in inline style values (`url('https://...')` → `url('https: //...')`) and forced visual consistency with Juice's spaced output that email clients don't care about. Dropped the colon/semicolon rewriting and the trailing-semicolon ensure; kept `preferUnitlessValues` (0px → 0) and gated its walk on the option being enabled.
1 parent 1d67243 commit 10bc2cd

2 files changed

Lines changed: 28 additions & 21 deletions

File tree

src/tests/transformers/inlineCss.test.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,4 +217,25 @@ describe('inlineCss', () => {
217217
expect(result).not.toContain('style=')
218218
})
219219
})
220+
221+
describe('pre-existing inline styles are passed through verbatim', () => {
222+
it('does not inject a space inside https:// in url()', () => {
223+
const html = `<div style="background-image:url('https://example.com/img.jpg')">x</div>`
224+
const result = run(html, true)
225+
expect(result).toContain("background-image:url('https://example.com/img.jpg')")
226+
expect(result).not.toContain('https: //')
227+
})
228+
229+
it('preserves data: URIs in url()', () => {
230+
const html = `<div style="background-image:url('data:image/png;base64,iVBORw0KG')">x</div>`
231+
const result = run(html, true)
232+
expect(result).toContain("background-image:url('data:image/png;base64,iVBORw0KG')")
233+
})
234+
235+
it('preserves URLs with query strings containing colons or ampersands', () => {
236+
const html = `<div style="background-image:url('https://cdn.example.com/img.jpg?expires=1700000000&sig=abc')">x</div>`
237+
const result = run(html, true)
238+
expect(result).toContain("url('https://cdn.example.com/img.jpg?expires=1700000000&sig=abc')")
239+
})
240+
})
220241
})

src/transformers/inlineCss.ts

Lines changed: 7 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -153,33 +153,19 @@ export function inlineCssDom(dom: ChildNode[], options: InlineCssOptions = {}):
153153
return dom
154154
}
155155

156-
// Post-process for preferUnitlessValues
157156
const result = parse(inlinedHtml)
158157

159-
walk(result, (node) => {
160-
const el = node as Element
161-
if (el.attribs?.style) {
162-
// Normalize style formatting: ensure spaces after : and ;
163-
let style = el.attribs.style
164-
.replace(/:\s*/g, ': ')
165-
.replace(/;\s*/g, '; ')
166-
.trimEnd()
167-
168-
// Ensure trailing semicolon
169-
if (!style.endsWith(';')) {
170-
style += ';'
171-
}
172-
173-
if (preferUnitlessValues) {
174-
style = style.replace(
158+
if (preferUnitlessValues) {
159+
walk(result, (node) => {
160+
const el = node as Element
161+
if (el.attribs?.style) {
162+
el.attribs.style = el.attribs.style.replace(
175163
/\b0(px|rem|em|%|vh|vw|vmin|vmax|in|cm|mm|pt|pc|ex|ch)\b/g,
176164
'0'
177165
)
178166
}
179-
180-
el.attribs.style = style
181-
}
182-
})
167+
})
168+
}
183169

184170
/**
185171
* Restore `embed` from our marker so the purge step can detect

0 commit comments

Comments
 (0)