From 19eb962a9a3f2d1bb928263e06b3fc107ab328d5 Mon Sep 17 00:00:00 2001 From: chenyang Date: Sun, 5 Jul 2026 21:39:15 +0800 Subject: [PATCH 1/2] fix: reading an unset style property returns "" per CSSOM, not undefined MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reading a property that is not set — via `el.style.someProp` or `el.style.getPropertyValue("some-prop")` — returned undefined, but CSSOM defines both as the empty string (the property getter is routed through the same handler as getPropertyValue). Callers that assume the spec, e.g. `el.style.color.replaceAll(...)`, crash on the undefined. Normalize an absent property to "" in the style getter. Co-Authored-By: Claude Opus 4.8 (1M context) --- cjs/interface/css-style-declaration.js | 5 ++++- esm/interface/css-style-declaration.js | 5 ++++- test/interface/css-style-declaration.js | 4 ++++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/cjs/interface/css-style-declaration.js b/cjs/interface/css-style-declaration.js index 726ab982..217f92ea 100644 --- a/cjs/interface/css-style-declaration.js +++ b/cjs/interface/css-style-declaration.js @@ -36,7 +36,10 @@ const handler = { return getKeys(style).length; if (/^\d+$/.test(name)) return getKeys(style)[name]; - return style.get(uhyphen(name)); + // Per CSSOM, reading a property that is not set returns the empty string, + // not undefined (which also matches getPropertyValue, routed here). + const value = style.get(uhyphen(name)); + return value === void 0 ? '' : value; }, set(style, name, value) { diff --git a/esm/interface/css-style-declaration.js b/esm/interface/css-style-declaration.js index 7b8de0ac..89fc7801 100644 --- a/esm/interface/css-style-declaration.js +++ b/esm/interface/css-style-declaration.js @@ -35,7 +35,10 @@ const handler = { return getKeys(style).length; if (/^\d+$/.test(name)) return getKeys(style)[name]; - return style.get(uhyphen(name)); + // Per CSSOM, reading a property that is not set returns the empty string, + // not undefined (which also matches getPropertyValue, routed here). + const value = style.get(uhyphen(name)); + return value === void 0 ? '' : value; }, set(style, name, value) { diff --git a/test/interface/css-style-declaration.js b/test/interface/css-style-declaration.js index 767863f9..baa5af2f 100644 --- a/test/interface/css-style-declaration.js +++ b/test/interface/css-style-declaration.js @@ -6,6 +6,10 @@ const {document} = parseHTML(''); let node = document.createElement('div'); assert(node.style.cssText, '', 'empty style'); +// Per CSSOM, an unset property reads as the empty string, not undefined — +// matching getPropertyValue, which is routed through the same getter. +assert(node.style.color, '', 'unset property getter returns ""'); +assert(node.style.getPropertyValue('color'), '', 'unset getPropertyValue returns ""'); node.style.cssText = 'background-color: blue; background-image: url("https://t.co/i.png");'; assert(node.style.backgroundColor, 'blue', 'style getter'); assert(node.style.backgroundImage, 'url("https://t.co/i.png")', 'style value with colon'); From e1dd1da5d607ea2cf0ff7da746bd6314775386dc Mon Sep 17 00:00:00 2001 From: chenyang Date: Wed, 8 Jul 2026 01:12:43 +0800 Subject: [PATCH 2/2] Apply CSSStyleDeclaration review suggestion --- cjs/interface/css-style-declaration.js | 5 +---- esm/interface/css-style-declaration.js | 5 +---- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/cjs/interface/css-style-declaration.js b/cjs/interface/css-style-declaration.js index 217f92ea..845be4d9 100644 --- a/cjs/interface/css-style-declaration.js +++ b/cjs/interface/css-style-declaration.js @@ -36,10 +36,7 @@ const handler = { return getKeys(style).length; if (/^\d+$/.test(name)) return getKeys(style)[name]; - // Per CSSOM, reading a property that is not set returns the empty string, - // not undefined (which also matches getPropertyValue, routed here). - const value = style.get(uhyphen(name)); - return value === void 0 ? '' : value; + return style.get(uhyphen(name)) ?? ''; }, set(style, name, value) { diff --git a/esm/interface/css-style-declaration.js b/esm/interface/css-style-declaration.js index 89fc7801..deb8b59a 100644 --- a/esm/interface/css-style-declaration.js +++ b/esm/interface/css-style-declaration.js @@ -35,10 +35,7 @@ const handler = { return getKeys(style).length; if (/^\d+$/.test(name)) return getKeys(style)[name]; - // Per CSSOM, reading a property that is not set returns the empty string, - // not undefined (which also matches getPropertyValue, routed here). - const value = style.get(uhyphen(name)); - return value === void 0 ? '' : value; + return style.get(uhyphen(name)) ?? ''; }, set(style, name, value) {