Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions src/clone-node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,20 @@ function cloneCSSStyle<T extends HTMLElement>(
if (sourceStyle.cssText) {
targetStyle.cssText = sourceStyle.cssText
targetStyle.transformOrigin = sourceStyle.transformOrigin
// Re-apply background-image explicitly: some browsers normalise gradient
// stop-positions when round-tripping through cssText serialisation, which
// causes a repeating-linear-gradient to lose its repeating behaviour and
// render identically to a plain linear-gradient. Fetching the value via
// getPropertyValue bypasses the shorthand serialiser and returns the exact
// computed value as the browser resolved it.
const bgImage = sourceStyle.getPropertyValue('background-image')
if (bgImage && bgImage !== 'none') {
targetStyle.setProperty(
'background-image',
bgImage,
sourceStyle.getPropertyPriority('background-image'),
)
}
} else {
getStyleProperties(options).forEach((name) => {
let value = sourceStyle.getPropertyValue(name)
Expand Down
5 changes: 5 additions & 0 deletions test/resources/repeating-gradient/node.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<div
id="gradient-box"
class="gradient-box"
style="width:200px;height:80px;"
></div>
13 changes: 13 additions & 0 deletions test/resources/repeating-gradient/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/* Regression test for: repeating-linear-gradient treated as linear-gradient.
* The gradient tile is 20px (0 → 10px → 20px), which creates a visible stripe
* pattern. Without the fix the repeating- prefix may be lost during CSS cloning,
* causing the gradient to stretch across the full element height instead. */
.gradient-box {
background-image: repeating-linear-gradient(
to bottom,
rgb(255, 0, 0) 0px,
rgb(255, 0, 0) 10px,
rgb(0, 0, 255) 10px,
rgb(0, 0, 255) 20px
);
}
24 changes: 24 additions & 0 deletions test/spec/svg.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import '../spec/setup'
import { toSvg } from '../../src'
import { cloneNode } from '../../src/clone-node'
import { bootstrap, renderAndCheck, getSvgDocument } from '../spec/helper'

describe('work with svg element', () => {
Expand Down Expand Up @@ -57,4 +58,27 @@ describe('work with svg element', () => {
.then(done)
.catch(done)
})

it('should preserve repeating-linear-gradient in cloned element style', (done) => {
// Regression test for: repeating-linear-gradient treated as linear-gradient.
// The cssText serialisation path (Firefox/Safari) normalises gradient stop
// positions to 0%/100%, making the gradient visually indistinguishable from
// a plain linear-gradient. The fix explicitly re-applies background-image
// via getPropertyValue after cssText assignment.
bootstrap('repeating-gradient/node.html', 'repeating-gradient/style.css')
.then((node) => cloneNode(node, {}, true))
.then((clonedNode) => {
expect(clonedNode).not.toBeNull()
const box = clonedNode!.querySelector(
'.gradient-box',
) as HTMLElement | null
expect(box).not.toBeNull()
// The cloned element must have an inline background-image that preserves
// the repeating-linear-gradient function name (not normalised away).
const bgImage = box!.style.backgroundImage
expect(bgImage).toContain('repeating-linear-gradient')
})
.then(done)
.catch(done)
})
})
Loading