blitz-dom: no CSSOM inline-style edit keeps both the value and the style attribute
Generated from repros/blitz-dom-cssom-inline-style-round-trip/README.md when the site was built at 7aa23e2.
What niso does
Section titled “What niso does”niso implements element.style (setProperty, removeProperty, cssText and the
property setters) on top of blitz-dom. Until cssom-inline-style it used blitz’s
string API, BaseDocument::style_attr_set_property, and set the result as the
style attribute, which blitz parses back. The serialization rounds numbers to
six significant digits, so what the page set is not what cascades. WPT’s
interpolation harness sets cubic-bezier(0, 0.23333333333333334, 1, 0.23333333333333334) to sample a transition at progress 0.3; after the round
trip the curve is cubic-bezier(0, 0.233333, 1, 0.233333), the output is
0.29999975, and 15 subtests in css/css-ui/animation/caret-color-interpolation.html,
css/css-transitions/animations/text-shadow-interpolation.html and
css/css-transforms/animation/transform-interpolation-005.html got
rgb(76, 49, 0) for rgb(77, 50, 0) and matrix3d values just off.
niso now keeps the parsed block itself (crates/niso-core/src/inline_style.rs):
it edits the block with Stylo’s prepare_for_update/update, installs it as the
element’s style_attribute, and writes the serialization into
ElementData::attrs directly. To keep blitz’s restyle and selector
invalidation for the change it first calls set_attribute(style, ""), which
blitz parses (cheaply) before niso replaces both the attribute value and the block.
Expected vs actual
Section titled “Expected vs actual”CSSOM (“update style attribute for”, CSSOM §6.7) sets the attribute to the declarations’ serialization without reparsing it: the declaration block keeps the values as parsed, and the attribute holds their serialization. blitz-dom offers two ways to edit inline style, and neither does both:
style_attr_set_property+set_attribute: the attribute is right, but blitz reparses it (DocumentMutator::set_attribute→ElementData::flush_style_attribute), so the cascade sees the rounded serialization.set_style_property(DocumentMutator,BaseDocument,ElementData): the block keeps the value, but thestyleattribute is not updated at all, sogetAttribute('style'), attribute selectors and serialization go stale.
style.transitionTimingFunction = 'cubic-bezier(0, 0.23333333333333334, 1, 0.23333333333333334)', eased at 0.5 (0.3 expected):style_attr_set_property + set_attribute: 0.299999755, attribute "transition-timing-function: cubic-bezier(0, 0.233333, 1, 0.233333);"set_style_property: 0.300000001, attribute NoneCARGO_TARGET_DIR=~/.capy/work/repro-target cargo runExit status 1 while neither API keeps both, 0 once one does. On Ubuntu, blitz needs
sudo apt-get install -y libfontconfig-dev pkg-config.
Upstream main
Section titled “Upstream main”Same code on DioxusLabs/blitz main at 808ded9348289cac0a3b4940e69da21d5b918443
(2026-11-09): style_attr_set_property (packages/blitz-dom/src/resolved_style.rs:225)
still returns only a string, set_attribute still reparses a style attribute
(packages/blitz-dom/src/mutator.rs:412), and ElementData::set_style_property
(packages/blitz-dom/src/node/element.rs:713) still leaves attrs alone. Not run
against main itself.
Existing issue or PR
Section titled “Existing issue or PR”None found in DioxusLabs/blitz issues or PRs for “style attribute”, “setProperty”, “CSSOM” or “style_attr_set_property”.
Issue text
Section titled “Issue text”Title: No inline-style edit keeps both the parsed value and the style attribute
Body:
To implement element.style, an embedder needs CSSOM’s “update style attribute”:
the element’s declaration block changes, and the style attribute becomes its
serialization without being parsed back. blitz-dom has two ways in, and each
keeps only half:
BaseDocument::style_attr_set_propertyreturns the new attribute string; setting it withDocumentMutator::set_attributereparses it, and the serialization rounds numbers to six significant digits.cubic-bezier(0, 0.23333333333333334, 1, 0.23333333333333334)cascades ascubic-bezier(0, 0.233333, 1, 0.233333), so the curve gives 0.29999975 at 0.5 instead of 0.3, and colors interpolated at that progress round down (WPT’s interpolation tests sample this way).DocumentMutator::set_style_propertykeeps the parsed value but never updates thestyleattribute, sogetAttribute('style'),[style]selectors and serialization see the old value.
Repro (blitz be60597; the same code is on main 808ded93):
let css = doc.style_attr_set_property("", "transition-timing-function", EASING, false).unwrap();doc.mutate().set_attribute(a, style, &css); // cascades 0.233333doc.mutate().set_style_property(b, "transition-timing-function", EASING);doc.get_node(b).unwrap().attr(local_name!("style")); // NoneSuggested fix: have set_style_property (or a new mutator method) also write the
block’s serialization into the style attribute, snapshotting for invalidation as
set_attribute does, without calling flush_style_attribute.