How can I use the CSS pseudo-element :before{ content: '' } to affect an option element?
The ::before
and ::after
pseudo-elements actually prepend/append a child node to the element, so this will not work on any element that cannot contain child nodes.
It would be (roughly) the equivalent of doing:
<option><span>sandy - </span>beach</option>
If you want to update the text value, you will need to use JavaScript.
Adding an :after element on select options
Short anwser
You can't add :pseudo
elements to inputs
and image
elements.
Alternative?
Well, you could use jquery
. But this still won't work on the option
element.
$("select").after("Hello");
Snippet
$("select").after("Hello");
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<select id="" name="" size="0" class="">
<option value="label_0" class=" level-label"></option>
<option value="241" class="has-no-children" selected="selected">White</option>
<option value="242" class="has-no-children">Black</option>
<option value="243" class="has-no-children">Red</option>
</select>
using :before with option element in a drop down list
You should be using a <label>
to indicate what the <select>
is for. You cannot use pseudo-elements on <option>
elements because only <option>
elements are valid within a <select>
. The other reason you wouldn't want to do this is because pseudo-elements are typically skipped by screen readers, making the label non-accessible to a portion or the population and certain assistive technologies.
This is the proper way to associate a label such as "Sort by" with a drop down list:
Demo
<label>
Sort by:
<select>
<option>one</option>
<option>two</option>
</select>
</label>
or
<label for="my-select">Sort by: </label>
<select id="my-select">
<option>one</option>
<option>two</option>
</select>
If you require "Sort by: " within the drop-down list, you should add that label within the HTML or inject it with JavaScript as CSS cannot do this. I would suggest arguing that it is not the right way to go with your designer however as you will have a bunch of redundant text and the drop-down will just look ugly.
This is how you would go about injecting the label within the drop-down using jQuery:
Demo
$('option').each(function () {
$(this).text("Sort by: " + $(this).text());
});
When is it allowed to style pseudo elements on an option element?
The short answer, if you're looking for a standards-based answer, is that CSS does not currently support using pseudo-elements with form elements, be it ::before
/::after
, or other pseudo-elements such as ::first-letter
. As a result, every browser does its own thing, and there is little to no interop.
As stated, there is no specification for the interaction between most pseudo-elements and form elements and/or replaced content The only statement in any spec for this is in css-content-3, which says:
Note: Replaced elements do not have ::before or ::after pseudo-elements; the content property replaces their entire contents.
But it gets worse: strictly speaking, form elements aren't the same thing as replaced content (despite many people, myself included, often stating the contrary), even though they behave very similarly. Form elements just happen to have platform-specific layout rules that prevent them from being completely styleable with CSS. They may support some common CSS properties and adhere to the box model to some extent, but they have limitations that prevent you from treating them fully as a regular, non-replaced element. This is really the only thing they have in common with replaced content.
To top it all off, the rendering of form elements is not covered in any current CSS spec. Work is being done to try and rein this all in in css-ui-4, but I'm not holding my breath.
Pseudo elements and SELECT tag
Well, it looks like the select
tags doesn't allow :after
or :before
pseudos because they are customized by each vendor, so it's quite hard to modify them and that's because they don't allow :before
or :after
pseudo elements on them.
To everyone who sees this, there's a good option to create a custom select
element with jQuery and minimal modification… Create a select and then use jQuery to edit it:
// Iterate over each select element
$('select').each(function() {
// Cache the number of options
var $this = $(this),
numberOfOptions = $(this).children('option').length;
// Hides the select element
$this.addClass('s-hidden');
// Wrap the select element in a div
$this.wrap('<div class="select"></div>');
// Insert a styled div to sit over the top of the hidden select element
$this.after('<div class="styledSelect"></div>');
// Cache the styled div
var $styledSelect = $this.next('div.styledSelect');
// Show the first select option in the styled div
$styledSelect.text($this.children('option').eq(0).text());
// Insert an unordered list after the styled div and also cache the list
var $list = $('<ul />', {
'class': 'options'
}).insertAfter($styledSelect);
// Insert a list item into the unordered list for each select option
for (var i = 0; i < numberOfOptions; i++) {
$('<li />', {
text: $this.children('option').eq(i).text(),
rel: $this.children('option').eq(i).val()
}).appendTo($list);
}
// Cache the list items
var $listItems = $list.children('li');
// Show the unordered list when the styled div is clicked (also hides it if the div is clicked again)
$styledSelect.click(function(e) {
e.stopPropagation();
$('div.styledSelect.active').each(function() {
$(this).removeClass('active').next('ul.options').hide();
});
$(this).toggleClass('active').next('ul.options').toggle();
});
// Hides the unordered list when a list item is clicked and updates the styled div to show the selected list item
// Updates the select element to have the value of the equivalent option
$listItems.click(function(e) {
e.stopPropagation();
$styledSelect.text($(this).text()).removeClass('active');
$this.val($(this).attr('rel'));
$list.hide();
/* alert($this.val()); Uncomment this for demonstration! */
});
// Hides the unordered list when clicking outside of it
$(document).click(function() {
$styledSelect.removeClass('active');
$list.hide();
});
});
body {
padding: 50px;
background-color: white;
}
.s-hidden {
visibility: hidden;
padding-right: 10px;
}
.select {
cursor: pointer;
display: inline-block;
position: relative;
font: normal 11px/22px Arial, Sans-Serif;
color: black;
border: 1px solid #ccc;
}
.styledSelect {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
background-color: white;
padding: 0 10px;
font-weight: bold;
}
.styledSelect:after {
content: "";
width: 0;
height: 0;
border: 5px solid transparent;
border-color: black transparent transparent transparent;
position: absolute;
top: 9px;
right: 6px;
}
.styledSelect:active,
.styledSelect.active {
background-color: #eee;
}
.options {
display: none;
position: absolute;
top: 100%;
right: 0;
left: 0;
z-index: 999;
margin: 0 0;
padding: 0 0;
list-style: none;
border: 1px solid #ccc;
background-color: white;
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
-moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
}
.options li {
padding: 0 6px;
margin: 0 0;
padding: 0 10px;
}
.options li:hover {
background-color: #39f;
color: white;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<select id="selectbox1">
<option value="">Select an option…</option>
<option value="aye">Aye</option>
<option value="eh">Eh</option>
<option value="ooh">Ooh</option>
<option value="whoop">Whoop</option>
</select>
<select id="selectbox2">
<option value="">Month…</option>
<option value="january">January</option>
<option value="february">February</option>
<option value="march">March</option>
<option value="april">April</option>
<option value="may">May</option>
<option value="june">June</option>
<option value="july">July</option>
<option value="august">August</option>
<option value="september">September</option>
<option value="october">October</option>
<option value="november">November</option>
<option value="december">December</option>
</select>
Selecting and manipulating CSS pseudo-elements such as ::before and ::after using javascript (or jQuery)
You could also pass the content to the pseudo element with a data attribute and then use jQuery to manipulate that:
In HTML:
<span>foo</span>
In jQuery:
$('span').hover(function(){
$(this).attr('data-content','bar');
});
In CSS:
span:after {
content: attr(data-content) ' any other text you may want';
}
If you want to prevent the 'other text' from showing up, you could combine this with seucolega's solution like this:
In HTML:
<span>foo</span>
In jQuery:
$('span').hover(function(){
$(this).addClass('change').attr('data-content','bar');
});
In CSS:
span.change:after {
content: attr(data-content) ' any other text you may want';
}
Select text in ::before or ::after pseudo-element
You can't, the before and after pseudo classes are not meant to be used for that purpose.
problem with select and :after with CSS in WebKit
I haven't checked this extensively, but I'm under the impression that this isn't (yet?) possible, due to the way in which select
elements are generated by the OS on which the browser runs, rather than the browser itself.
How can I prevent the ::before pseudo element from affecting my flex layout?
You can update your pseudo element, like this:
nav ul li.internal-nav.selected a:before,
nav ul li.internal-nav a:hover:before {
content: '> ';
position: absolute;
left: -1rem;
color: red;
}
nav ul li.internal-nav.selected a:before {
opacity: .6;
}
Run code snippet and open it on fullpage to see changes.
Also you can check it here (Codepen.io)
header {
margin-block-start: 3em;
padding-bottom: 0.67rem;
padding-left: 5%;
padding-right: 5%;
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
nav {
margin-left: auto;
}
nav ul {
list-style: none;
display: flex;
flex-direction: column;
padding-inline-start: 0;
padding-left: 1em;
}
nav ul li {
text-align: right;
font-size: x-large;
}
nav ul li a:hover {
color: red;
}
nav ul li.internal-nav a {
position: relative;
}
nav ul li.internal-nav.selected a:before,
nav ul li.internal-nav a:hover:before {
content: '> ';
position: absolute;
left: -1rem;
color: red;
}
nav ul li.internal-nav.selected a:before {
opacity: .6;
}
h1 {
color: rgba(0, 0, 0, 0.6);
font-size: 5em;
}
.profile-photo3 {
position: relative;
flex: 1;
min-width: 20rem;
background-color: blue;
clip-path: polygon(70% 0%, 100% 50%, 70% 100%, 0% 70%, 20% 15%);
}
.profile-photo3 img {
width: 100%;
mix-blend-mode: screen;
}
<head>
<script src="https://cpwebassets.codepen.io/assets/editor/iframe/iframeConsoleRunner-d0f3648046d2aaca07bd0037b9e061a26c74a8a999b75672ad6a638cca641472.js"></script>
<script src="https://cpwebassets.codepen.io/assets/editor/iframe/iframeRefreshCSS-4793b73c6332f7f14a9b6bba5d5e62748e9d1bd0b5c52d7af6376f3d1c625d7e.js"></script>
<script src="https://cpwebassets.codepen.io/assets/editor/iframe/iframeRuntimeErrors-4f205f2c14e769b448bcf477de2938c681660d5038bc464e3700256713ebe261.js"></script>
</head>
<body>
<header>
<h1>Dogs :)</h1>
<div class="profile-photo3"><img src="https://images.dog.ceo/breeds/collie-border/n02106166_2345.jpg"></div>
<nav>
<ul>
<li class="internal-nav"><a href="#">About Dogs</a></li>
<li class="internal-nav selected"><a href="#">My Fav Dogs</a></li>
<li class="internal-nav"><a href="#">Dog Facts</a></li>
</ul>
</nav>
</header>
<script src="https://cpwebassets.codepen.io/assets/common/stopExecutionOnTimeout-1b93190375e9ccc259df3a57c1abc0e64599724ae30d7ea4c6877eb615f89387.js"></script>
<script src="https://cdpn.io/cp/internal/boomboom/pen.js?key=pen.js-f2136278-4370-4b42-10b9-cde5fe228f8b" crossorigin=""></script>
</body>
CSS: How to affect :after Pseudo Element if Last-Child li gets hovered?
li:nth-child(4):hover
is already saying
li, which is the 4th element, which is being hovered
so li:nth-child(4):hover + li:last-child:after
is looking for a 5th li
sibling that immediately follows the 4th element and is also the last child.
li:nth-child(4):hover ~ li:last-child:after
is looking for a 5th li
sibling that is somewhere after the 4th element and is also the last child.
li:nth-child(4):hover > li:last-child:after
is looking for an li
that is a child of the 4th li
and is also a last child.
and li:nth-child(4):hover li:last-child:after
is looking for an li
that is a descendant of the 4th li
and is also a last child.
depending on what you're looking for you can either use:
li:nth-child(4):hover:after { transform: translatex(400px);}
li:last-child:hover:after { transform: translatex(400px);}
or li:nth-child(4):hover:last-child:after { transform: translatex(400px);}
if you want to be consistent with the other ones.
ul {
display: flex;
width: max-content;
list-style: none;
padding: 0;
margin: 0 auto;
}
a {
display: block;
width: 100px; height: 50px;
color: white;
background-color: orange;
}
/*Creating the pseudo element */
li:last-child:after {
content: '';
position: absolute;
top: 100px; left: 100px;
width: 50px; height: 50px;
background-color: red;
transition: transform 1s;
}
/*Creating the desired action for li childs 1 to 3*/
li:nth-child(1):hover ~ li:last-child:after { transform: translatex(100px);}
li:nth-child(2):hover ~ li:last-child:after { transform: translatex(200px);}
li:nth-child(3):hover ~ li:last-child:after { transform: translatex(300px);}
li:nth-child(4):hover:last-child:after { transform: translatex(400px);}
<div>
<ul>
<li><a href="#">Test 1</a></li>
<li><a href="#">Test 2</a></li>
<li><a href="#">Test 3</a></li>
<li><a href="#">Test 4</a></li>
</ul>
</div>
Related Topics
Selectable <Optgroup> in HTML <Select> Tag
How to Prevent Chrome from Changing Font When Autofilling Username/Password
Display:Table Versus Using Tables
How to Create Two HTML Buttons Side by Side
Display Two Images Side by Side on an HTML Page
How to Center Something If I Don't Know Ahead of Time What the Width Is
Darken a Background Image Without Affecting the Text
Different Colors in Placeholder
Fill Svg Element with With a Background-Image with an Offset
How to Freeze Header of the Page
HTML and CSS: Using Background Image as a Clickable Link
Why Are My Flex Items Not Wrapping
Thymeleaf - How to Apply Two (Or More) Styles Based on Mutually Exclusive Conditions
Placing a <Div> Within a <Canvas>