Re: [svgwg] SVGAnimatedLength initial value for `fx` and `fy` (#1054)

Being naïve on purpose.
Reading step by step, the issue:

Differences of implementations:
<img width="1044" height="697" alt="Image" src="https://github.com/user-attachments/assets/370f3fb9-57cf-4f68-833f-cede07cfa899" />

Gecko, Blink return the same results.

Safari already does the right thing according to STP 235 for **missing values**, but maybe I'm missing some cases. 
https://codepen.io/webcompat/pen/GgZQMgZ
This renders the same everywhere. 

<img width="3162" height="753" alt="Image" src="https://github.com/user-attachments/assets/946e9593-e61a-44dd-a5a5-cde7fe094f5c" />

The WPT tests are failing with `expected "50%" but got "0"`

* SVGAnimatedLength, initial values, SVGRadialGradientElement.prototype.fx (remove) 
* SVGAnimatedLength, initial values, SVGRadialGradientElement.prototype.fx (invalid value)
* SVGAnimatedLength, initial values, SVGRadialGradientElement.prototype.fy (remove)
* SVGAnimatedLength, initial values, SVGRadialGradientElement.prototype.fy (invalid value)


This is **only for SVGRadialGradientElement**.


https://github.com/web-platform-tests/wpt/blob/17ed18c17ad38f84d48f327dd4103b9b4271b732/svg/types/scripted/support/initial-value-helper.js


The code does:

```
        e.removeAttribute(content_attribute);
        assert_equals(getValue(e[attribute].baseVal), initial, 'initial after');
```

and 

```
        e.setAttribute(content_attribute, 'foobar');
        assert_equals(getValue(e[attribute].baseVal), initial, 'initial after');
```

why would it work for other properties, but radialGradient?

Oh it fails even before. 

```
let e = document.createElementNS('http://www.w3.org/2000/svg', objects[info.interface]);
let initial = info[attribute] && info[attribute].initial || config.initial;
let valid = info[attribute] && info[attribute].valid || config.valid;
assert_equals(getValue(e[attribute].baseVal), initial, 'initial before');
```

At the moment the element is created `fx` and `fy` do not have a default value of `50%` as expected.
even before removing or trying to set an invalid value. 

## The spec:

1. If attribute ‘[fx](https://svgwg.org/svg2-draft/pservers.html#RadialGradientElementFXAttribute)’ is not specified, ‘[fx](https://svgwg.org/svg2-draft/pservers.html#RadialGradientElementFXAttribute)’ will coincide with the presentational value of ‘[cx](https://svgwg.org/svg2-draft/pservers.html#RadialGradientElementCXAttribute)’ for the element whether the value for 'cx' was inherited or not. ✅  
2. If the element references an element that specifies a value for 'fx', then the value of 'fx' is inherited from the referenced element. ✅ 

Basically, it says go see `cx` definition.

Let's modify the WPT to make it more obvious

```
let e = document.createElementNS(
  "http://www.w3.org/2000/svg",
  objects[info.interface],
);
let initial = (info[attribute] && info[attribute].initial) || config.initial;
let valid = (info[attribute] && info[attribute].valid) || config.valid;
if (
  e.nodeName === "radialGradient" &&
  (content_attribute === "fx" || content_attribute === "fy")
) {
  console.log("TEST: -------- BEFORE  --------------------");
  console.log("e: " + e.nodeName);
  console.log("content_attribute: " + content_attribute);
  console.log("e[attribute]: " + e[attribute]);
  console.log("e[attribute].baseVal: " + e[attribute].baseVal);
  console.log(
    "getValue(e[attribute].baseVal): " + getValue(e[attribute].baseVal),
  );
  console.log("initial: " + initial);
  console.log("VALUE OF CX: " + getValue(e["cx"].baseVal));
  console.log("VALUE OF CY: " + getValue(e["cy"].baseVal));
  console.log("TEST: ---------END BEFORE -------------------");
  assert_equals(getValue(e[attribute].baseVal), initial, "initial before");
  e.setAttribute(content_attribute, valid);
  assert_not_equals(getValue(e[attribute].baseVal), initial, "new value");
  e.removeAttribute(content_attribute);
  assert_equals(getValue(e[attribute].baseVal), initial, "initial after");
}
```

And run the test again:

```
[Log] TEST: -------- BEFORE  -------------------- (initial-value-helper.js, line 53)
[Log] e: radialGradient (initial-value-helper.js, line 54)
[Log] content_attribute: fx (initial-value-helper.js, line 55)
[Log] e[attribute]: [object SVGAnimatedLength] (initial-value-helper.js, line 56)
[Log] e[attribute].baseVal: [object SVGLength] (initial-value-helper.js, line 57)
[Log] getValue(e[attribute].baseVal): 0 (initial-value-helper.js, line 58)
[Log] initial: 50% (initial-value-helper.js, line 59)
[Log] VALUE OF CX: 50% (initial-value-helper.js, line 60)
[Log] VALUE OF CY: 50% (initial-value-helper.js, line 61)
[Log] TEST: ---------END BEFORE ------------------- (initial-value-helper.js, line 62)
[Log] TEST: -------- BEFORE  -------------------- (initial-value-helper.js, line 53)
[Log] e: radialGradient (initial-value-helper.js, line 54)
[Log] content_attribute: fy (initial-value-helper.js, line 55)
[Log] e[attribute]: [object SVGAnimatedLength] (initial-value-helper.js, line 56)
[Log] e[attribute].baseVal: [object SVGLength] (initial-value-helper.js, line 57)
[Log] getValue(e[attribute].baseVal): 0 (initial-value-helper.js, line 58)
[Log] initial: 50% (initial-value-helper.js, line 59)
[Log] VALUE OF CX: 50% (initial-value-helper.js, line 60)
[Log] VALUE OF CY: 50% (initial-value-helper.js, line 61)
[Log] TEST: ---------END BEFORE ------------------- (initial-value-helper.js, line 62)
```

The value of cx and cy are '50%', each so the initial value of `fx` and `fy` should be 50%.


So the spec says the correct thing.

Note that **when `cx` value is NOT defined explicitly** or the attribute is missing, its default value **per spec** is `50%`. 




-- 
GitHub Notification of comment by karlcow
Please view or discuss this issue at https://github.com/w3c/svgwg/issues/1054#issuecomment-3767221527 using your GitHub account


-- 
Sent via github-notify-ml as configured in https://github.com/w3c/github-notify-ml-config

Received on Monday, 19 January 2026 09:06:15 UTC