Where in the CSS specs does it say how multiple properties with the same name should be handled?

Viewed 89

In debugging another issue, I'd like to confirm I've correctly understood how a browser should handle a declaration like

background-image: url(image0.jpg);
background-image: image-set(url(image1.jpg) 1x, url(image2.jpg) 2x);

I've poked around in the specs a little but couldn't find it.

My impression from testing it out is that browsers will go with the first declaration they consider valid, but I would like to confirm this with a source. Note that I'm not (just) asking what the correct behaviour is – I'm specifically looking for an authoritative source, ideally a spec.

3 Answers

To answer my own question – I realised I should probably look for the answers to the two sub-questions "which out of two declarations wins" and "what should it do about invalid declarations".

For the former, https://www.w3.org/TR/css-cascade-3/#cascade-order says

The last declaration in document order wins.

which I take to mean that out of two property-value declarations with the same property, the last one wins.

And for the latter, https://www.w3.org/TR/css-cascade-3/#w3c-partial says

user agents must not selectively ignore unsupported component values and honor supported values in a single multi-value property declaration: if any value is considered invalid (as unsupported values must be), CSS requires that the entire declaration be ignored.

which I take to mean that if a browser e.g. doesn't support image-set in the question's example, it will ignore that entire declaration.

From the specification:

The final value of a CSS property for a given element or box is the result of a multi-step calculation:

  1. First, all the declared values applied to an element are collected, for each property on each element. There may be zero or many declared values applied to the element.
  2. Cascading yields the cascaded value. There is at most one cascaded value per property per element.

And

Each property declaration applied to an element contributes a declared value for that property associated with the element. See Filtering Declarations for details. ref

Following the Filtering Declarations:

In order to find the declared values, implementations must first identify all declarations that apply to each element. A declaration applies to an element if:

  • It belongs to a style sheet that currently applies to this document.
  • It is not qualified by a conditional rule [CSS3-CONDITIONAL] with a false condition.
  • It belongs to a style rule whose selector matches the element. [SELECT]
  • It is syntactically valid: the declaration’s property is a known property name, and the declaration’s value matches the syntax for that property.

The values of the declarations that apply form, for each property on each element, a list of declared values. The next section, the cascade, prioritizes these lists.

For the cascade:

The cascade takes an unordered list of declared values for a given property on a given element, sorts them by their declaration’s precedence as determined below, and outputs a single cascaded value.

I guess you know what happen with the cascade (specificity, order, etc) so in your case the last property will win if it's valid. If not, the first one if it's valid. If not the default value will be used.

Just answering the why here.
The logic behind that is the same one as behind any variable mutation in other programs. With the subtlety that invalid properties won't be re-assigned, because css is made to be resilient.

Related