CSS content generation before or after 'input' elements [duplicate]
Asked Answered
M

5

228

In Firefox 3 and Google Chrome 8.0 the following works as expected:

<style type="text/css">
    span:before { content: 'span: '; }
</style>

<span>Test</span> <!-- produces: "span: Test" -->

But it doesn't when the element is <input>:

<style type="text/css">
    input:before { content: 'input: '; }
</style>

<input type="text"></input> <!-- produces only the textbox; the generated content
                                 is nowhere to be seen in both FF3 and Chrome 8 -->

Why is it not working like I expected?

Modest answered 1/1, 2011 at 17:29 Comment(4)
<input> needs to self-close. If you want to give your text box a label, use <label>.Brunildabruning
I realize this is an older thread, but... BoltClock's comment is semantically correct and is supported by the widely held opinion of CSS purists that CSS should be for design only (not for content). However, I am of the opinion that label elements and the like are design elements - so I feel that CSS is the right path for the desired outcome in this case.Kant
@Joshua: I'm not sure. I don't think there's a lot to earn from being a CSS purist; I heard some (all?) of them don't like variables and the like in CSS, too. That's absurd. I do agree, though that labels can well be considered content, so again, I'm not sure. Still, I don't think the limitation makes a lot of sense in practice...Catlike
Agreed. I think it is best to apply the blanket, "purist-style" rules to those who are just learning the tool-set. But then once you have mastered them, and can understand things like the type of role that abstraction plays in CSS, then it's ok to start questioning and stretching those boundaries. If you do before then, you'll only get more confused on down the line. I suppose that's the difference between coding and programming.. "Look, it did something" vs "Look what I did". That's just my opinion.Kant
H
346

With :before and :after you specify which content should be inserted before (or after) the content inside of that element. input elements have no content.

E.g. if you write <input type="text">Test</input> (which is wrong) the browser will correct this and put the text after the input element.

The only thing you could do is to wrap every input element in a span or div and apply the CSS on these.

See the examples in the specification:

For example, the following document fragment and style sheet:

<h2> Header </h2>               h2 { display: run-in; }
<p> Text </p>                   p:before { display: block; content: 'Some'; }

...would render in exactly the same way as the following document fragment and style sheet:

<h2> Header </h2>            h2 { display: run-in; }
<p><span>Some</span> Text </p>  span { display: block }

This is the same reason why it does not work for <br>, <img>, etc. (<textarea> seems to be special).

Horney answered 1/1, 2011 at 17:37 Comment(6)
@Jason why, with jquery of course! edit: also, you can use thumbtacks, or spraypaint or summin. or fire.Papillose
use a button element instead: jsfiddle.net/svandragt/gRgcbRima
This is what I really want: <input name='…' type='…' required>, then input[required]::after { content: ' *'; color: red; }. le sigh.Flick
@thirdender: Which is clearly a matter of design. Yeah, I know how you feel.Catlike
The spec cited says: “This specification does not fully define the interaction of :before and :after with replaced elements (such as IMG in HTML)”, and INPUT can be interpreted as a replaced element. Thus, the spec does not say that :before does not work for such elements. Rather, that it’s unspecified.Oconner
It doesn't matter what there is in "specification". What you write doesn't work in the browser.Botfly
A
81

This is not due to input tags not having any content per-se, but that their content is outside the scope of CSS.

input elements are a special type called replaced elements, these do not support :pseudo selectors like :before and :after.

In CSS, a replaced element is an element whose representation is outside the scope of CSS. These are kind of external objects whose representation is independent of the CSS. Typical replaced elements are <img>, <object>, <video> or form elements like <textarea> and <input>. Some elements, like <audio> or <canvas> are replaced elements only in specific cases. Objects inserted using the CSS content properties are anonymous replaced elements.

Note that this is even referred to in the spec:

This specification does not fully define the interaction of :before and :after with replaced elements (such as IMG in HTML).

And more explicitly:

Replaced elements do not have ::before and ::after pseudo-elements

Analcite answered 30/12, 2014 at 15:25 Comment(0)
C
23

Something like this works:

input + label::after {
  content: 'click my input';
  color: black;
}

input:focus + label::after {
  content: 'not valid yet';
  color: red;
}

input:valid + label::after {
  content: 'looks good';
  color: green;
}
<input id="input" type="number" required />
<label for="input"></label>

Then add some floats or positioning to order stuff.

Councillor answered 30/4, 2014 at 8:27 Comment(2)
While this works, it's not a good idea if you need to keep your markup accessible. CSS content should only be used for design. In this case, using javascript to input helpful information into the label is a better way to go.Bullheaded
For sure! I was answering the question, not trying to make the code work for all situations. This should get people going in the right direction. Some ways to deal with accessibility would be to have multiple labels with the various texts and using display: none to hide the irrelevant ones.Councillor
A
4

fyi <form> supports :before / :after as well, might be of help if you wrap your <input> element with it... (got myself a design issue with that too)

Androsphinx answered 19/11, 2012 at 13:6 Comment(2)
fieldset is probably more appropriate than form if you want a simple wrapper for an input element.Melchizedek
And span or div is probably more appropriate than fieldset, since for the latter you need to override all the user agent css (at the very least margin, padding, border)Anesthesiology
C
0

Use tags label and our method for =, is bound to input. If follow the rules of the form, and avoid confusion with tags, use the following:

<style type="text/css">
    label.lab:before { content: 'input: '; }
</style>

or compare (short code):

<style type="text/css">
    div label { content: 'input: '; color: red; }
</style>

form....

<label class="lab" for="single"></label><input name="n" id="single" ...><label for="single"> - simle</label>

or compare (short code):

<div><label></label><input name="n" ...></div>
Caren answered 18/10, 2013 at 15:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.