Skip to content

css() pools style declarations across the whole match set and writes the union to every element #77

Description

@jakejackson1

Guidelines

Description of the bug

css() reads the style attribute of every element in the match set into a single map, merges the new declarations into that one map, then writes the combined string back to all of them.

The result is cross-contamination: if two selected elements start with different inline styles, both end up carrying the union of the two. Setting one property on a set of elements silently rewrites unrelated properties on all of them.

Root cause

src/Helpers/QueryMutators.php:1039-1071$css is built once, outside any per-element loop, and attr() then applies the single result to the whole set:

// Get any existing CSS.
$css = [];
foreach ($this->matches as $match) {          // <-- accumulates across ALL matches
	$style = $match->getAttribute('style');
	if (! empty($style)) {
		$style_array = explode(';', $style);
		foreach ($style_array as $item) {
			...
			$css[$css_att] = trim($css_val);
		}
	}
}

...

$this->attr('style', $css_string);            // <-- one string, applied to ALL matches

Suggested fix

Move the read-merge-write cycle inside a per-element loop so each element's own style attribute is the basis for its own result.

Workaround

Apply css() to one element at a time when the selected elements do not already share an identical style.

QueryPath version

4.2.0 (also reproduces on main at bed5d2c)

PHP Version and environment (server type, cli provider etc., enclosing libraries and their respective versions)

PHP 8.3.16 CLI (macOS, Homebrew). Not PHP-8 specific — the cause is present on every supported version.

Minimal reproducible PHP+HTML snippet to replicate bug

<?php
require __DIR__ . '/vendor/autoload.php';

$qp = html5qp('<div><p style="color:red"/><p style="font-size:2px"/></div>', 'p');

$qp->css('margin', '0');

var_dump($qp->get(0)->getAttribute('style'));
var_dump($qp->get(1)->getAttribute('style'));

// Both print: 'color: red;font-size: 2px;margin: 0;'
// Expected:   'color: red;margin: 0;'  and  'font-size: 2px;margin: 0;'

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions