Better CSS Placeholder
I haven’t seen anyone mention this little CSS tip. All the proprietary vendor-specific placeholder rules now safely can be replaced with just ::placeholder
. Seems very useful especially with the ever-increasing emphasis on site performance. The end result is less code and thus faster loading, better SEO and so forth.
Contents
5 second summary
Instead of this widely used monstrous vendor-specific anti-pattern:
::-webkit-input-placeholder { /* Chrome and Safari */
color: #777;
}
:-moz-placeholder { /* Mozilla Firefox 4 - 18 */
color: #777;
opacity: 1;
}
::-moz-placeholder { /* Mozilla Firefox 19+ */
color: #777;
opacity: 1;
}
:-ms-input-placeholder { /* Internet Explorer 10 - 11 */
color: #777;
}
::-ms-input-placeholder { /* Microsoft Edge */
color: #777;
}
We now can just write this:
::placeholder { color: #777; opacity: 1; }
And done. That line supports all major browsers. So we just saved some bandwidth and boosted performance in like 2 seconds. Less code, cleaner code. Thanks CSS devs and browser makers.
opacity
property is included for Mozilla because browsers like Firefox decrease the opacity of placeholder colors by default. For more information, check out how to deal with Firefox later in the article.Code discussion
The above vendor-prefixed anti-pattern is very common even today:
::-webkit-input-placeholder { /* Chrome and Safari */
color: #777;
}
:-moz-placeholder { /* Mozilla Firefox 4 - 18 */
color: #777;
opacity: 1;
}
::-moz-placeholder { /* Mozilla Firefox 19+ */
color: #777;
opacity: 1;
}
:-ms-input-placeholder { /* Internet Explorer 10 - 11 */
color: #777;
}
::-ms-input-placeholder { /* Microsoft Edge */
color: #777;
}
Five declaration blocks to style the placeholder element. Looking at it now feels wrong, but alas it did the job, got us through some dark times. And you can still go that route; although a royal mess, that set of rules continues to work just fine if for some reason you need to support very old browsers.
::placeholder
pseudo-element is not included in the commonly used anti-pattern (although it should have been). Including it would have made for a smoother transition over time.You might think, combining all the selectors would help, something like:
/* Don't do this it doesn't work */
::-webkit-input-placeholder,
:-moz-placeholder,
::-moz-placeholder,
:-ms-input-placeholder,
::-ms-input-placeholder {
color: #777;
opacity: 1;
}
Unfortunately that syntax is not supported. When it comes to styling the placeholder, you have to define each selector individually. Combining is not allowed. So if you want to customize placeholders for multiple elements, the number of declarations increases by a multiple of five.
Let’s look at an example using my pro WordPress plugin, SAC Pro. I wanted to style the placeholder for two different elements, so would have needed 10 declarations, like:
.sacpro-box ::-webkit-input-placeholder { color: #777; }
.sacpro-form ::-webkit-input-placeholder { color: #333; }
.sacpro-box :-moz-placeholder { color: #777; opacity: 1; }
.sacpro-form :-moz-placeholder { color: #333; opacity: 1; }
.sacpro-box ::-moz-placeholder { color: #777; opacity: 1; }
.sacpro-form ::-moz-placeholder { color: #333; opacity: 1; }
.sacpro-box :-ms-input-placeholder { color: #777; }
.sacpro-form :-ms-input-placeholder { color: #333; }
.sacpro-box ::-ms-input-placeholder { color: #777; }
.sacpro-form ::-ms-input-placeholder { color: #333; }
And it just gets crazier the more elements you want to style. So much code for something so simple.
Notice the above CSS rules are all vendor-prefixed selectors, implemented to support placeholder in various browsers until full support is rolled out. Well good news, that day finally has arrived..
A better way..
Fortunately browser support for the actual CSS placeholder selector has improved greatly. In fact, recent versions of all major browsers fully support ::placeholder. So now we can style placeholders with a single golden rule:
::placeholder { color: #777; opacity: 1; }
Compare that with the ol’ vendor-prefix stack. Much less code & easier to maintain.
Or if you need to target placeholder for a specific element, say .example
:
.example ::placeholder { color: #777; opacity: 1; }
And to really drive it home, let’s return to the SAC Pro example. It’s now possible to style two separate placeholders using only two lines instead of 10:
.sacpro-box ::placeholder { color: #777; opacity: 1; }
.sacpro-form ::placeholder { color: #333; opacity: 1; }
Elegant and awesome.
Dealing with Firefox
Note the inclusion of opacity
in the above examples. That helps to normalize the color
property across browsers. For example, Firefox lowers placeholder opacity by default. This can be addressed directly by including the vendor-specific selector for Mozilla/Firefox:
/* Firefox lowers placeholder opacity by default */
::-moz-placeholder { color: #777; opacity: 1; }
Fortunately it’s NOT necessary to include that vendor-specific rule.
Instead, to address Firefox’s weird placeholder opacity tweaking, simply include opacity
when declaring ::placeholder
. The color then will be accurate and consistent across all browsers, exactly as specified.
::placeholder { color: #777; opacity: 1; }
Dealing with IE
Internet Explorer (IE) has been retired. Some people are still using IE though. According to this source, IE still enjoys 28 million users in 2023. Read it again.
So to be extra safe for those folks you could do like this. Basically including the IE vendor rule whenever using ::placeholder
. For example:
/* All major browsers */
::placeholder { color: #777; opacity: 1; }
/* Internet Explorer */
:-ms-input-placeholder { color: #777; opacity: 1; }
Personally, I’m no longer adding special/extra support for anything IE. Anyone still using IE imho is gonna be just fine without my custom placeholder styles lol.