Skip to content

Commit 35a6953

Browse files
actions-userclaude
andcommitted
fix: preserve repeating-linear-gradient through cssText round-trip
When cloneCSSStyle copies styles via the cssText path (Firefox / Safari), the browser's shorthand serialiser can normalise gradient stop-positions to 0 % / 100 %, making a repeating-linear-gradient render identically to a plain linear-gradient in the exported image. Fix: after assigning cssText, explicitly re-apply background-image using getPropertyValue, which returns the exact computed value and bypasses the shorthand serialiser. Closes #571 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 116ff7a commit 35a6953

File tree

4 files changed

+56
-0
lines changed

4 files changed

+56
-0
lines changed

src/clone-node.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,20 @@ function cloneCSSStyle<T extends HTMLElement>(
133133
if (sourceStyle.cssText) {
134134
targetStyle.cssText = sourceStyle.cssText
135135
targetStyle.transformOrigin = sourceStyle.transformOrigin
136+
// Re-apply background-image explicitly: some browsers normalise gradient
137+
// stop-positions when round-tripping through cssText serialisation, which
138+
// causes a repeating-linear-gradient to lose its repeating behaviour and
139+
// render identically to a plain linear-gradient. Fetching the value via
140+
// getPropertyValue bypasses the shorthand serialiser and returns the exact
141+
// computed value as the browser resolved it.
142+
const bgImage = sourceStyle.getPropertyValue('background-image')
143+
if (bgImage && bgImage !== 'none') {
144+
targetStyle.setProperty(
145+
'background-image',
146+
bgImage,
147+
sourceStyle.getPropertyPriority('background-image'),
148+
)
149+
}
136150
} else {
137151
getStyleProperties(options).forEach((name) => {
138152
let value = sourceStyle.getPropertyValue(name)
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<div
2+
id="gradient-box"
3+
class="gradient-box"
4+
style="width:200px;height:80px;"
5+
></div>
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/* Regression test for: repeating-linear-gradient treated as linear-gradient.
2+
* The gradient tile is 20px (0 → 10px → 20px), which creates a visible stripe
3+
* pattern. Without the fix the repeating- prefix may be lost during CSS cloning,
4+
* causing the gradient to stretch across the full element height instead. */
5+
.gradient-box {
6+
background-image: repeating-linear-gradient(
7+
to bottom,
8+
rgb(255, 0, 0) 0px,
9+
rgb(255, 0, 0) 10px,
10+
rgb(0, 0, 255) 10px,
11+
rgb(0, 0, 255) 20px
12+
);
13+
}

test/spec/svg.spec.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import '../spec/setup'
44
import { toSvg } from '../../src'
5+
import { cloneNode } from '../../src/clone-node'
56
import { bootstrap, renderAndCheck, getSvgDocument } from '../spec/helper'
67

78
describe('work with svg element', () => {
@@ -57,4 +58,27 @@ describe('work with svg element', () => {
5758
.then(done)
5859
.catch(done)
5960
})
61+
62+
it('should preserve repeating-linear-gradient in cloned element style', (done) => {
63+
// Regression test for: repeating-linear-gradient treated as linear-gradient.
64+
// The cssText serialisation path (Firefox/Safari) normalises gradient stop
65+
// positions to 0%/100%, making the gradient visually indistinguishable from
66+
// a plain linear-gradient. The fix explicitly re-applies background-image
67+
// via getPropertyValue after cssText assignment.
68+
bootstrap('repeating-gradient/node.html', 'repeating-gradient/style.css')
69+
.then((node) => cloneNode(node, {}, true))
70+
.then((clonedNode) => {
71+
expect(clonedNode).not.toBeNull()
72+
const box = clonedNode!.querySelector(
73+
'.gradient-box',
74+
) as HTMLElement | null
75+
expect(box).not.toBeNull()
76+
// The cloned element must have an inline background-image that preserves
77+
// the repeating-linear-gradient function name (not normalised away).
78+
const bgImage = box!.style.backgroundImage
79+
expect(bgImage).toContain('repeating-linear-gradient')
80+
})
81+
.then(done)
82+
.catch(done)
83+
})
6084
})

0 commit comments

Comments
 (0)