Warhol

Specified vs. computed values


“Sometimes Warhol shows CSS values as they appear in my style sheets, but sometimes they show up in a different format. Colors get resolved to RGB, variables are replaced by concrete values… what is going on here?”

The short answer is that the “original values” from a stylesheet are not always knowable. This is not a huge problem and does not affect Warhol's ability to identify problems, but it does make its error messages less precise than we would like them to be. Unfortunatly there's nothing that we can do to change this.

Color formats

When Warhol processes a page, it uses a browser's DOM APIs to access style rules - be it for testing or for taking snapshots. Accessing style rules through browsers means that Warhol does in fact never interact with your original style sheets, but rather with a browser's interpretation of said style sheets. And the process of interpreting style sheets can be lossy! For example the color red in hexadecimal, #FF0000, is not only equivalent to rgb(255, 0, 0), but is automatically converted as soon as the browser parses the color. Run the following JavaScript snippet in your browser of choice to see this in action:

let style = document.createElement("style")
style.innerHTML = ".foo { color: #FF0000 }"
document.body.append(style)
window.alert(style.sheet.cssRules[0].style.color) // outputs "rgb(255, 255, 0)"

This does not happen with color keywords, als the next snippet demonstrates:

let style = document.createElement("style")
style.innerHTML = ".foo { color: red } .bar { color: hsl(0, 100%, 50%) }"
document.body.append(style)
window.alert(style.sheet.cssRules[0].style.color) // outputs "red"
window.alert(style.sheet.cssRules[0].style.color) // outputs "rgb(255, 255, 0)" again

A web browser's own developer tools do not have this problem, but for Warhol there is no way to access the original values and color formats. It is important to note that this does not in any way affect Warhol's error detection - for Warhol, red, rgb(255, 0, 0) and hsl(0, 100%, 50%) are all the same color. But when Warhol detects a wrong color and tries to tell you what was expected in place of the wrong color, it might not be able to use the same color format as the style sheets do.

CSS variables

Something similar happens with CSS variables in CSS shorthand properties. Sometimes Warhol will be able to tell you that a value was defined using a CSS variable (like var(--myColor)), but sometimes it will fall back to the computed value (eg. rgb(255, 0, 0)). This has to do with a litte-known implementation detail of CSS variables called pending-substitution values which arises from the fact that CSS variables can contain almost totally arbitrary content. Consider the following snippet:

body {
  --size: 2px;
}
.foo {
  border: var(--size) solid black;
}

It appears to be clear that the border-width was declared using the value var(--size) (which computes to 2px), so we would expect Warhol to be able to tell us so. But remember that the following snippet is also valid css:

body {
  --sizeAndStyle: 2px solid;
}
.foo {
  border: var(--sizeAndStyle) black;
}

In this case there is no single value that was used to declare the border-width! The values for both border-width and border-style come from the same CSS variable, but there is no single source for either of those properties. There are no distinguishable “original values” for either border-width or border-style.

CSS variables are much more simple than most people think - all they do is string concatenation. This makes them very user-friendly and powerful, but also means that any CSS variable in shorthand properties like border and background makes the “original values” the for shorthand properties's sub-components (like border-top-width or background-color) unknowable.

This, like the issue with color formats, does not in any way affect Warhol's error detection! Warhol uses computed values to perform comparisons and the original declared values are only used for error messages - if such “original values” are available. And for colors and CSS variables, they just sometimes are not.