CSS :after not adding content to certain elements - css

I'm having trouble understanding the behavior of the CSS :after property. According to the spec (here and here):
As their names indicate, the :before and :after pseudo-elements specify the location of content before and after an element's document tree content.
This doesn't seem to place restrictions on which elements can have a :after (or :before) property. However, it seems to only work with specific elements... <p> works, <img> doesn't, <input> doesn't, <table> does. I'm could test more, but the point is made. Note that this seems pretty consistent across browsers. What determines whether an object can accept a :before and :after property?

img and input are both replaced elements.
A replaced element is any element whose appearance and dimensions are
defined by an external resource. Examples include images (<img> tags),
plugins (<object> tags), and form elements (<button>, <textarea>,
<input>, and <select> tags). All other elements types can be referred
to as non-replaced elements.
:before and :after only work with non-replaced elements.
From the spec:
Note. This 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.
With span:before, span:after, the DOM looks like this:
<span><before></before>Content of span<after></after></span>
Evidently, that won't work with <img src="" />.

:before and :after are not required to work for replaced elements, and CSS specifications do not specify how they would work for them, and the concept of replaced element is somewhat vague.
The CSS 2.1 specification clearly suggests that they can work for replaced elements, just saying that it does not “fully define” how. This relates to the issue that a replaced element is expected to have its own visual rendering, which is not controlled by CSS, whereas the pseudo-elements should add something to the content of the element. The spec adds that this will be defined “in more detail” in a future specification, but this has not taken place so far.
Browser vendors just decided to avoid problems by not implementing these pseudo-elements for some elements at all.
It is not clear at all what “replaced element” means, and the meaning appears to have changed somewhat. It is often interpreted as meaning the same as empty element (an element with EMPTY declared content, i.e. an element that cannot have any content), but CSS 2.1 itself shows a sample style sheet with the selector br:before (though browsers have ignored this, implementing br their own way). It can be argued that more and more elements have moved into the scope of CSS rendering, at least in part. For example, an input element (incuding its font, colors, etc.) is largely controllable with CSS in modern browsers.
Current browsers (Firefox, IE, Chrome) do not seem to support the :after and :before pseudo-elements for empty elements other than hr. For hr, IE and Chrome place the generated content inside a bordered box, which is the implementation of hr; the content makes the box taller. Firefox places the content of both (!) pseudo-elements after the horizontal rule that is its implementation of hr. This variation illustrates the kinds of “interaction” problems that are referred to in CSS 2.1.
It is often claimed that these pseudo-elements cannot be used for empty elements since their HTML definitions do not allow any content. This is a category error. The syntax rules of a markup language do not restrict what you can do in CSS
To conclude, :after and :before are currently not usable for empty elements (except marginally for hr), but this is mainly due to implementations and may change in the future.

I've spent several hours plucking out my hair only to find that some other css override content (or display:none) property of my selector.
For example, if the following code is written in some other place, before or after element will never show:
#id > child:before {
content: none!important;
}
<html>
<div id="id" class="class">
<child>
Before element is not showing
</child>
</div>
<style>
child:before {
content: 'before';
color: 'red';
}
</style>
</html>
Just find the css which is overwriting your style and spam stronger selectors and !important to make it work
#id>child:before {
content: none!important;
}
<html>
<div id="id" class="class">
<child>
Before element is <strong>showing</strong>
</child>
</div>
<style>
#id.class>child:before {
content: 'before'!important;
border: 1px solid red;
}
</style>
</html>

<img> is a replaced element and using :before or :after pseudo-elements on it works if the image fails to load and otherwise it does not work. If you intend to have a fallback in case of image load failure, the following css useful:
img{
position: relative;
}
img:after{
position: absolute;
content: "Any allowed type of content including a fallback image";
left: 0;
}
For a good example, please refer to https://css-tricks.com/7-practical-uses-for-the-before-and-after-pseudo-elements-in-css/

Elements that doesn't have closing tag are void elements and they can't display content inside them:
https://www.w3.org/TR/html5/syntax.html#void-elements
All Blink, Webkit and Quantum browsers allow you to create pseudo elements only on checkboxes but this is controversial since no spec allow this behavior.
Here an example:
https://codepen.io/equinusocio/pen/BOBaEM/
input[type="checkbox"] {
appearance: none;
color: #000;
width: 42px;
height: 24px;
border: 1px solid currentColor;
border-radius: 100px;
cursor: pointer;
transition: all 100ms;
background-size: 30%;
outline: none;
position: relative;
box-sizing: border-box;
background-color: #eee;
transition: background-color 200ms;
&::before {
content: '';
position: absolute;
left: 2px;
top: 2px;
bottom: 2px;
height: 18px;
width: 18px;
border-radius: 50%;
background-color: currentColor;
will-change: transform;
transition: transform 200ms cubic-bezier(.01,.65,.23,1);
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
}
&:checked {
background-color: aquamarine;
&::before {
transform: translateX(100%);
}
}
}

Related

Issue double selector CSS input:not(:placeholder-shown)::before [duplicate]

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.
:before and :after render inside a container
and <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...
W3C specification
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.
:after and :before are not supported in Internet Explorer 7 and under, on any elements.
It's also not meant to be used on replaced elements such as form elements (inputs) and image elements.
In other words it's impossible with pure CSS.
However if using jquery you can use
$(".mystyle").after("add your smiley here");
API docs on .after
To append your content with javascript. This will work across all browsers.
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.
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 {
display: inline;
color: red;
}
.field_with_errors input+span:after {
content: "*"
}
<div class="field_with_errors">Label:</div>
<div class="field_with_errors">
<input type="text" /><span></span>
</div>
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
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
}
View on Codepen
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.
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>
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 }
A working solution in pure CSS:
The trick is to suppose there's a dom element after the text-field.
/*
* The trick is here:
* this selector says "take the first dom element after
* the input text (+) and set its before content to the
* value (:before).
*/
input#myTextField + *:before {
content: "👍";
}
<input id="myTextField" class="mystyle" type="text" value="someValue" />
<!--
There's maybe something after a input-text
Does'nt matter what it is (*), I use it.
-->
<span></span>
(*) Limited solution, though:
you have to hope that there's a following dom element,
you have to hope no other input field follows your input field.
But in most cases, we know our code so this solution seems efficient and 100% CSS and 0% jQuery.
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>
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.
As others explained, inputs 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.
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;
}
try next:
label[for="userName"] {
position: relative;
}
label[for="userName"]::after {
content: '[after]';
width: 22px;
height: 22px;
display: inline-block;
position: absolute;
right: -30px;
}
<label for="userName">
Name:
<input type="text" name="userName" id="userName">
</label>
The question mentions "input field". Although I believe the OP was referring to input field with type=text, ::after and ::before pseudocontent does render for several different types of input fields:
input::before {
content: "My content" /* 11 different input types will render this */
}
Here is a comprehensive demo of all input types, clearly showing which ones are compatible with (in this case) the ::before pseudoelement.
To summarize, this is a list of all of the input types that can render pseudocontent:
checkbox
color
date
datetime-local
file
image
month
radio
range
time
week
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 only works for nodes that can have child nodes since they insert a new node as the first or last node.
I found that you can do it like this:
.submit .btn input
{
padding:11px 28px 12px 14px;
background:#004990;
border:none;
color:#fff;
}
.submit .btn
{
border:none;
color:#fff;
font-family: 'Open Sans', sans-serif;
font-size:1em;
min-width:96px;
display:inline-block;
position:relative;
}
.submit .btn:after
{
content:">";
width:6px;
height:17px;
position:absolute;
right:36px;
color:#fff;
top:7px;
}
<div class="submit">
<div class="btn">
<input value="Send" type="submit" />
</div>
</div>
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.
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;
}
While the explanations that point out that the Firefox behavior of not allowing ::after and ::before content for elements that can't display any content are quite correct, it still seems to work perfectly fine with this rule:
input[type=checkbox] {
-moz-appearance: initial;
}
As ::after is the only way to restyle a checkbox or radiobox without introducing more and unrelated markup like a trailing span or label, I think it's fine to force Firefox to allow ::before and ::after content to be displayed, despite not being to spec.
Example of switcher with after and before
just wrap your input on div block
.fm-form-control {
position: relative;
margin-top: 25px;
margin-bottom: 25.2px;
}
.fm-switcher {
display: none;
}
.fm-switcher:checked + .fm-placeholder-switcher:after {
background-color: #94c6e7;
}
.fm-switcher:checked + .fm-placeholder-switcher:before {
left: 24px;
}
.fm-switcher[disabled] + .fm-placeholder-switcher {
cursor: not-allowed;
}
.fm-switcher[disabled] + .fm-placeholder-switcher:before {
background-color: #cbd0d3;
}
.fm-switcher[disabled] + .fm-placeholder-switcher:after {
background-color: #eaeded;
border-color: #cbd0d3;
}
.fm-placeholder-switcher {
padding-left: 53px;
cursor: pointer;
line-height: 24px;
}
.fm-placeholder-switcher:before {
position: absolute;
content: '';
left: 0;
top: 50%;
width: 20px;
height: 20px;
margin-top: -10px;
margin-left: 2px;
background-color: #2980b9;
z-index: 2;
-moz-transition: all 0.15s ease-in-out;
-o-transition: all 0.15s ease-in-out;
-webkit-transition: all 0.15s ease-in-out;
transition: all 0.15s ease-in-out;
border-radius: 12px;
}
.fm-placeholder-switcher:after {
position: absolute;
content: '';
left: 0;
top: 50%;
width: 48px;
height: 20px;
margin-top: -12px;
background-color: #ffffff;
z-index: 1;
border-radius: 12px;
border: 2px solid #bdc3c7;
-moz-transition: all 0.15s ease-in-out;
-o-transition: all 0.15s ease-in-out;
-webkit-transition: all 0.15s ease-in-out;
transition: all 0.15s ease-in-out;
}
<div class='fm-form-control'>
<input class='fm-switcher' id='switcher_id' type='checkbox'>
<label class='fm-placeholder-switcher' for='switcher_id'>
Switcher
</label>
</div>

:active::after doesn't work (pseudo element for pseudo class) [duplicate]

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.
:before and :after render inside a container
and <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...
W3C specification
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.
:after and :before are not supported in Internet Explorer 7 and under, on any elements.
It's also not meant to be used on replaced elements such as form elements (inputs) and image elements.
In other words it's impossible with pure CSS.
However if using jquery you can use
$(".mystyle").after("add your smiley here");
API docs on .after
To append your content with javascript. This will work across all browsers.
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.
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 {
display: inline;
color: red;
}
.field_with_errors input+span:after {
content: "*"
}
<div class="field_with_errors">Label:</div>
<div class="field_with_errors">
<input type="text" /><span></span>
</div>
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
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
}
View on Codepen
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.
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>
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 }
A working solution in pure CSS:
The trick is to suppose there's a dom element after the text-field.
/*
* The trick is here:
* this selector says "take the first dom element after
* the input text (+) and set its before content to the
* value (:before).
*/
input#myTextField + *:before {
content: "👍";
}
<input id="myTextField" class="mystyle" type="text" value="someValue" />
<!--
There's maybe something after a input-text
Does'nt matter what it is (*), I use it.
-->
<span></span>
(*) Limited solution, though:
you have to hope that there's a following dom element,
you have to hope no other input field follows your input field.
But in most cases, we know our code so this solution seems efficient and 100% CSS and 0% jQuery.
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>
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.
As others explained, inputs 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.
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;
}
try next:
label[for="userName"] {
position: relative;
}
label[for="userName"]::after {
content: '[after]';
width: 22px;
height: 22px;
display: inline-block;
position: absolute;
right: -30px;
}
<label for="userName">
Name:
<input type="text" name="userName" id="userName">
</label>
The question mentions "input field". Although I believe the OP was referring to input field with type=text, ::after and ::before pseudocontent does render for several different types of input fields:
input::before {
content: "My content" /* 11 different input types will render this */
}
Here is a comprehensive demo of all input types, clearly showing which ones are compatible with (in this case) the ::before pseudoelement.
To summarize, this is a list of all of the input types that can render pseudocontent:
checkbox
color
date
datetime-local
file
image
month
radio
range
time
week
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 only works for nodes that can have child nodes since they insert a new node as the first or last node.
I found that you can do it like this:
.submit .btn input
{
padding:11px 28px 12px 14px;
background:#004990;
border:none;
color:#fff;
}
.submit .btn
{
border:none;
color:#fff;
font-family: 'Open Sans', sans-serif;
font-size:1em;
min-width:96px;
display:inline-block;
position:relative;
}
.submit .btn:after
{
content:">";
width:6px;
height:17px;
position:absolute;
right:36px;
color:#fff;
top:7px;
}
<div class="submit">
<div class="btn">
<input value="Send" type="submit" />
</div>
</div>
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.
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;
}
While the explanations that point out that the Firefox behavior of not allowing ::after and ::before content for elements that can't display any content are quite correct, it still seems to work perfectly fine with this rule:
input[type=checkbox] {
-moz-appearance: initial;
}
As ::after is the only way to restyle a checkbox or radiobox without introducing more and unrelated markup like a trailing span or label, I think it's fine to force Firefox to allow ::before and ::after content to be displayed, despite not being to spec.
Example of switcher with after and before
just wrap your input on div block
.fm-form-control {
position: relative;
margin-top: 25px;
margin-bottom: 25.2px;
}
.fm-switcher {
display: none;
}
.fm-switcher:checked + .fm-placeholder-switcher:after {
background-color: #94c6e7;
}
.fm-switcher:checked + .fm-placeholder-switcher:before {
left: 24px;
}
.fm-switcher[disabled] + .fm-placeholder-switcher {
cursor: not-allowed;
}
.fm-switcher[disabled] + .fm-placeholder-switcher:before {
background-color: #cbd0d3;
}
.fm-switcher[disabled] + .fm-placeholder-switcher:after {
background-color: #eaeded;
border-color: #cbd0d3;
}
.fm-placeholder-switcher {
padding-left: 53px;
cursor: pointer;
line-height: 24px;
}
.fm-placeholder-switcher:before {
position: absolute;
content: '';
left: 0;
top: 50%;
width: 20px;
height: 20px;
margin-top: -10px;
margin-left: 2px;
background-color: #2980b9;
z-index: 2;
-moz-transition: all 0.15s ease-in-out;
-o-transition: all 0.15s ease-in-out;
-webkit-transition: all 0.15s ease-in-out;
transition: all 0.15s ease-in-out;
border-radius: 12px;
}
.fm-placeholder-switcher:after {
position: absolute;
content: '';
left: 0;
top: 50%;
width: 48px;
height: 20px;
margin-top: -12px;
background-color: #ffffff;
z-index: 1;
border-radius: 12px;
border: 2px solid #bdc3c7;
-moz-transition: all 0.15s ease-in-out;
-o-transition: all 0.15s ease-in-out;
-webkit-transition: all 0.15s ease-in-out;
transition: all 0.15s ease-in-out;
}
<div class='fm-form-control'>
<input class='fm-switcher' id='switcher_id' type='checkbox'>
<label class='fm-placeholder-switcher' for='switcher_id'>
Switcher
</label>
</div>

img::after not displaying when img src is included [duplicate]

I'm having trouble understanding the behavior of the CSS :after property. According to the spec (here and here):
As their names indicate, the :before and :after pseudo-elements specify the location of content before and after an element's document tree content.
This doesn't seem to place restrictions on which elements can have a :after (or :before) property. However, it seems to only work with specific elements... <p> works, <img> doesn't, <input> doesn't, <table> does. I'm could test more, but the point is made. Note that this seems pretty consistent across browsers. What determines whether an object can accept a :before and :after property?
img and input are both replaced elements.
A replaced element is any element whose appearance and dimensions are
defined by an external resource. Examples include images (<img> tags),
plugins (<object> tags), and form elements (<button>, <textarea>,
<input>, and <select> tags). All other elements types can be referred
to as non-replaced elements.
:before and :after only work with non-replaced elements.
From the spec:
Note. This 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.
With span:before, span:after, the DOM looks like this:
<span><before></before>Content of span<after></after></span>
Evidently, that won't work with <img src="" />.
:before and :after are not required to work for replaced elements, and CSS specifications do not specify how they would work for them, and the concept of replaced element is somewhat vague.
The CSS 2.1 specification clearly suggests that they can work for replaced elements, just saying that it does not “fully define” how. This relates to the issue that a replaced element is expected to have its own visual rendering, which is not controlled by CSS, whereas the pseudo-elements should add something to the content of the element. The spec adds that this will be defined “in more detail” in a future specification, but this has not taken place so far.
Browser vendors just decided to avoid problems by not implementing these pseudo-elements for some elements at all.
It is not clear at all what “replaced element” means, and the meaning appears to have changed somewhat. It is often interpreted as meaning the same as empty element (an element with EMPTY declared content, i.e. an element that cannot have any content), but CSS 2.1 itself shows a sample style sheet with the selector br:before (though browsers have ignored this, implementing br their own way). It can be argued that more and more elements have moved into the scope of CSS rendering, at least in part. For example, an input element (incuding its font, colors, etc.) is largely controllable with CSS in modern browsers.
Current browsers (Firefox, IE, Chrome) do not seem to support the :after and :before pseudo-elements for empty elements other than hr. For hr, IE and Chrome place the generated content inside a bordered box, which is the implementation of hr; the content makes the box taller. Firefox places the content of both (!) pseudo-elements after the horizontal rule that is its implementation of hr. This variation illustrates the kinds of “interaction” problems that are referred to in CSS 2.1.
It is often claimed that these pseudo-elements cannot be used for empty elements since their HTML definitions do not allow any content. This is a category error. The syntax rules of a markup language do not restrict what you can do in CSS
To conclude, :after and :before are currently not usable for empty elements (except marginally for hr), but this is mainly due to implementations and may change in the future.
I've spent several hours plucking out my hair only to find that some other css override content (or display:none) property of my selector.
For example, if the following code is written in some other place, before or after element will never show:
#id > child:before {
content: none!important;
}
<html>
<div id="id" class="class">
<child>
Before element is not showing
</child>
</div>
<style>
child:before {
content: 'before';
color: 'red';
}
</style>
</html>
Just find the css which is overwriting your style and spam stronger selectors and !important to make it work
#id>child:before {
content: none!important;
}
<html>
<div id="id" class="class">
<child>
Before element is <strong>showing</strong>
</child>
</div>
<style>
#id.class>child:before {
content: 'before'!important;
border: 1px solid red;
}
</style>
</html>
<img> is a replaced element and using :before or :after pseudo-elements on it works if the image fails to load and otherwise it does not work. If you intend to have a fallback in case of image load failure, the following css useful:
img{
position: relative;
}
img:after{
position: absolute;
content: "Any allowed type of content including a fallback image";
left: 0;
}
For a good example, please refer to https://css-tricks.com/7-practical-uses-for-the-before-and-after-pseudo-elements-in-css/
Elements that doesn't have closing tag are void elements and they can't display content inside them:
https://www.w3.org/TR/html5/syntax.html#void-elements
All Blink, Webkit and Quantum browsers allow you to create pseudo elements only on checkboxes but this is controversial since no spec allow this behavior.
Here an example:
https://codepen.io/equinusocio/pen/BOBaEM/
input[type="checkbox"] {
appearance: none;
color: #000;
width: 42px;
height: 24px;
border: 1px solid currentColor;
border-radius: 100px;
cursor: pointer;
transition: all 100ms;
background-size: 30%;
outline: none;
position: relative;
box-sizing: border-box;
background-color: #eee;
transition: background-color 200ms;
&::before {
content: '';
position: absolute;
left: 2px;
top: 2px;
bottom: 2px;
height: 18px;
width: 18px;
border-radius: 50%;
background-color: currentColor;
will-change: transform;
transition: transform 200ms cubic-bezier(.01,.65,.23,1);
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
}
&:checked {
background-color: aquamarine;
&::before {
transform: translateX(100%);
}
}
}

webkit css pseudo elements for time field

I've found an interesting post about webkit pseudo elements for inputs here, so I was going to remove the cancel button from input type="time". But by murthy's law exactly this pseudo element is not described anywhere.
P.S. I already tryed
::-webkit-search-cancel-button
::-webkit-input-cancel-button
::-webkit-time-cancel-button
::-webkit-time-cancel-button
Of course there is a way to do this with :after element, but I don't believe there is no pseudo element for this
input[type="time"]::after
{
content: "";
background: #FFF;
height: 20px;
width: 10px;
position: absolute;
margin: 0 -10px;
}
That would be ::-webkit-clear-button
So use
input[type="time"]::-webkit-clear-button{
display:none;
}
To find such things you can enable Show Shadow DOM from the console options, under Elements.
This way when you select the input element, you can open it and look under the hood..
I knew that Internet Explorer 10 supports such a pseudo-element with ::-ms-clear.
So I searched in the source code of Chromium for "webkit-clear" and discovered the presence of ::-webkit-clear-button.
This JSFiddle shows that the ::-webkit-clear-button pseudo-element has the desired effect.
input[type="time"]::-webkit-clear-button {
display: none;
}

Can I have multiple :before pseudo-elements for the same element?

Is it possible to have multiple :before pseudos for the same element?
.circle:before {
content: "\25CF";
font-size: 19px;
}
.now:before{
content: "Now";
font-size: 19px;
color: black;
}
I am trying to apply the above styles to the same element using jQuery, but only the most recent one is applied, never both of them.
In CSS2.1, an element can only have at most one of any kind of pseudo-element at any time. (This means an element can have both a :before and an :after pseudo-element — it just cannot have more than one of each kind.)
As a result, when you have multiple :before rules matching the same element, they will all cascade and apply to a single :before pseudo-element, as with a normal element. In your example, the end result looks like this:
.circle.now:before {
content: "Now";
font-size: 19px;
color: black;
}
As you can see, only the content declaration that has highest precedence (as mentioned, the one that comes last) will take effect — the rest of the declarations are discarded, as is the case with any other CSS property.
This behavior is described in the Selectors section of CSS2.1:
Pseudo-elements behave just like real elements in CSS with the exceptions described below and elsewhere.
This implies that selectors with pseudo-elements work just like selectors for normal elements. It also means the cascade should work the same way. Strangely, CSS2.1 appears to be the only reference; neither css3-selectors nor css3-cascade mention this at all, and it remains to be seen whether it will be clarified in a future specification.
If an element can match more than one selector with the same pseudo-element, and you want all of them to apply somehow, you will need to create additional CSS rules with combined selectors so that you can specify exactly what the browser should do in those cases. I can't provide a complete example including the content property here, since it's not clear for instance whether the symbol or the text should come first. But the selector you need for this combined rule is either .circle.now:before or .now.circle:before — whichever selector you choose is personal preference as both selectors are equivalent, it's only the value of the content property that you will need to define yourself.
If you still need a concrete example, see my answer to this similar question.
The legacy css3-content specification contains a section on inserting multiple ::before and ::after pseudo-elements using a notation that's compatible with the CSS2.1 cascade, but note that that particular document is obsolete — it hasn't been updated since 2003, and no one has implemented that feature in the past decade. The good news is that the abandoned document is actively undergoing a rewrite in the guise of css-content-3 and css-pseudo-4. The bad news is that the multiple pseudo-elements feature is nowhere to be found in either specification, presumably owing, again, to lack of implementer interest.
If your main element has some child elements or text, you could make use of it.
Position your main element relative (or absolute/fixed) and use both :before and :after positioned absolute (in my situation it had to be absolute, don't know about your's).
Now if you want one more pseudo-element, attach an absolute :before to one of the main element's children (if you have only text, put it in a span, now you have an element), which is not relative/absolute/fixed.
This element will start acting like his owner is your main element.
HTML
<div class="circle">
<span>Some text</span>
</div>
CSS
.circle {
position: relative; /* or absolute/fixed */
}
.circle:before {
position: absolute;
content: "";
/* more styles: width, height, etc */
}
.circle:after {
position: absolute;
content: "";
/* more styles: width, height, etc */
}
.circle span {
/* not relative/absolute/fixed */
}
.circle span:before {
position: absolute;
content: "";
/* more styles: width, height, etc */
}
I've resolved this using:
.element:before {
font-family: "Font Awesome 5 Free" , "CircularStd";
content: "\f017" " Date";
}
Using the font family "font awesome 5 free" for the icon, and after, We have to specify the font that we are using again because if we doesn't do this, navigator will use the default font (times new roman or something like this).
You can also use an image/icon plus text in the content field
e.g.
p.album-title::after {
content: url('https://...camera-icon-blue.png') ' View >';
display: block;
...;
}
In ::after css set content:'any text' and add backgroun-image with svg text from external svg file url(anySvgText.svg) or inline svg code url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" height="30" width="200"><text x="0" y="15" fill="black" style="font-family: tahoma;">any second text</text></svg>')
Also you can use only svg instead content value. but you must set empty string (content: '') to display a ::after style
.circle:before {
content: "\25CF";
font-size: 19px;
color: red;
width: 200px;
display: block;
background-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" height="30" width="200"><text x="0" y="15" fill="black" style="font-family: tahoma;">Now</text></svg>');
background-position-x: 15px;
}
<div class="circle"></div>

Resources