I am trying to use the :after
CSS pseudo-element on an input
field, but it does not work. If I use it with a span
, it works OK.
<style type="text/css">
.mystyle:after {content:url(smiley.gif);}
.mystyle {color:red;}
</style>
This works (puts the smiley after "buu!" and before "some more")
<span class="mystyle">buuu!</span>a some more
This does not work - it only colors someValue in red, but there is no smiley.
<input class="mystyle" type="text" value="someValue">
What am I doing wrong? should I use another pseudo-selector?
Note: I cannot add a span
around my input
, because it is being generated by a third-party control.
This question is related to
html
css
pseudo-element
css-content
Oddly, it works with some types of input. At least in Chrome,
<input type="checkbox" />
works fine, same as
<input type="radio" />
It's just type=text
and some others that don't work.
You have to have some kind of wrapper around the input to use a before or after pseudo-element. Here's a fiddle that has a before on the wrapper div of an input and then places the before inside the input - or at least it looks like it. Obviously, this is a work around but effective in a pinch and lends itself to being responsive. You can easily make this an after if you need to put some other content.
Working Fiddle
Dollar sign inside an input as a pseudo-element: http://jsfiddle.net/kapunahele/ose4r8uj/1/
The HTML:
<div class="test">
<input type="text"></input>
</div>
The CSS:
input {
margin: 3em;
padding-left: 2em;
padding-top: 1em;
padding-bottom: 1em;
width:20%;
}
.test {
position: relative;
background-color: #dedede;
display: inline;
}
.test:before {
content: '$';
position: absolute;
top: 0;
left: 40px;
z-index: 1;
}
I found that you can do it like this:
.submit .btn input_x000D_
{_x000D_
padding:11px 28px 12px 14px;_x000D_
background:#004990;_x000D_
border:none;_x000D_
color:#fff;_x000D_
}_x000D_
_x000D_
.submit .btn_x000D_
{_x000D_
border:none;_x000D_
color:#fff;_x000D_
font-family: 'Open Sans', sans-serif;_x000D_
font-size:1em;_x000D_
min-width:96px;_x000D_
display:inline-block;_x000D_
position:relative;_x000D_
}_x000D_
_x000D_
.submit .btn:after_x000D_
{_x000D_
content:">";_x000D_
width:6px;_x000D_
height:17px;_x000D_
position:absolute;_x000D_
right:36px;_x000D_
color:#fff;_x000D_
top:7px;_x000D_
}
_x000D_
<div class="submit">_x000D_
<div class="btn">_x000D_
<input value="Send" type="submit" />_x000D_
</div>_x000D_
</div>
_x000D_
You need to have a div parent that takes the padding and the :after. The first parent needs to be relative and the second div should be absolute so you can set the position of the after.
If you are trying to style an input element with :before and :after, odds are you are trying to mimic the effects of other span, div, or even a elements in your CSS stack.
As Robert Koritnik's answer points out, :before and :after can only be applied to container elements and input elements are not containers.
HOWEVER, HTML 5 introduced the button element which is a container and behaves like an input[type="submit|reset"] element.
<style>
.happy:after { content:url(smiley.gif); }
</style>
<form>
<!-- won't work -->
<input class="happy" type="submit" value="Submit" />
<!-- works -->
<button class="happy">Submit</button>
</form>
:before
and :after
render inside a containerand <input> can not contain other elements.
Pseudo-elements can only be defined (or better said are only supported) on container elements. Because the way they are rendered is within the container itself as a child element. input
can not contain other elements hence they're not supported. A button
on the other hand that's also a form element supports them, because it's a container of other sub-elements.
If you ask me, if some browser does display these two pseudo-elements on non-container elements, it's a bug and a non-standard conformance. Specification directly talks about element content...
If we carefully read the specification it actually says that they are inserted inside a containing element:
Authors specify the style and location of generated content with the :before and :after pseudo-elements. As their names indicate, the :before and :after pseudo-elements specify the location of content before and after an element's document tree content. The 'content' property, in conjunction with these pseudo-elements, specifies what is inserted.
See? an element's document tree content. As I understand it this means within a container.
The biggest misunderstanding here is the meaning of the words before
and after
. They do not refer to the element itself, but to the content in the element. So element:before
is before the content, and element:after
is after the content, but both are still inside the original element.
The input
element has no content in the CSS view, and so has no :before
or :after
pseudo content. This is true of many other void or replaced elements.
There is no pseudo element referring to outside the element.
In a different universe, these pseudo elements might have been called something else to make this distinction clearer. And someone might even have proposed a pseudo element which is genuinely outside the element. So far, this is not the case in this universe.
As others explained, input
s are kinda-replaced void elements, so most browsers won't allow you to generate ::before
nor ::after
pseudo-elements in them.
However, the CSS Working Group is considering explicitly allowing ::before
and ::after
in case the input
has appearance: none
.
From https://lists.w3.org/Archives/Public/www-style/2016Mar/0190.html,
Safari and Chrome both allow pseudo-elements on their form inputs. Other browsers don't. We looked into removing this, but the use-counter is recording ~.07% of pages using it, which is 20x our max removal threshold.
Actually specifying pseudo-elements on inputs would require specifying the internal structure of inputs at least somewhat, which we haven't managed to do yet (and I'm not confident we *can* do). But Boris suggested, in one of the bugthreads, allowing it on appearance:none inputs - basically just turning them into <div>s, rather than "kinda-replaced" elements.
:before
and :after
only works for nodes that can have child nodes since they insert a new node as the first or last node.
I used the background-image
to create the red dot for required fields.
input[type="text"][required] {
background-image: radial-gradient(red 15%, transparent 16%);
background-size: 1em 1em;
background-position: top right;
background-repeat: no-repeat
}
I found this post as I was having the same issue, this was the solution that worked for me. As opposed to replacing the input's value just remove it and absolutely position a span behind it that is the same size, the span can have a :before
pseudo class applied to it with the icon font of your choice.
<style type="text/css">
form {position: relative; }
.mystyle:before {content:url(smiley.gif); width: 30px; height: 30px; position: absolute; }
.mystyle {color:red; width: 30px; height: 30px; z-index: 1; position: absolute; }
</style>
<form>
<input class="mystyle" type="text" value=""><span class="mystyle"></span>
</form>
Summary
It does not work with <input type="button">
, but it works fine with <input type="checkbox">
.
Fiddle: http://jsfiddle.net/gb2wY/50/
HTML:
<p class="submit">
<input id="submit-button" type="submit" value="Post">
<br><br>
<input id="submit-cb" type="checkbox" checked>
</p>
CSS:
#submit-button::before,
#submit-cb::before {
content: ' ';
background: transparent;
border: 3px solid crimson;
display: inline-block;
width: 100%;
height: 100%;
padding: 0;
margin: -3px -3px;
}
According to a note in the CSS 2.1 spec, the specification “does not fully define the interaction of :before and :after with replaced elements (such as IMG in HTML). This will be defined in more detail in a future specification.” Although input
is not really a replaced element any more, the basic situation has not changed: the effect of :before
and :after
on it in unspecified and generally has no effect.
The solution is to find a different approach to the problem you are trying to address this way. Putting generated content into a text input control would be very misleading: to the user, it would appear to be part of the initial value in the control, but it cannot be modified – so it would appear to be something forced at the start of the control, but yet it would not be submitted as part of form data.
You can't put a pseudo element in an input element, but can put in shadow element, like a placeholder!
input[type="text"] {
&::-webkit-input-placeholder {
&:before {
// your code
}
}
}
To make it work in other browsers, use :-moz-placeholder
, ::-moz-placeholder
and :-ms-input-placeholder
in different selectors. Can't group the selectors, because if a browser doesn't recognize the selector invalidates the entire statement.
UPDATE: The above code works only with CSS pre-processor (SASS, LESS...), without pre-processors use:
input[type="text"]::-webkit-input-placeholder:before { // your code }
try next:
label[for="userName"] {_x000D_
position: relative;_x000D_
}_x000D_
_x000D_
label[for="userName"]::after {_x000D_
content: '[after]';_x000D_
width: 22px;_x000D_
height: 22px;_x000D_
display: inline-block;_x000D_
position: absolute;_x000D_
right: -30px;_x000D_
}
_x000D_
<label for="userName">_x000D_
Name: _x000D_
<input type="text" name="userName" id="userName">_x000D_
</label>
_x000D_
Here's another approach (assuming you have control of the HTML): add an empty <span></span>
right after the input, and target that in CSS using input.mystyle + span:after
.field_with_errors {_x000D_
display: inline;_x000D_
color: red;_x000D_
}_x000D_
.field_with_errors input+span:after {_x000D_
content: "*"_x000D_
}
_x000D_
<div class="field_with_errors">Label:</div>_x000D_
<div class="field_with_errors">_x000D_
<input type="text" /><span></span> _x000D_
</div>
_x000D_
I'm using this approach in AngularJS because it will add .ng-invalid
classes automatically to <input>
form elements, and to the form, but not to the <label>
.
:before
and :after
are applied inside a container, which means you can use it for elements with an end tag.
It doesn't apply for self-closing elements.
On a side note, elements which are self-closing (such as img/hr/input) are also known as 'Replaced Elements', as they are replaced with their respective content. "External Objects" for the lack of a better term. A better read here
Pseudo elements like :after
, :before
are only for container elements. Elements starting and closing in a single place like <input/>
, <img>
etc are not container elements and hence pseudo elements are not supported. Once you apply a pseudo element to container element like <div>
and if you inspect the code(see the image) you can understand what I mean. Actually the pseudo element is created inside the container element. This is not possible in case of <input>
or <img>
A working solution in pure CSS:
The trick is to suppose there's a dom element after the text-field.
/*_x000D_
* The trick is here:_x000D_
* this selector says "take the first dom element after_x000D_
* the input text (+) and set its before content to the_x000D_
* value (:before)._x000D_
*/_x000D_
input#myTextField + *:before {_x000D_
content: "";_x000D_
}
_x000D_
<input id="myTextField" class="mystyle" type="text" value="someValue" />_x000D_
<!--_x000D_
There's maybe something after a input-text_x000D_
Does'nt matter what it is (*), I use it._x000D_
-->_x000D_
<span></span>
_x000D_
(*) Limited solution, though:
But in most cases, we know our code so this solution seems efficient and 100% CSS and 0% jQuery.
Source: Stackoverflow.com