In this article, we’ll be taking a look at the structure inside <input type='color'>
elements, browser inconsistencies, why they look a certain way in a certain browser, and how to dig into it. Having a good understanding of this input allows us to evaluate whether a certain cross-browser look can be achieved and how to do so with a minimum amount of effort and code.
Here’s exactly what we’re talking about:
But before we dive into this, we need to get into…
Accessibility issues!
We’ve got a huge problem here: for those who completely rely on a keyboard, this input doesn’t work as it should in Safari and in Firefox on Windows, but it does work in Firefox on Mac and Linux (which I only tested on Fedora, so feel free to yell at me in the comments if it doesn’t work for you using another distribution).
In Firefox on Windows, we can Tab to the input to focus it, press Enter to bring up a dialog… which we then cannot navigate with the keyboard!
I’ve tried tabbing, arrow keys, and every other key available on the keyboard… nothing! I could at least close the dialog with good old Alt + F4. Later, in the bug ticket I found for this on Bugzilla, I also discovered a workaround: Alt + Tab to another window, then Alt + Tab back and the picker dialog can be navigated with the keyboard.
Things are even worse in Safari. The input isn’t even focusable (bug ticket) if VoiceOver isn’t on. And even when using VoiceOver, tabbing through the dialog the inputs opens is impossible.
If you’d like to use <input type='color'>
on an actual website, please let browsers know this is something that needs to be solved!
How to look inside
In Chrome, we need to bring up DevTools, go to Settings and, in the Preferences section under Elements, check the Show user agent shadow DOM option.
Then, when we return to inspect our element, we can see inside its shadow DOM.
In Firefox, we need to go to about:config
and ensure the devtools.inspector.showAllAnonymousContent
flag is set to true
.
Then, we close the DevTools and, when we inspect our input again, we can see inside our input.
Sadly, we don’t seem to have an option for this in pre-Chromium Edge.
The structure inside
The structure revealed in DevTools differs from browser to browser, just like it does for range inputs.
In Chrome, at the top of the shadow DOM, we have a <div>
wrapper that we can access using ::-webkit-color-swatch-wrapper
.
Inside it, we have another <div>
we can access with ::-webkit-color-swatch
.
![Screenshot of Chrome DevTools showing the shadow DOM of the <input type='color' data-recalc-dims=](https://i0.wp.com/css-tricks.com/wp-content/uploads/2019/05/in_struct_chrome.png?ssl=1)
In Firefox, we only see one <div>
, but it’s not labeled in any way, so how do we access it?
On a hunch, given this <div>
has the background-color
set to the input’s value
attribute, just like the ::-webkit-color-swatch
component, I tried ::-moz-color-swatch
. And it turns out it works!
![Screenshot of Firefox DevTools showing what's inside an <input type='color' data-recalc-dims=](https://i0.wp.com/css-tricks.com/wp-content/uploads/2019/05/in_struct_firefox.png?ssl=1)
However, I later learned we have a better way of figuring this out for Firefox!
We can go into the Firefox DevTools Settings and, in the Inspector section, make sure the “Show Browser Styles” option is checked. Then, we go back to the Inspector and select this <div>
inside our <input type='color'>
. Among the user agent styles, we see a rule set for input[type='color']::-moz-color-swatch
!
![Animated gif. Shows how to enable viewing applied user agent styles in Firefox DevTools: Settings data-recalc-dims=](https://i0.wp.com/css-tricks.com/wp-content/uploads/2019/05/enable_ua_styles_firefox.gif?ssl=1)
In pre-Chromium Edge, we cannot even see what kind of structure we have inside. I gave ::-ms-color-swatch
a try, but it didn’t work and neither did ::-ms-swatch
(which I considered because, for an input type='range'
, we have ::-webkit-slider-thumb
and ::-moz-range thumb
, but just ::-ms-thumb
).
After a lot of searching, all I found was this issue from 2016. Pre-Chromium Edge apparently doesn’t allow us to style whatever is inside this input. Well, that’s a bummer.
How to look at the browser styles
In all browsers, we have the option of not applying any styles of our own and then looking at the computed styles.
In Chrome and Firefox, we can also see the user agent stylesheet rule sets that are affecting the currently selected element (though we need to explicitly enable this in Firefox, as seen in the previous section).
![Screenshot collage of Chrome DevTools and Firefox DevTools showing where to look for user agent styles: Elements data-recalc-dims=](https://i0.wp.com/css-tricks.com/wp-content/uploads/2019/05/view_ua_styles.png?ssl=1)
This is oftentimes more helpful than the computed styles, but there are exceptions and we should still always check the computed values as well.
In Firefox, we can also see the CSS file for the form
elements at view-source:resource://gre-resources/forms.css
.
![Screenshot showing view-source:resource://gre-resources/forms.css open in Firefox to allow us seeing user agent styles for form elements.](https://i0.wp.com/css-tricks.com/wp-content/uploads/2019/05/view_css_file_firefox.png?ssl=1)
The input element itself
We’ll now be taking a look at the default values of a few properties in various browsers in order to get a clear picture of what we’d really need to set explicitly in order to get a custom cross-browser result.
The first property I always think about checking when it comes to <input>
elements is box-sizing
. The initial value of this property is border-box
in Firefox, but content-box
in Chrome and Edge.
![Comparative screenshots of DevTools in the three browsers showing the computed values of box-sizing for the actual input.](https://i0.wp.com/css-tricks.com/wp-content/uploads/2019/05/default_l0_box.png?ssl=1)
box-sizing
values for <input type='color'>
compared in Chrome, Firefox and Edge (from top-to-bottom).We can see that Firefox is setting it to border-box
on <input type='color'>
, but it looks like Chrome isn’t setting it at all, so it’s left with the initial value of content-box
(and I suspect the same is true for Edge).
In any event, what it all means is that, if we are to have a border
or a padding
on this element, we also need to explicitly set box-sizing
so that we get a consistent result across all these browsers.
The font
property value is different for every browser, but since we don’t have text inside this input, all we really care about is the font-size
, which is consistent across all browsers I’ve checked: 13.33(33)px
. This is a value that really looks like it came from dividing 40px
by 3
, at least in Chrome.
![Comparative screenshots of DevTools in the three browsers showing the font values for the actual input.](https://i0.wp.com/css-tricks.com/wp-content/uploads/2019/05/default_l0_font.png?ssl=1)
font
values for <input type='color'>
compared in Chrome, Firefox and Edge (from top-to-bottom).This is a situation where the computed styles are more useful for Firefox, because if we look at the browser styles, we don’t get much in terms of useful information:
![Screenshot of what we get if we look at the browser styles where the font was set for Firefox. The value for the font is -moz-field, which is an alias for the look of a native text field. Expanding this to check the longhands shows us empty instead of actual values.](https://i0.wp.com/css-tricks.com/wp-content/uploads/2019/05/default_l0_font_useless_firefox.png?ssl=1)
The margin
is also consistent across all these browsers, computing to 0
.
![Comparative screenshots of DevTools in the three browsers showing the margin values for the actual input.](https://i0.wp.com/css-tricks.com/wp-content/uploads/2019/05/default_l0_margin.png?ssl=1)
margin
values for <input type='color'>
compared in Chrome, Firefox and Edge (from top-to-bottom).The border
is different for every single browser. In both Chrome and Edge, we have a solid 1px
one, but the border-color
is different (rgb(169, 169, 169)
for Chrome and rgb(112, 112, 112)
for Edge). In Firefox, the border
is an outset 2px
one, with a border-color
of… ThreeDLightShadow
?!
![Comparative screenshots of DevTools in the three browsers showing the border values for the actual input.](https://i0.wp.com/css-tricks.com/wp-content/uploads/2019/05/default_l0_border.png?ssl=1)
border
values for <input type='color'>
compared in Chrome, Firefox and Edge (from top-to-bottom).What’s the deal with ThreeDLightShadow
? If it doesn’t sound familiar, don’t worry! It’s a (now deprecated) CSS2 system value, which Firefox on Windows shows me to be rgb(227, 227, 227)
in the Computed styles tab.
![Screenshot of Computed panel search in Firefox on Windows, showing that the ThreeDLightShadow keyword computes to rgb(227, 227, 227).](https://i0.wp.com/css-tricks.com/wp-content/uploads/2019/05/default_l0_border_color_firefox_comp.png?ssl=1)
border-color
for <input type='color'>
in Firefox on Windows.Note that in Firefox (at least on Windows), the operating system zoom level (Settings → System → Display → Scale and Layout → Change the size of text, apps and other items) is going to influence the computed value of the border-width
, even though this doesn’t seem to happen for any other property I’ve checked and it seems to be partially related to the border-style
.
![Screenshot showing the Windows display settings window with the zoom level options dropdown opened.](https://i0.wp.com/css-tricks.com/wp-content/uploads/2019/05/win_zoom.png?ssl=1)
The strangest thing is the computed border-width
values for various zoom levels don’t seem to make any sense. If we keep the initial border-style: outset
, we have:
1.6px
for125%
2px
for150%
1.7px
for175%
1.5px
for200%
1.8px
for225%
1.6px
for250%
1.66667px
for300%
If we set border-style: solid
, we have a computed border-width
of 2px
, exactly as it was set, for zoom values that are multiples of 50%
and the exact same computed values as for border-style: outset
for all the other zoom levels.
The padding
is the same for Chrome and Edge (1px 2px
), while Firefox is the odd one out again.
![Comparative screenshots of DevTools in the three browsers showing the padding values for the actual input.](https://i0.wp.com/css-tricks.com/wp-content/uploads/2019/05/default_l0_padding.png?ssl=1)
padding
values for <input type='color'>
compared in Chrome, Firefox and Edge (from top-to-bottom).It may look like the Firefox padding
is 1px
. That’s what it is set to and there’s no indication of anything overriding it — if a property is overridden, then it’s shown as grey and with a strike-through.
![Screenshot of Firefox DevTools highlighting how the border set on input[type='color'] overrides the one set on input and the look (grey + strike-through) of overridden properties.](https://i0.wp.com/css-tricks.com/wp-content/uploads/2019/05/override_firefox.png?ssl=1)
But the computed value is actually 0 8px
! Moreover, this is a value that doesn’t depend on the operating system zoom level. So, what the hairy heck is going on?!
![Screenshot of Firefox DevTools showing how the computed padding value on <input type='color' data-recalc-dims=](https://i0.wp.com/css-tricks.com/wp-content/uploads/2019/05/default_l0_padding_comp_firefox.png?ssl=1)
padding
in Firefox doesn’t match the value that was set on input.Now, if you’ve actually tried inspecting a color input, took a close look at the styles set on it, and your brain works differently than mine (meaning you do read what’s in front of you and don’t just scan for the one thing that interests you, completely ignoring everything else…) then you’ve probably noticed there is something overriding the 1px
padding (and should be marked as such) — the flow-relative padding!
![Screenshot of Firefox DevTools showing the flow-relative padding overriding the old padding due to higher specificity of selector (input[type='color'] vs. input).](https://i0.wp.com/css-tricks.com/wp-content/uploads/2019/05/default_l0_padding_firefox.png?ssl=1)
padding
overrides in Firefox.Dang, who knew those properties with lots of letters were actually relevant? Thanks to Zoltan for noticing and letting me know. Otherwise, it probably would have taken me two more days to figure this one out.
This raises the question of whether the same kind of override couldn’t happen in other browsers and/or for other properties.
Edge doesn’t support CSS logical properties, so the answer is a “no” in that corner.
In Chrome, none of the logical properties for margin
, border
or padding
are set explicitly for <input type='color'>
, so we have no override.
Concerning other properties in Firefox, we could have found ourselves in the same situation for margin
or for border
, but with these two, it just so happens the flow-relative properties haven’t been explicitly set for our input, so again, there’s no override.
Even so, it’s definitely something to watch out for in the future!
Moving on to dimensions, our input’s width
is 44px
in Chrome and Edge and 64px
in Firefox.
![Comparative screenshots of DevTools in the three browsers showing the width values for the actual input.](https://i0.wp.com/css-tricks.com/wp-content/uploads/2019/05/default_l0_dim_w.png?ssl=1)
width
values for <input type='color'>
compared in Chrome, Firefox and Edge (from top-to-bottom).Its height
is 23px
in all three browsers.
![Comparative screenshots of DevTools in the three browsers showing the height values for the actual input.](https://i0.wp.com/css-tricks.com/wp-content/uploads/2019/05/default_l0_dim_h.png?ssl=1)
height
values for <input type='color'>
compared in Chrome, Firefox and Edge (from top-to-bottom).Note that, since Chrome and Edge have a box-sizing
of content-box
, their width
and height
values do not include the padding
or border
. However, since Firefox has box-sizing
set to border-box
, its dimensions include the padding
and border
.
![Comparative screenshots of DevTools in the three browsers showing the layout boxes.](https://i0.wp.com/css-tricks.com/wp-content/uploads/2019/05/boxes_comp.png?ssl=1)
<input type='color'>
compared in Chrome, Firefox and Edge (from top-to-bottom).This means the content-box
is 44px
x23px
in Chrome and Edge and 44xpx
x19px
in Firefox, the padding-box
is 48px
x25
in Chrome and Edge and 60px
x19px
in Firefox and the border-box
is 50px
x27px
in Chrome and Edge and 64px
x23
in Firefox.
We can clearly see how the dimensions were set in Chrome and I’d assume they were set in the same direct way in Edge as well, even if Edge doesn’t allow us to trace this stuff. Firefox doesn’t show these dimensions as having been explicitly set and doesn’t even allow us to trace where they came from in the Computed tab (as it does for other properties like border
, for example). But if we look at all the styles that have been set on input[type='color']
, we discover the dimensions have been set as flow-relative ones (inline-size
and block-size
).
![Screenshot of the Firefox user agent styles showing flow relative dimensions being set on input[type='color'].](https://i0.wp.com/css-tricks.com/wp-content/uploads/2019/05/default_l0_dim_firefox_logical.png?ssl=1)
<input type='color'>
dimensions have been set in Firefox.The final property we check for the normal state of the actual input is background
. Here, Edge is the only browser to have a background-image
(set to a top to bottom gradient), while Chrome and Firefox both have a background-color
set to ButtonFace
(another deprecated CSS2 system value). The strange thing is this should be rgb(240, 240, 240)
(according to this resource), but its computed value in Chrome is rgb(221, 221, 221)
.
![Comparative screenshots of DevTools in the three browsers showing the background values for the actual input.](https://i0.wp.com/css-tricks.com/wp-content/uploads/2019/05/default_l0_background.png?ssl=1)
background
values for <input type='color'>
compared in Chrome, Firefox and Edge (from top-to-bottom).What’s even stranger is that, if we actually look at our input in Chrome, it sure does look like it has a gradient background
! If we screenshot it and then use a picker, we get that it has a top to bottom gradient from #f8f8f8
to #ddd
.
![Screenshot of the input in Chrome. A very light, almost white, grey to another light, but still darker grey gradient from top to bottom can be seen as the background, not the solid background-color indicated by DevTools.](https://i0.wp.com/css-tricks.com/wp-content/uploads/2019/06/look_chrome_normal.png?ssl=1)
Also, note that changing just the background-color
(or another property not related to dimensions like border-radius
) in Edge also changes the background-image
, background-origin
, border-color
or border-style
.
![Animated gif. Shows the background-image, background-origin, border-color, border-style before and after changing the seemingly unrelated background-color - their values don't get preserved following this change.](https://i0.wp.com/css-tricks.com/wp-content/uploads/2019/05/input_bg_border_edge_wtf.gif?ssl=1)
background-color
.Other states
We can take a look at the styles applied for a bunch of other states of an element by clicking the :hov
button in the Styles
panel for Chrome and Firefox and the a:
button in the same Styles
panel for Edge. This reveals a section where we can check the desired state(s).
![Screenshot collage highlighting the buttons that bring up the states panel in Chrome, Firefox and Edge.](https://i0.wp.com/css-tricks.com/wp-content/uploads/2019/05/state_toggle.png?ssl=1)
Note that, in Firefox, checking a class only visually applies the user styles on the selected element, not the browser styles. So, if we check :hover
for example, we won’t see the :hover
styles applied on our element. We can however see the user agent styles matching the selected state for our selected element shown in DevTools.
Also, we cannot test for all states like this and let’s start with such a state.
:disabled
In order to see how styles change in this state, we need to manually add the disabled
attribute to our <input type='color'>
element.
Hmm… not much changes in any browser!
In Chrome, we see the background-color
is slightly different (rgb(235, 235, 228)
in the :disabled
state versus rgb(221, 221, 221)
in the normal state).
![Chrome DevTools screenshot showing the background being set to rgb(235, 235, 228) for a :disabled input.](https://i0.wp.com/css-tricks.com/wp-content/uploads/2019/06/default_state_disabled_chrome.png?ssl=1)
:disabled
styling.But the difference is only clear looking at the info in DevTools. Visually, I can tell tell there’s a slight difference between an input that’s :disabled
and one that’s not if they’re side-by-side, but if I didn’t know beforehand, I couldn’t tell which is which just by looking at them, and if I just saw one, I couldn’t tell whether it’s enabled or not without clicking it.
![Disabled and enabled input side by side in Chrome. There is a slight difference in background-color, but it's pretty much impossible to tell which is which just by looking at them.](https://i0.wp.com/css-tricks.com/wp-content/uploads/2019/05/input_disabled_chrome_vis.png?ssl=1)
<input type='color'>
in Chrome.In Firefox, we have the exact same values set for the :disabled
state as for the normal state (well, except for the cursor, which realistically, isn’t going to produce different results save for exceptional cases anyway). What gives, Firefox?!
![Comparison of styles set in Firefox for <input type='color' data-recalc-dims=](https://i0.wp.com/css-tricks.com/wp-content/uploads/2019/05/default_state_disabled_firefox.png?ssl=1)
:disabled
(top) versus normal (bottom) styling.In Edge, both the border-color
and the background
gradient are different.
![Chrome DevTools screenshot showing border-color and the background-image being set to slightly different values for a :disabled input.](https://i0.wp.com/css-tricks.com/wp-content/uploads/2019/06/default_state_disabled_edge-1.png?ssl=1)
:disabled
styling (by checking computed styles).We have the following styles for the normal state:
border-color: rgb(112, 112, 112);
background-image: linear-gradient(rgb(236, 236, 236), rgb(213, 213, 213));
And for the :disabled
state:
border-color: rgb(186, 186, 186);
background-image: linear-gradient(rgb(237, 237, 237), rgb(229, 229, 229));
Clearly different if we look at the code and visually better than Chrome, though it still may not be quite enough:
![Disabled and enabled input side by side in Edge. There is a slight difference in background-image and a bigger difference in border-color, but it still may be difficult to tell whether an input is enabled or not at first sight without having a reference to compare.](https://i0.wp.com/css-tricks.com/wp-content/uploads/2019/05/input_disabled_edge_vis.png?ssl=1)
<input type='color'>
in Edge.:focus
This is one state we can test by toggling the DevTools pseudo-classes. Well, in theory. In practice, it doesn’t really help us in all browsers.
Starting with Chrome, we can see that we have an outline
in this state and the outline-color
computes to rgb(77, 144, 254)
, which is some kind of blue.
![Chrome DevTools screenshot showing an outline for an input having <code data-recalc-dims=](https://i0.wp.com/css-tricks.com/wp-content/uploads/2019/06/default_state_focus_chrome.png?ssl=1)
:focus
styling.Pretty straightforward and easy to spot.
Moving on to Firefox, things start to get hairy! Unlike Chrome, toggling the :focus
pseudo-class from DevTools does nothing on the input element, though by focusing it (by tab click), the border
becomes blue and we get a dotted
rectangle within — but there’s no indication in DevTools regarding what is happening.
![Animated gif. Shows how, on :focus, our input gets a blue border and a dark inner dotted rectangle.](https://i0.wp.com/css-tricks.com/wp-content/uploads/2019/06/default_state_focus_firefox_vis.gif?ssl=1)
:focus
it.If we check Firefox’s forms.css
, it provides an explanation for the dotted rectangle. This is the dotted border
of a pseudo-element, ::-moz-focus-inner
(a pseudo-element which, for some reason, isn’t shown in DevTools inside our input as ::-moz-color-swatch
is). This border
is initially transparent
and then becomes visible when the input is focused — the pseudo-class used here (:-moz-focusring
) is pretty much an old Firefox version of the new standard (:focus-visible
), which is currently only supported by Chrome behind the Experimental Web Platform features flag.
![Firefox DevTools screenshot where the inner dotted rectangle on :focus comes from: it is set as a transparent border on the ::-moz-focus-inner pseudo-element and it becomes visible when the input should have a noticeable :focus indicator.](https://i0.wp.com/css-tricks.com/wp-content/uploads/2019/06/default_state_focus_inner_firefox.png?ssl=1)
:focus
comes from.What about the blue border
? Well, it appears this one isn’t set by a stylesheet, but at an OS level instead. The good news is we can override all these styles should we choose to do so.
In Edge, we’re faced with a similar situation. Nothing happens when toggling the :focus
pseudo-class from DevTools, but if we actually tab to our input to focus it, we can see an inner dotted rectangle.
![Animated gif. Shows how, on :focus, our input gets an inner dotted rectangle.](https://i0.wp.com/css-tricks.com/wp-content/uploads/2019/06/default_state_focus_edge_vis.gif?ssl=1)
:focus
it.Even though I have no way of knowing for sure, I suspect that, just like in Firefox, this inner rectangle is due to a pseudo-element that becomes visible on :focus
.
:hover
In Chrome, toggling this pseudo-class doesn’t reveal any :hover
-specific styles in DevTools. Furthermore, actually hovering the input doesn’t appear to change anything visually. So it looks like Chrome really doesn’t have any :hover
-specific styles?
In Firefox, toggling the :hover
pseudo-class from DevTools reveals a new rule in the styles panel:
![Screenshot of Firefox DevTools showing the rule set that shows up for the :hover state.](https://i0.wp.com/css-tricks.com/wp-content/uploads/2019/06/default_state_hover_firefox.png?ssl=1)
:hover
styling as seen in DevTools.When actually hovering the input, we see the background
turns light blue and the border
blue, so the first thought would be that light blue is the -moz-buttonhoverface
value and that the blue border
is again set at an OS level, just like in the :focus
case.
![Animated gif. Shows that, on actually hovering our <input type='color' data-recalc-dims=](https://i0.wp.com/css-tricks.com/wp-content/uploads/2019/06/default_state_hover_firefox_vis.gif?ssl=1)
:hover
.However, if we look at the computed styles, we see the same background
we have in the normal state, so that blue background
is probably really set at an OS level as well, in spite of having that rule in the forms.css
stylesheet.
![Screenshot of Firefox DevTools showing the computed value for background-color in the :hover state.](https://i0.wp.com/css-tricks.com/wp-content/uploads/2019/06/default_state_hover_firefox_comp.png?ssl=1)
background-color
of an <input type='color'>
on :hover
.In Edge, toggling the :hover
pseudo-class from DevTools gives our input a light blue (rgb(166, 244, 255)
) background
and a blue (rgb(38, 160, 218)
) border
, whose exact values we can find in the Computed tab:
![Screenshot of Edge DevTools showing the computed value for background-color and border-color in the :hover state.](https://i0.wp.com/css-tricks.com/wp-content/uploads/2019/06/default_state_hover_edge.png?ssl=1)
background-color
and border-color
of an <input type='color'>
on :hover
.:active
Checking the :active
state in the Chrome DevTools does nothing visually and shows no specific rules in the Styles panel. However, if we actually click our input, we see that the background
gradient that doesn’t even show up in DevTools in the normal state gets reversed.
![Screenshot of the input in :active state in Chrome. A very light, almost white, grey to another light, but still darker grey gradient from bottom to top can be seen as the background, not the solid background-color indicated by DevTools.](https://i0.wp.com/css-tricks.com/wp-content/uploads/2019/06/look_chrome_normal.png?ssl=1)
:active
state. It appears to have a gradient (reversed from the normal state), in spite of the info we get from DevTools telling us it doesn’t.In Firefox DevTools, toggling the :active
state on does nothing, but if we also toggle the :hover
state on, then we get a rule set that changes the inline padding
(the block padding
is set to the same value of 0
it has in all other states), the border-style
and sets the background-color
back to our old friend ButtonFace
.
![Screenshot of Firefox DevTools showing the rule set that shows up for the :active state.](https://i0.wp.com/css-tricks.com/wp-content/uploads/2019/06/default_state_active_firefox.png?ssl=1)
:active
styling as seen in DevTools.In practice, however, the only thing that matches the info we get from DevTools is the inline shift given by the change in logical padding
. The background
becomes a lighter blue than the :hover
state and the border
is blue. Both of these changes are probably happening at an OS level as well.
![Animated gif. Shows that, on actually clicking our <input type='color' data-recalc-dims=](https://i0.wp.com/css-tricks.com/wp-content/uploads/2019/06/default_state_active_firefox_vis.gif?ssl=1)
:active
state.In Edge, activating the :active
class from DevTools gives us the exact same styles we have for the :hover
state. However, if we have both the :hover
and the :active
states on, things change a bit. We still have a light blue background
and a blue border
, but both are darker now (rgb(52, 180, 227)
for the background-color
and rgb(0, 137, 180)
for the border-color
):
![Screenshot of Edge DevTools showing the computed value for background-color and border-color in the :active state.](https://i0.wp.com/css-tricks.com/wp-content/uploads/2019/06/default_state_active_edge.png?ssl=1)
background-color
and border-color
of an <input type='color'>
on :active
viewed in Edge.This is the takeaway: if we want a consistent cross-browser results for <input type='color'>
, we should define our own clearly distinguishable styles for all these states ourselves because, fortunately, almost all the browser defaults — except for the inner rectangle we get in Edge on :focus
— can be overridden.
The swatch wrapper
This is a component we only see in Chrome, so if we want a cross-browser result, we should probably ensure it doesn’t affect the swatch inside — this means ensuring it has no margin
, border
, padding
or background
and that its dimensions equal those of the actual input’s content-box
.
In order to know whether we need to mess with these properties (and maybe others as a result) or not, let’s see what the browser defaults are for them.
Fortunately, we have no margin
or border
, so we don’t need to worry about these.
![Chrome DevTools screenshot showing the margin and border values for the swatch wrapper.](https://i0.wp.com/css-tricks.com/wp-content/uploads/2019/06/default_l1_margin_border_chrome.png?ssl=1)
margin
and border
values for the swatch wrapper in Chrome.We do however have a non-zero padding
(of 4px 2px
), so this is something we’ll need to zero out if we want to achieve a consistent cross-browser result.
![Chrome DevTools screenshot showing the padding values for the swatch wrapper.](https://i0.wp.com/css-tricks.com/wp-content/uploads/2019/06/default_l1_padding_chrome.png?ssl=1)
padding
values for the swatch wrapper in Chrome.The dimensions are both conveniently set to 100%
, which means we won’t need to mess with them.
![Chrome DevTools screenshot showing the size values for the swatch wrapper.](https://i0.wp.com/css-tricks.com/wp-content/uploads/2019/06/default_l1_dim_chrome.png?ssl=1)
Something we need to note here is that we have box-sizing
set to border-box
, so the padding
gets subtracted from the dimensions set on this wrapper.
![Chrome DevTools screenshot showing the box-sizing value for the swatch wrapper.](https://i0.wp.com/css-tricks.com/wp-content/uploads/2019/06/default_l1_box_chrome.png?ssl=1)
box-sizing
value for the swatch wrapper in Chrome.This means that while the padding-box
, border-box
and margin-box
of our wrapper (all equal because we have no margin
or border
) are identical to the content-box
of the actual <input type='color'>
(which is 44px
x23px
in Chrome), getting the wrapper’s content-box
involves subtracting the padding
from these dimensions. It results that this box is 40px
x15px
.
![Chrome DevTools screenshot showing the box model for the swatch wrapper.](https://i0.wp.com/css-tricks.com/wp-content/uploads/2019/06/default_l1_model_chrome.png?ssl=1)
The background
is set to transparent
, so that’s another property we don’t need to worry about resetting.
![Chrome DevTools screenshot showing the background values for the swatch wrapper.](https://i0.wp.com/css-tricks.com/wp-content/uploads/2019/06/default_l1_background_chrome.png?ssl=1)
background
values for the swatch wrapper in Chrome.There’s one more property set on this element that caught my attention: display
. It has a value of flex
, which means its children are flex items.
![Chrome DevTools screenshot showing the display value for the swatch wrapper.](https://i0.wp.com/css-tricks.com/wp-content/uploads/2019/06/default_l1_display_chrome.png?ssl=1)
display
value for the swatch wrapper in Chrome.The swatch
This is a component we can style in Chrome and Firefox. Sadly, Edge doesn’t expose it to allow us to style it, so we cannot change properties we might want to, such as border
, border-radius
or box-shadow
.
The box-sizing
property is one we need to set explicitly if we plan on giving the swatch a border
or a padding
because its value is content-box
in Chrome, but border-box
in Firefox.
![Comparative screenshots of DevTools in the two browsers showing the computed values of box-sizing for the swatch component.](https://i0.wp.com/css-tricks.com/wp-content/uploads/2019/06/default_l2_box.png?ssl=1)
box-sizing
values for the swatch viewed in Chrome (top) and Firefox (bottom).Fortunately, the font-size
is inherited from the input itself so it’s the same.
![Comparative screenshots of DevTools in the two browsers showing the computed values of font-size for the swatch component.](https://i0.wp.com/css-tricks.com/wp-content/uploads/2019/06/default_l2_font.png?ssl=1)
font-size
values for the swatch viewed in Chrome (top) and Firefox (bottom).The margin
computes to 0
in both Chrome and Firefox.
![Comparative screenshots of DevTools in the two browsers showing the computed values of margin for the swatch component.](https://i0.wp.com/css-tricks.com/wp-content/uploads/2019/06/default_l2_margin.png?ssl=1)
margin
values for the swatch viewed in Chrome (top) and Firefox (bottom).This is because most margins haven’t been set, so they end up being 0
which is the default for <div>
elements. However, Firefox is setting the inline margins to auto
and we’ll be getting to why that computes to 0
in just a little moment.
![Screenshot of Firefox DevTools.](https://i0.wp.com/css-tricks.com/wp-content/uploads/2019/06/default_l2_margin_logical_firefox.png?ssl=1)
margin
for the swatch being set to auto
in Firefox.The border
is solid 1px
in both browsers. The only thing that differs is the border-color
, which is rgb(119, 119, 119)
in Chrome and grey
(or rgb(128, 128, 128)
, so slightly lighter) in Firefox.
![Comparative screenshots of DevTools in the two browsers showing the computed values of border for the swatch component.](https://i0.wp.com/css-tricks.com/wp-content/uploads/2019/06/default_l2_border.png?ssl=1)
border
values for the swatch viewed in Chrome (top) and Firefox (bottom).Note that the computed border-width
in Firefox (at least on Windows) depends on the OS zoom level, just as it is in the case of the actual input.
The padding
is luckily 0
in both Chrome and Firefox.
![Comparative screenshots of DevTools in the two browsers showing the computed values of padding for the swatch component.](https://i0.wp.com/css-tricks.com/wp-content/uploads/2019/06/default_l2_padding.png?ssl=1)
padding
values for the swatch viewed in Chrome (top) and Firefox (bottom).The dimensions end up being exactly what we’d expect to find, assuming the swatch covers its parent’s entire content-box
.
![Comparative screenshots of DevTools in the two browsers showing the box model for the swatch component.](https://i0.wp.com/css-tricks.com/wp-content/uploads/2019/06/default_l2_model.png?ssl=1)
In Chrome, the swatch parent is the <div>
wrapper we saw earlier, whose content-box
is 4px
x15px
. This is equal to the margin-box
and the border-box
of the swatch (which coincide as we have no margin
). Since the padding
is 0
, the content-box
and the padding-box
for the swatch are identical and, subtracting the 1px
border, we get dimensions that are 38px
x13px
.
In Firefox, the swatch parent is the actual input, whose content-box
is 44px
x19px
one. This is equal to the margin-box
and the border-box
of the swatch (which coincide as we have no margin
). Since the padding
is 0
, the content-box
and the padding-box
for the swatch are identical and, subtracting the 1px
border, we get that their dimensions are 42px
x17px
.
In Firefox, we see that the swatch is made to cover its parent’s content-box
by having both its dimensions set to 100%
.
![Comparative screenshots of DevTools in the two browsers showing the size values for the swatch component.](https://i0.wp.com/css-tricks.com/wp-content/uploads/2019/06/default_l2_dim.png?ssl=1)
This is the reason why the auto
value for the inline margin
computes to 0
.
But what about Chrome? We cannot see any actual dimensions being set. Well, this result is due to the flex
layout and the fact that the swatch is a flex item that’s made to stretch such that it covers its parent’s content-box
.
![Chrome DevTools screenshot showing the flex value for the swatch wrapper.](https://i0.wp.com/css-tricks.com/wp-content/uploads/2019/06/default_l2_flex_chrome.png?ssl=1)
flex
value for the swatch wrapper in Chrome.Final thoughts
Phew, we covered a lot of ground here! While it may seem exhaustive to dig this deep into one specific element, this is the sort of exercise that illustrates how difficult cross-browser support can be. We have our own styles, user agent styles and operating system styles to traverse and some of those are always going to be what they are. But, as we discussed at the very top, this winds up being an accessibility issue at the end of the day, and something to really consider when it comes to implementing a practical, functional application of a color input.
Remember, a lot of this is ripe territory to reach out to browser vendors and let them know how they can update their implementations based on your reported use cases. Here are the three tickets I mentioned earlier where you can either chime in or reference to create a new ticket:
Wow, that’s nightmare territory
The colour picker should be burned with fire. No way anyone should use it on a real site.
That was a deep dive !
I had no idea you could inspect browser shadow DOM so easily.
That would make a great article series ;)
Edge Canary (I have 77.0.223.0 currently) has the exact same devtools settings as Chrome, and inspecting the shadow dom gives the same results as Chrome.
The firefox’s padding devtools “inconsistency” is due to the later rule doesn’t override the declared input rule, what’s overriding it is the browser itself when it processes the RTL logic, and devtools doesn’t have access to the browser on-the-fly post-processed styles, showing and associating the “raw input” for the rendering engine.
That was intense! I think we need a follow up on the actual color-picker itself in addition to the input. For a file picker it makes sense for that to be native but for a color picker not at all.
The color picker breaks the 4th wall so to speak … the eye dropper is able to traverse the system windows to get colors, which is a very good reason for that functionality to be a native function.