How to Use the CSS Pseudo-Element :Before{ Content: '' } to Affect an <Option> Element

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



Leave a reply



Submit