Beating !important user agent styles (sort of)
I was recently asked to help debug an issue with autocomplete styles in <input> elements in Chrome. When Chrome autofills a form field, it sets the text and background color in that field.

The team didn’t want to override colors specified by the designer, so they needed a way to prevent these autocomplete styles from kicking in.
The Chrome user agent stylesheet includes the following:
input:-internal-autofill-previewed,
input:-internal-autofill-selected,
textarea:-internal-autofill-previewed,
textarea:-internal-autofill-selected,
select:-internal-autofill-previewed,
select:-internal-autofill-selected {
appearance: menulist-button;
background-image:none !important;
background-color: light-dark(#E8F0FE, rgba(70,90,126,0.4)) !important;
color: FieldText !important;
}
Uh oh: both background-color and color and specified with !important. This presents a challenge. Normally, the user agent stylesheet is first (lowest priority) in the cascade, so overriding it is easy. But !important reverses the precedence or stylesheet origins, making an !important declaration in the user agent stylesheet the absolute highest precedence. As Stefan Judis succinctly put it, You can’t override !important user agent CSS declarations.
So what could we do?

While running, CSS transitions take precedence over even !important declarations. Luckily for us in this case, the !important user agent style isn’t applied when the page loads; the browser applies these styles once a user autofills a value (resulting in the proprietary pseudoselector :-internal-autofill-selected matching). That means we can transition to those styles.
Since we want to prevent these !important styles from being applied, we can essentially do this by transitioning to those styles over a very long time. Like infinity long[1].
The behavior of an animation that’s infinitely long doesn’t seem to be particularly well defined (what’s 1% of the way to infinity?), so to make sure the destination colors never kick in (or, rather, don’t kick in until the “end” of the transition), we can add the step-end timing function.
input {
/* prevent anything that tries to change this from ever getting there */
transition:
color calc(infinity * 1s) step-end,
background-color calc(infinity * 1s) step-end;
/* style the field as normal */
background-color: transparent;
color: CanvasText;
}
So that’s it. When the user agent stylesheet tries to set the background and color values, it will transition to those colors over infinite time — so, never.
This seems to be 1.79769e+308 seconds for me. The universe is 4.348e+17 seconds old, and my uptime’s just not that good. ↩︎