71

Is there a Webkit-specific CSS style that will allow me to control the color/size/style of the box around the color in an input[type=color]?

I'm setting the color and background color of the input already so it looks good with a cross-compatibility polyfill I'm using for older Chrome and Firefox.

Now that Chrome actually has a color picker, there's a box around the color which leaves a 1px grey box floating in the middle of the input when both color and background color of the input are set to the same color.

Is there some CSS to get rid of it, either by setting that box's width to 0, changing the style to none, or, at worst, setting the color to the same as the color and background color?


In this image, I'm talking about the grey box around the white area and outside the green:

Screenshot of color picker

I've found one workaround, which is to set a high enough padding that the box (the grey border and green contents) is squished to size 0. But that's really hacky, and doesn't look very good over in Firefox.

vsync
  • 118,978
  • 58
  • 307
  • 400
BrianFreud
  • 7,094
  • 6
  • 33
  • 50

12 Answers12

108

WebKit has special CSS selectors you can use to customize form controls but they aren't official.
An update to WebKit in the future will probably break it.

Please don't use it for production!!

But feel free to play with it for personal projects :)

Method 1

Uses webkit-specific selectors to mostly hide the non-colored part of the input.

input[type="color"] {
 -webkit-appearance: none;
 border: none;
 width: 32px;
 height: 32px;
}
input[type="color"]::-webkit-color-swatch-wrapper {
 padding: 0;
}
input[type="color"]::-webkit-color-swatch {
 border: none;
}
<input type=color value="#ff0000">

Method 2

Hides the color input (opacity:0) and uses JavaScript to set the background of the wrapper to the input's value.

var color_picker = document.getElementById("color-picker");
var color_picker_wrapper = document.getElementById("color-picker-wrapper");
color_picker.onchange = function() {
 color_picker_wrapper.style.backgroundColor = color_picker.value;    
}
color_picker_wrapper.style.backgroundColor = color_picker.value;
input[type="color"] {
 opacity: 0;
 display: block;
 width: 32px;
 height: 32px;
 border: none;
}
#color-picker-wrapper {
 float: left;
}
<div id="color-picker-wrapper">
 <input type="color" value="#ff0000" id="color-picker">
</div>
0b10011
  • 18,397
  • 4
  • 65
  • 86
Keishi Hattori
  • 1,104
  • 1
  • 8
  • 2
  • Wow, they make those hard to find. Thanks :D – BrianFreud Jul 13 '12 at 15:17
  • 3
    Method 2 works properly on Chrome, Firefox, and Opera. – Aebsubis Apr 21 '15 at 10:10
  • 2
    FYI the equivalent pseudo element for Firefox is -moz-color-swatch (there is no color-swatch-wrapper pseudo element on Firefox thouhg) – Arnaud Aug 11 '16 at 12:27
  • Method one still works on modern Chrome in 2020, with [one crazy caveat](https://bugs.chromium.org/p/chromium/issues/detail?id=1154623) -- you have to declare the rule by itself, i.e. no combining the `-webkit` and `-moz` prefixes in a single rule. – Coderer Dec 02 '20 at 12:03
  • Used this today, and just wanted to add Method 1 combined with `input[type="color"]:focus { outline: none !important; border: 0px; box-shadow: 0; }` makes it look like Method 2 without the js, by eliminating the focus border. – Ancel Designs Mar 10 '21 at 18:42
18

A good workaround is to:

  1. Wrap your color picker in a label.
  2. Set the color picker's visibility to false.
  3. Bind the label's background color to the value of the color picker.

Now, you have an easy to style label that when clicked, opens your color picker. As discussed in comments, clicking a label activates the color picker without any javascript; it's the default behaviour.

$(document).on('change', 'input[type=color]', function() {
  this.parentNode.style.backgroundColor = this.value;
});
input {
  visibility: hidden;
}

label {
  background-color: black;
  height: 32px;
  width: 32px;
  position: fixed;
}
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<label><input type="color"></label>

JSFiddle: https://jsfiddle.net/9zhap7rb/3/

GKFX
  • 1,386
  • 1
  • 11
  • 30
CodeToad
  • 4,656
  • 6
  • 41
  • 53
  • I just did the same thing for a "file" input element. It works very well. I set its width and height to 0 and set overflow to hidden, then just style the label however I like. – Frank Mar 27 '15 at 22:01
  • 1
    @Frank I may have misunderstood you, but if you are then using JS to click on the file input, this will not work in IE as this is seen as a security risk. You may not be but just a headsup for someone else – Luke Madhanga May 21 '15 at 21:26
  • Luke, look at the fiddle -- it's not JS based. Per the spec, if you put an `input` in a `label` then a click on the `label` triggers the `input`. This is the same way you'd make an entire checkbox toggleable by clicking the label. – Coderer Jul 21 '17 at 10:04
  • In case anybody decides to use this in 2020, 5 years later, it won't work in Safari iOS, because Safari iOS doesn't suport colour inputs. – Antony Jones May 15 '20 at 10:47
16

I am using a simple solution, but not so elegant, I guess. You can wrap the input with a div and make the input bigger than the container, after that you can shape the container as you want. You can also use a label with a for attribute to create a clickable button with some text.

I have made an example:

.input-color-container {
  position: relative;
  overflow: hidden;
  width: 40px;
  height: 40px;
  border: solid 2px #ddd;
  border-radius: 40px;
}

.input-color {
  position: absolute;
  right: -8px;
  top: -8px;
  width: 56px;
  height: 56px;
  border: none;
}

.input-color-label {
  cursor: pointer;
  text-decoration: underline;
  color: #3498db;
}
<div class="input-color-container">
  <input id="input-color" value="#ed6868" class="input-color" type="color">
</div>
<label class="input-color-label" for="input-color">
  I am a clickable label, try me
</label>
Henrique Rotava
  • 781
  • 1
  • 7
  • 13
15

This is how I did it for a art project recently. I am a newbie, so let me know if I did this horribly wrong.

input[type=color]{
 width: 40px;
 height: 40px;
 border: none;
 border-radius: 40px;
 background: none;
}
input[type="color"]::-webkit-color-swatch-wrapper {
 padding: 0;
}
input[type="color"]::-webkit-color-swatch {
 border: solid 1px #000; /*change color of the swatch border here*/
 border-radius: 40px;
}
<input type="color" value="#C899F5">
Terran Webb
  • 151
  • 1
  • 3
13

Building upon the approach from @Henrique Rotava, we can leverage the hidden overflow and negative margins to create a more flexible wrapper with less CSS markup. Basically the picker becomes big enough and stretches out enough that only the middle shows up when the wrapper clips it.

The wrapper must declare a width and height, which should be fine for most use cases where you want to style the wrapper, not the input. Otherwise the element will not be visible. All other formatting is optional for the wrapper.

input[type='color'] {
  padding: 0;
  width: 150%;
  height: 150%;
  margin: -25%;
}

.cp_wrapper {
  overflow: hidden;
  width: 2em;
  height: 2em;
  /* optional formatting below here */
  border-radius: 50%;
  box-shadow: 1px 1px 3px 0px grey;
  margin: 1em;
}
<div class="cp_wrapper">
  <input type="color" name="cp_1" value="#ff8888" />
</div>
<div class="cp_wrapper">
  <input type="color" name="cp_2" value="#88ff88" />
</div>
<div class="cp_wrapper">
  <input type="color" name="cp_3" value="#8888ff" />
</div>
OXiGEN
  • 2,041
  • 25
  • 19
8

Unfortunately, color inputs are quite finicky. Different browsers treat them differently. For example, Chrome will size the input based on width/height + border-width. Firefox, on the other hand, will use the maximum of width/height and border-width. This makes equal spacing quite difficult, with <input type=color> by itself.

However, what we can do is remove everything except for the picked color itself, and throw a wrapper around it that will be able to more predictably handle the spacing around the input.

label.color-picker {
  width: 150px; /* Width of color picker */
  border: 1px solid #ccc; /* Outer border */
  border-radius: 3px; /* Border radius of outer border */
  padding: 5px; /* Space between outer border and color picker */
  background: #fff; /* Color between outer border and color picker */

  display: block; /* Contain color picker within label */
}

label.color-picker > span {
  border: 1px solid #ccc; /* Border around color in color picker */

  display: block; /* Contain color picker within span */
}

label.color-picker > span > input[type=color] {
  height: 10px; /* Height of color picker */

  display: block; /* Avoids space above/below color picker */
  width: 100%; /* Fill available horizontal space */
  border: none; /* Remove browser's border */
  padding: 0px; /* Remove space around color picker in Chrome */
}

/* Chrome styles */
label.color-picker > span > input[type=color]::-webkit-color-swatch-wrapper {
  padding: 0; /* Remove browser's padding around color picker */
}
label.color-picker > span > input[type=color]::-webkit-color-swatch {
  border: none; /* Remove browser's border around color in color picker */
}

/* Firefox styles */
label.color-picker > span > input[type=color]::-moz-color-swatch {
  border: none; /* Remove browser's border around color in color picker */
}
label.color-picker > span > input[type=color]::-moz-focus-inner {
  border: none; /* Remove browser's padding around color in color picker */
  padding: 0; /* Remove browser's padding around color in color picker */
}
<label class="color-picker">
    <span>
        <input type=color value="#ff00ff">
    </span>
</label>
0b10011
  • 18,397
  • 4
  • 65
  • 86
5

Here is the nice little color input design, you can disable the default frame by -webkit-appearance: none and then give the desired styles. Hop this helps :)

input[type="color"] {
   -webkit-appearance: none;
    width: 30px;
    height: 30px;
    border: 0;
    border-radius: 50%;
    padding: 0;
    overflow: hidden;
    box-shadow: 2px 2px 5px rgba(0,0,0,.1);
}
input[type="color"]::-webkit-color-swatch-wrapper {
    padding: 0;
}
input[type="color"]::-webkit-color-swatch {
    border: none;
}
<input type=color value="#A4A4A4">
Kiran Maniya
  • 8,453
  • 9
  • 58
  • 81
2

Another method, not mentioned here, uses custom-property (variable) set on the input element itself, and controlled by an onInput event handler directly on the element. Since CSS attr is currently unit-less, there is no choice but create a variable of type color and use it.

It's a bit of a hassle but the HTML is still single-element.

input[type=color]{
  --size: 100px;
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
  margin: 0;
  border: 0;
  padding: 0;
  width: 0;
  height: 0;
  background: white;
  margin: calc(var(--size)/-2) 0 0 calc(var(--size)/-2);
}
  
input[type=color]::before{
  content: '';
  display: block;
  background: var(--value);
  text-transform: uppercase;
  width: var(--size);
  height: var(--size);
  margin: calc(var(--size)/2) 0 0 calc(var(--size)/2);
  border: 2px black;
  position: relative;
  z-index: 1;
  border-radius: 50%;
  cursor: pointer;
}
<input type="color" value="#ff0000" style="--value:#ff0000" oninput="this.style.setProperty('--value', this.value)" />

OCT 2020: New attr() type syntax (not yet finilized)

There is a very cool new feature coming to CSS which helps a lot in this situation, as it makes it possible to access the dynamic value property of an input and use it in a pseudo-element. Apparently type="color" allows pseudo-elements.

As of writing this, no browser has support for this feature which allows specifying type within attr() so effectively attr could be used as background for the input's psuedo-element, allowing complete customization:

input[type=color]{
  appearance: none;
  margin: 0;
  border: 0;
  padding: 0;
  width: 0;
  height: 0;
  margin: -100px 0 0 -100px;
}
  
input[type=color]::before{
  content: '';
  display: block;
  background: white;
  background: attr(value color, white);
  width: 200px;
  height: 200px;
  margin: 100px 0 0 100px;
  border: 2px black;
  position: relative;
  z-index: 1;
  border-radius: 50%;
}
<input type="color" value="#ff0000" />
vsync
  • 118,978
  • 58
  • 307
  • 400
2

Try this one...

enter image description here

.input-color-container {
            width: 35px;
            height: 35px;
            border-radius: 8px;
            background-color: white;
            border: 1px solid #D4D9E2;
            // border: solid 2px #ddd;
            // border-radius: 40px;
        }
        .input-color {
            appearance: none;
            background: transparent;
            border: none;
            height: 35px;
            width: 35px;
            cursor: pointer;
            
        }
        .input-color::-webkit-color-swatch {
                border-radius: 50%;
                border: none;
            }
<div class="input-color-container">
  <input class="input-color" value="#FF0000" type="color">
</div>
Rohit Tagadiya
  • 3,373
  • 1
  • 25
  • 25
1

I think this solution is best than Keishi Hattori which is currently the chosen one. Keishi Hattori's solution leaves a dull color around the selected color and requires to set a width/height and does not work well if you add a border.

I found the following solution to work better.

input[type="color"] {
  -webkit-appearance: none;
  position:relative;
}
input[type="color"]::-webkit-color-swatch {
  position:absolute;
  top:-1px;
  left:-1px;
  right:-1px;
  bottom:-1px;
  box-sizing: border-box;
  border:1px solid transparent;
}
<input type="color"  value="#ff0000">

You can add a border if you want.

input[type="color"].withborder {
  -webkit-appearance: none;
  position:relative;
  border:1px solid #000;
}

input[type="color"].withborder::-webkit-color-swatch {
  position:absolute;
  top:0px;
  left:0px;
  right:0px;
  bottom:0px;
  box-sizing: border-box;
  border:1px solid transparent;
}
<input type="color" class="withborder"  value="#ff0000">

You can add a background in input[type="color"] if you want. You'll need to change the 0px in the ::-webkit-color-swatch.

input[type="color"].withborder {
  -webkit-appearance: none;
  position:relative;
  border:1px solid #000;
  background:#bbb;

}

input[type="color"].withborder::-webkit-color-swatch {
  position:absolute;
  top:4px;
  left:4px;
  right:4px;
  bottom:4px;
  box-sizing: border-box;
  border:0px solid transparent;
}
<input type="color" class="withborder"  value="#ff0000">
v1nce
  • 735
  • 9
  • 20
0

This may work, except IE.

input[type=color]{
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
  margin: 0;
  border: 0;
  padding: 0;
  /*input[type=color] double the scale and clip the offset*/
  -webkit-transform: scale(2);
  transform: scale(2);
  -webkit-clip-path: inset(25%);
  clip-path: inset(25%);
}
  
input[type=color]:before{
  content: attr(value);
  text-shadow:.1em .1em #fff;
  font-size:.5em;
  width:50%;height:50%;
  left:25%;top:25%;
  text-align:center;
  position:absolute;
  background-image: url('data:image/gif;base64,R0lGODlhBgADAPABAICAgAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQJFAABACwAAAAABgADAAACBkxggGfMBQAh+QQJFAABACwAAAAABgADAAACBQximHZbACH5BAUUAAEALAAAAAAGAAMAAAIFRGKXiVoAOw==');
  }
<input type="color" value="#ff0000" />
<input type="color" value="#00ff00" />
<input type="color" value="#0000ff" />
PartialFlavor_55KP
  • 137
  • 1
  • 3
  • 13
-2

My method:

<div class="user__colors">
    <label><input type="color"/></label>
</div>

input {
    background-color: transparent;
    border: none;
    position: relative;
    width: 80px;
    height: 12px;
    &:after {
        position: absolute;
        content: '';
        display: block;
        width: 100%;
        height: 100%;
        background: url(../img/color-palette.jpg) repeat-y 0 0;
        background-size: contain;
        top: 0;
        border-radius: 3px;
    }
}

And it view like this: http://prntscr.com/gloozc

But if you press Ctl+F5, you`ll see original input for a moment.