Here are three solutions:
Solution #1 - appearance: none - with Internet Explorer 10 - 11 workaround (Demo)
--
To hide the default arrow set appearance: none
on the select element, then add your own custom arrow with background-image
select {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none; /* Remove default arrow */
background-image: url(...); /* Add custom arrow */
}
Browser Support:
appearance: none
has very good browser support (caniuse) - except for Internet Explorer.
We can improve this technique and add support for Internet Explorer 10 and Internet Explorer 11 by adding
select::-ms-expand {
display: none; /* Hide the default arrow in Internet Explorer 10 and Internet Explorer 11 */
}
If Internet Explorer 9 is a concern, we have no way of removing the default arrow (which would mean that we would now have two arrows), but, we could use a funky Internet Explorer 9 selector.
To at least undo our custom arrow - leaving the default select arrow intact.
/* Target Internet Explorer 9 to undo the custom arrow */
@media screen and (min-width:0\0) {
select {
background-image:none\9;
padding: 5px\9;
}
}
All together:
select {
margin: 50px;
width: 150px;
padding: 5px 35px 5px 5px;
font-size: 16px;
border: 1px solid #CCC;
height: 34px;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
background: url(https://stackoverflow.com/favicon.ico) 96% / 15% no-repeat #EEE;
}
/* CAUTION: Internet Explorer hackery ahead */
select::-ms-expand {
display: none; /* Remove default arrow in Internet Explorer 10 and 11 */
}
/* Target Internet Explorer 9 to undo the custom arrow */
@media screen and (min-width:0\0) {
select {
background: none\9;
padding: 5px\9;
}
}
<select>
<option>Apples</option>
<option selected>Pineapples</option>
<option>Chocklate</option>
<option>Pancakes</option>
</select>
This solution is easy and has good browser support - it should generally suffice.
If browser support for Internet Explorer is needed, read ahead.
Solution #2 Truncate the select element to hide the default arrow (demo)
--
(Read more here)
Wrap the select
element in a div with a fixed width and overflow:hidden
.
Then give the select
element a width of about 20 pixels greater than the div.
The result is that the default drop-down arrow of the select
element will be hidden (due to the overflow:hidden
on the container), and you can place any background image you want on the right-hand-side of the div.
The advantage of this approach is that it is cross-browser (Internet Explorer 8 and later, WebKit, and Gecko). However, the disadvantage of this approach is that the options drop-down juts out on the right-hand-side (by the 20 pixels which we hid... because the option elements take the width of the select element).
[It should be noted, however, that if the custom select element is necessary only for mobile devices - then the above problem doesn't apply - because of the way each phone natively opens the select element. So for mobile, this may be the best solution.]
.styled select {
background: transparent;
width: 150px;
font-size: 16px;
border: 1px solid #CCC;
height: 34px;
}
.styled {
margin: 50px;
width: 120px;
height: 34px;
border: 1px solid #111;
border-radius: 3px;
overflow: hidden;
background: url(https://stackoverflow.com/favicon.ico) 96% / 20% no-repeat #EEE;
}
<div class="styled">
<select>
<option>Pineapples</option>
<option selected>Apples</option>
<option>Chocklate</option>
<option>Pancakes</option>
</select>
</div>
If the custom arrow is necessary on Firefox - prior to Version 35 - but you don't need to support old versions of Internet Explorer - then keep reading...
Solution #3 - Use the pointer-events
property (demo)
--
(Read more here)
The idea here is to overlay an element over the native drop down arrow (to create our custom one) and then disallow pointer events on it.
Advantage: It works well in WebKit and Gecko. It looks good too (no jutting out option
elements).
Disadvantage: Internet Explorer (Internet Explorer 10 and down) doesn't support pointer-events
, which means you can't click the custom arrow. Also, another (obvious) disadvantage with this method is that you can't target your new arrow image with a hover effect or hand cursor, because we have just disabled pointer events on them!
However, with this method you can use Modernizer or conditional comments to make Internet Explorer revert to the standard built in arrow.
NB: Being that Internet Explorer 10 doesn't support conditional comments
anymore: If you want to use this approach, you should probably use Modernizr. However, it is still possible to exclude the pointer-events CSS from Internet Explorer 10 with a CSS hack described here.
.notIE {
position: relative;
display: inline-block;
}
select {
display: inline-block;
height: 30px;
width: 150px;
outline: none;
color: #74646E;
border: 1px solid #C8BFC4;
border-radius: 4px;
box-shadow: inset 1px 1px 2px #DDD8DC;
background: #FFF;
}
/* Select arrow styling */
.notIE .fancyArrow {
width: 23px;
height: 28px;
position: absolute;
display: inline-block;
top: 1px;
right: 3px;
background: url(https://stackoverflow.com/favicon.ico) right / 90% no-repeat #FFF;
pointer-events: none;
}
/*target Internet Explorer 9 and Internet Explorer 10:*/
@media screen and (min-width: 0\0) {
.notIE .fancyArrow {
display: none;
}
}
<!--[if !IE]> -->
<div class="notIE">
<!-- <![endif]-->
<span class="fancyArrow"></span>
<select>
<option>Apples</option>
<option selected>Pineapples</option>
<option>Chocklate</option>
<option>Pancakes</option>
</select>
<!--[if !IE]> -->
</div>
<!-- <![endif]-->
Implementation
There are three different implementations: pseudo-elements, pseudo-classes, and nothing.
- WebKit, Blink (Safari, Google Chrome, Opera 15+) and Microsoft Edge are using a pseudo-element:
::-webkit-input-placeholder
. [Ref]
- Mozilla Firefox 4 to 18 is using a pseudo-class:
:-moz-placeholder
(one colon). [Ref]
- Mozilla Firefox 19+ is using a pseudo-element:
::-moz-placeholder
, but the old selector will still work for a while. [Ref]
- Internet Explorer 10 and 11 are using a pseudo-class:
:-ms-input-placeholder
. [Ref]
- April 2017: Most modern browsers support the simple pseudo-element
::placeholder
[Ref]
Internet Explorer 9 and lower does not support the placeholder
attribute at all, while Opera 12 and lower do not support any CSS selector for placeholders.
The discussion about the best implementation is still going on. Note the pseudo-elements act like real elements in the Shadow DOM. A padding
on an input
will not get the same background color as the pseudo-element.
CSS selectors
User agents are required to ignore a rule with an unknown selector. See Selectors Level 3:
a group of selectors containing an invalid selector is invalid.
So we need separate rules for each browser. Otherwise the whole group would be ignored by all browsers.
::-webkit-input-placeholder { /* WebKit, Blink, Edge */
color: #909;
}
:-moz-placeholder { /* Mozilla Firefox 4 to 18 */
color: #909;
opacity: 1;
}
::-moz-placeholder { /* Mozilla Firefox 19+ */
color: #909;
opacity: 1;
}
:-ms-input-placeholder { /* Internet Explorer 10-11 */
color: #909;
}
::-ms-input-placeholder { /* Microsoft Edge */
color: #909;
}
::placeholder { /* Most modern browsers support this now. */
color: #909;
}
<input placeholder="Stack Snippets are awesome!">
Usage notes
- Be careful to avoid bad contrasts. Firefox's placeholder appears to be defaulting with a reduced opacity, so needs to use
opacity: 1
here.
- Note that placeholder text is just cut off if it doesn’t fit – size your input elements in
em
and test them with big minimum font size settings. Don’t forget translations: some languages need more room for the same word.
- Browsers with HTML support for
placeholder
but without CSS support for that (like Opera) should be tested too.
- Some browsers use additional default CSS for some
input
types (email
, search
). These might affect the rendering in unexpected ways. Use the properties -webkit-appearance
and -moz-appearance
to change that. Example:
[type="search"] {
-moz-appearance: textfield;
-webkit-appearance: textfield;
appearance: textfield;
}
Best Answer
Chrome does not allow styling form validation bubbles anymore:
See Details
Firefox has no way to style the error bubbles
See Details