How to Set Placeholder Value Using CSS

Input placeholder using CSS only

It doesn't work for the simple fact that this:

<input id="tb1" type="text" class="note"></input>

is not valid. <input /> elements are not containers. As the spec notes, endtags are forbidden (and essentially ignored by the browser): http://www.w3.org/TR/html401/interact/forms.html#h-17.4

Placeholder Text

You can use the following pseudo-elements (note the terminology) in webkit-based, Firefox and IE browsers of later vintage:

// Note two colons, -input-
::-webkit-input-placeholder

// Note two colons, NO -input-
::-moz-placeholder

// Note ONE colon, -input-
:-ms-input-placeholder

This particular "functionality" associated with this one attribute seems to be evolving, so this answer may eventually become dated. These are vendor-prefixed, after all.

What I did find is in webkit-based browsers, you can treat this attribute as a pseudo-element (more below on that), to the point you can manipulate it's CSS content with :before and :after in such a way that it appears you've changed the placeholder. With Firefox, at least right now, that's not possible (also more later). With IE9 (the only version I tested), it did not appear to work.

The following works only in Chrome:

Markup

<input type="text" class="before" placeholder="Wide "/><br/>
<input type="text" placeholder="Wide "/><br/>
<input type="text" placeholder="Wide "/>

CSS

.before::-webkit-input-placeholder:before {
content: 'Hello \A';
font-size: 12px;
color: red;
}
::-webkit-input-placeholder:before {
content: 'Hello ';
font-size: 12px;
color: red;
}
::-webkit-input-placeholder {
white-space: pre;
font-size: 5px;
}
::-webkit-input-placeholder:after {
content: 'World';
font-size: 12px;
color: blue;
}

http://jsfiddle.net/LDkjW/

Note there's two :befores in there, showing two methods, one with the \A newline which works in CSS, and also a bracketed :before and :after if you're interested. As you can agree, the :after isn't very useful if you've used \A with :before.

Note, browsers freak out if you have a pseudo-selector it doesn't recognize, so if you decide to include the others, you should do each vendor's in it's own block. In addition, you'll see the lack of -input- on the -moz (Firefox) pseudo-element. That's because (ta-da) textarea's also get the placeholder treatment. And at least Chrome (IE?) does also apply this to textareas. Why -input- is in there, who knows.

That's it. I don't know how this is intended to be used, but I suspect it's probably best done another way. If webkit browsers are all you care about, you're good. Otherwise, maybe one day... The rest is just excessive.


Firefox

You can "remove from view" the placeholder fairly easily in Firefox:

::-moz-placeholder {
font-size: 0;
left-indent: -1000px;
font-color: white;
}

You get the idea. ::-moz-placeholder was :-moz-placeholder until recently, which it was given the new selector moniker. Let's take a closer look.

:-moz-placeholder  // Legacy
::-moz-placeholder // As of FF17

One : indicates by convention that this references a state of the selected element. Your hovers, :link, visited, :focused, as well as the more useful CSS3 pseudo-selectors such as :nth-child, :selected, :checked, etc.

This ::-moz-placeholder being a pseudo-element, it's not observing a state or condition of an element, it's representing an element. A pseudo element. Where are we headed with this, you might be thinking.

From what it appears to be, an input is not what it appears to be. For instance:

http://dxr.mozilla.org/mozilla-central/layout/style/forms.css.html

Which you can access through Firefox's address bar using:

resource://gre-resources/forms.css

We find things like:

input > .anonymous-div,
input::-moz-placeholder {
word-wrap: normal !important;
/* Make the line-height equal to the available height */
line-height: -moz-block-height;
}

And:

textarea > .anonymous-div,
input > .anonymous-div,
input::-moz-placeholder,
textarea::-moz-placeholder {
white-space: pre;
overflow: auto;
...
-moz-text-decoration-color: inherit;
-moz-text-decoration-style: inherit;
display: inline-block;
ime-mode: inherit;
resize: inherit;
}
textarea > .anonymous-div.wrap,
input > .anonymous-div.wrap {
white-space: pre-wrap;
}
textarea > .anonymous-div.inherit-overflow,
input > .anonymous-div.inherit-overflow {
overflow: inherit;
}
input::-moz-placeholder,
textarea::-moz-placeholder {
/*
* Changing display to inline can leads to broken behaviour and will assert.
*/
display: inline-block !important;
/*
* Changing resize would display a broken behaviour and will assert.
*/
resize: none !important;
overflow: hidden !important;
/*
* The placeholder should be ignored by pointer otherwise, we might have some
* unexpected behavior like the resize handle not being selectable.
*/
pointer-events: none !important;
opacity: 0.54;
}

I'm sure you've noticed the input::-moz-placeholder (?) and the textarea is also part of the fun. But did you notice this?

textarea > .anonymous-div,
input > .anonymous-div,

.anonymous-div? What the heck is that? Whatever it is, the selector indicates it's within the input/textarea element. Really?

Later, the unusual truth comes out:

 /*
* Make form controls inherit 'unicode-bidi' transparently as required by
* their various anonymous descendants and pseudo-elements:
*
* <textarea> and <input type="text">:
* inherit into the XULScroll frame with class 'anonymous-div' which is a
* child of the text control.
*
* Buttons (either <button>, <input type="submit">, <input type="button">
* or <input type="reset">)
* inherit into the ':-moz-button-content' pseudo-element.
*
* <select>:
* inherit into the ':-moz-display-comboboxcontrol-frame' pseudo-element and
* the <optgroup>'s ':before' pseudo-element, which is where the label of
* the <optgroup> gets displayed. The <option>s don't use anonymous boxes,
* so they need no special rules.
*/
textarea > .anonymous-div,
input > .anonymous-div,
input::-moz-placeholder,
textarea::-moz-placeholder,
*|*::-moz-button-content,
*|*::-moz-display-comboboxcontrol-frame,
optgroup:before {
unicode-bidi: inherit;
text-overflow: inherit;
}

So there you go. There's an "anonymous" (div) embedded within all textarea and input[type=text] elements you work with. Here's some XUL that seems plausibly similar to what is probably going on right under our noses:

XUL

<box id="num" class="labeledbutton" title="Number of Things:" value="52"/>

<button label="Show" oncommand="document.getElementById('num').showTitle(true)"/>
<button label="Hide" oncommand="document.getElementById('num').showTitle(false)"/>

XBL

<binding id="labeledbutton">
<content>
<xul:label xbl:inherits="value=title"/>
<xul:label xbl:inherits="value"/>
</content>
<implementation>
<method name="showTitle">
<parameter name="state"/>
<body>
if (state) document.getAnonymousNodes(this)[0].
setAttribute("style","visibility: visible");
else document.getAnonymousNodes(this)[0].
setAttribute("style","visibility: collapse");
</body>
</method>
</implementation>
</binding>

Unfortunately, the manner in which Firefox deals with this "anonymous" gang of pseudo-elements means you probably won't be able to manipulate the placeholder's text like we did in Chrome.

And just now I found the XUL/XBL markup that includes the input and placeholder mechanism/definition. Here it is:

  <property name="label" onset="this.setAttribute('label', val); return val;"
onget="return this.getAttribute('label') ||
(this.labelElement ? this.labelElement.value :
this.placeholder);"/>
<property name="placeholder" onset="this.inputField.placeholder = val; return val;"
onget="return this.inputField.placeholder;"/>
<property name="emptyText" onset="this.placeholder = val; return val;"
onget="return this.placeholder;"/>

Which handles the placeholder swapping. The following shows in the .anonymous-div, which appears to get swapped out with some code from the core. I'll spare you those gory details.

  <binding id="input-box">
<content context="_child">
<children/>
...
</content>

These last two blocks I found within:

jar:file:///C:/path/to/a/FirefoxPortable/App/firefox/omni.ja!/chrome/toolkit/content/global/bindings/textbox.xml

If you're interested in getting into Firefox's business on this (or in general), try this if you're interesting in getting into more of the actual chrome HTML and CSS files:

resource://gre-resources/

You can read more on ::-webkit-input-placeholder or ::-moz-placeholder in this question. Take note that this particular type of selector (pseudo-element, not pseudo class... at least lately...) is somewhat brittle in the way you approach using them in stylesheets.

http://dxr.mozilla.org/mozilla-central/layout/style/forms.css.html

Phew. Never thought this snipe hunt was going to end. Hope that helps somebody. I learned some things, like the context menu over the input[type=text] elements is hardcoded into the XUL code with the element markup definition. Another surprise.

Anyhow, good luck.



Related Topics



Leave a reply



Submit