problem with <select> and :after with CSS in WebKit - html

I would like to add some style on a select box with the pseudo :after (to style my select box with 2 parts and without images). Here's the HTML:
<select name="">
<option value="">Test</option>
</select>
And it doesn't work. I don't know why and I didn't find the answer in the W3C specs. Here's the CSS:
select {
-webkit-appearance: none;
background: black;
border: none;
border-radius: 0;
color: white;
}
select:after {
content: " ";
display: inline-block;
width: 24px; height: 24px;
background: blue;
}
So is it normal or is there a trick?

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.

I was looking for the same thing since the background of my select is the same as the arrow color. As previously mentioned, it is impossible yet to add anything using :before or :after on a select element. My solution was to create a wrapper element on which I added the following :before code.
.select-wrapper {
position: relative;
}
.select-wrapper:before {
content: '\f0d7';
font-family: FontAwesome;
color: #fff;
display: inline-block;
position: absolute;
right: 20px;
top: 15px;
pointer-events: none;
}
And this my select
select {
box-sizing: border-box;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
width: 100%;
padding: 10px 20px;
background: #000;
color: #fff;
border: none;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
}
select::-ms-expand {
display: none;
}
I have used FontAwesome.io for my new arrow, but you can use whatever else you want. Obviously this is not a perfect solution, but depending on your needs it might be enough.

To my experience it simply does not work, unless you are willing to wrap your <select> in some wrapper. But what you can do instead is to use background image SVG. E.g.
.archive .options select.opt {
-moz-appearance: none;
-webkit-appearance: none;
padding-right: 1.25EM;
appearance: none;
position: relative;
background-color: transparent;
background-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' version='1.1' height='10px' width='15px'%3E%3Ctext x='0' y='10' fill='gray'%3E%E2%96%BE%3C/text%3E%3C/svg%3E");
background-repeat: no-repeat;
background-size: 1.5EM 1EM;
background-position: right center;
background-clip: border-box;
-moz-background-clip: border-box;
-webkit-background-clip: border-box;
}
.archive .options select.opt::-ms-expand {
display: none;
}
Just be careful with proper URL-encoding because of IE. You must use charset=utf8 (not just utf8), don't use double-quotes (") to delimit SVG attribute values, use apostrophes (') instead to simplify your life. URL-encode s (%3E). In case you havee to print any non-ASCII characters you have to obtain their UTF-8 representation (e.g. BabelMap can help you with that) and then provide that representation in URL-encoded form - e.g. for ▾ (U+25BE BLACK DOWN-POINTING SMALL TRIANGLE) UTF-8 representation is \xE2\x96\xBE which is %E2%96%BE when URL-encoded.

What if modifying the markup isn't an option?
Here's a solution that has no requirements for a wrapper: it uses an SVG in a background-image.
You may need to use an HTML entity decoder to understand how to change the fill colour.
-moz-appearance: none;
-webkit-appearance: none;
appearance: none;
background-image: url('data:image/svg+xml;charset=US-ASCII,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22292.4%22%20height%3D%22292.4%22%3E%3Cpath%20fill%3D%22%23000000%22%20d%3D%22M287%2069.4a17.6%2017.6%200%200%200-13-5.4H18.4c-5%200-9.3%201.8-12.9%205.4A17.6%2017.6%200%200%200%200%2082.2c0%205%201.8%209.3%205.4%2012.9l128%20127.9c3.6%203.6%207.8%205.4%2012.8%205.4s9.2-1.8%2012.8-5.4L287%2095c3.5-3.5%205.4-7.8%205.4-12.8%200-5-1.9-9.2-5.5-12.8z%22%2F%3E%3C%2Fsvg%3E');
background-repeat: no-repeat;
background-position: right .7em top 50%;
background-size: .65em auto;
Pinched from CSS-Tricks.

Faced the same problem. Probably it could be a solution:
<select id="select-1">
<option>One</option>
<option>Two</option>
<option>Three</option>
</select>
<label for="select-1"></label>
#select-1 {
...
}
#select-1 + label:after {
...
}

This post may help http://bavotasan.com/2011/style-select-box-using-only-css/
He is using a outside div with a class for resolving this issue.
<div class="styled-select">
<select>
<option>Here is the first option</option>
<option>The second option</option>
</select>
</div>

This solution is similar to the one from sroy, but with css triangle instead of web font:
.select-wrapper {
position: relative;
width: 200px;
}
.select-wrapper:after {
content: "";
width: 0;
height: 0;
border-left: 5px solid transparent;
border-right: 5px solid transparent;
border-top: 6px solid #666;
position: absolute;
right: 8px;
top: 8px;
pointer-events: none;
}
select {
background: #eee;
border: 0 !important;
border-radius: 0;
-webkit-appearance:none;
-moz-appearance:none;
appearance:none;
text-indent: 0.01px;
text-overflow: "";
font-size: inherit;
line-height: inherit;
width: 100%;
}
select::-ms-expand {
display: none;
}
<div class="select-wrapper">
<select>
<option value="1">option 1</option>
<option value="2">option 2</option>
<option value="3">option 3</option>
</select>
</div>

This is a modern solution I cooked up using font-awesome. Vendor extensions have been omitted for brevity.
HTML
<fieldset>
<label for="color">Select Color</label>
<div class="select-wrapper">
<select id="color">
<option>Red</option>
<option>Blue</option>
<option>Yellow</option>
</select>
<i class="fa fa-chevron-down"></i>
</div>
</fieldset>
SCSS
fieldset {
.select-wrapper {
position: relative;
select {
appearance: none;
position: relative;
z-index: 1;
background: transparent;
+ i {
position: absolute;
top: 40%;
right: 15px;
}
}
}
If your select element has a defined background color, then this won't work as this snippet essentially places the Chevron icon behind the select element (to allow clicking on top of the icon to still initiate the select action).
However, you can style the select-wrapper to the same size as the select element and style its background to achieve the same effect.
Check out my CodePen for a working demo that shows this bit of code on both a dark and light themed select box using a regular label and a "placeholder" label and other cleaned up styles such as borders and widths.
P.S. This is an answer I had posted to another, duplicate question earlier this year.

<div class="select">
<select name="you_are" id="dropdown" class="selection">
<option value="0" disabled selected>Select</option>
<option value="1">Student</option>
<option value="2">Full-time Job</option>
<option value="2">Part-time Job</option>
<option value="3">Job-Seeker</option>
<option value="4">Nothing Yet</option>
</select>
</div>
Insted of styling the select why dont you add a div out-side the select.
and style then in CSS
.select{
width: 100%;
height: 45px;
position: relative;
}
.select::after{
content: '\f0d7';
position: absolute;
top: 0px;
right: 10px;
font-family: 'Font Awesome 5 Free';
font-weight: 900;
color: #0b660b;
font-size: 45px;
z-index: 2;
}
#dropdown{
-webkit-appearance: button;
-moz-appearance: button;
appearance: button;
height: 45px;
width: 100%;
outline: none;
border: none;
border-bottom: 2px solid #0b660b;
font-size: 20px;
background-color: #0b660b23;
box-sizing: border-box;
padding-left: 10px;
padding-right: 10px;
}

Instead of a wrapper element you can use CSS grid and place an icon (or whatever) in the same cell as the select:
.select-field {
display: grid;
grid-template:
"label"
"select"
/ max-content;
}
.label {
grid-area: label;
}
.select {
appearance: none;
background: white;
border: 1px solid var(--border-color);
grid-area: select;
padding-block: 0.5ex;
padding-inline: 1ch calc(1ch + 1em);
}
.after {
align-self: center;
border-block-start: 0.5em solid var(--border-color);
border-inline: 0.5em solid transparent;
block-size: 0;
grid-area: select;
inline-size: 0;
justify-self: end;
margin-inline-end: 1ch;
pointer-events: none;
}
.select,
.select + .after {
--border-color: silver;
}
.select:hover,
.select:hover + .after {
--border-color: grey;
}
.select:focus,
.select:focus + .after {
--border-color: rebeccapurple;
}
<div class="select-field">
<label for="my-select" class="label">Select One</label>
<select id="my-select" class="select">
<option value="foo">Foo</option>
<option value="bar">Bar</option>
<option value="baz">Baz</option>
</select>
<div class="after"></div>
</div>
Here I used an empty div to and styled it to be a CSS triangle which has the same color as the border which changes during hover/focus.
The most important bits here are the following:
The <select> and the <div class="after"> go into the same grid-area (which I named select). This will put the empty div over the select.
Give the <select> an appearance of none. This will remove any browser default style.
Give the <select> and extra padding at the end of the inline direction to make room for the empty style.
Justify the empty div to the end.
Give the empty div an extra margin at the end of the inline direction which matches your desired padding of the <select>
Give the empty div a pointer-events of none so the click will go through it to the <select> element.
Other then that you can do whatever with the empty div. It doesn’t even have to be empty. E.g. you can put an svg icon in there if you want.

If you chose to use the select::after method, remember that:
.select::after{
...
pointer-events: none;
...
for clickable..

Related

Style the dropdown arrow design

I have a select field in my form and I want to style the field arrow. I want to add a color background to the arrow (not for all fields) and change the position.
The arrow is located in the end of field now. I've tried to add css to the field but it doesn't work
I've tried the following:
.wpcf7-select:after {
content: '\25BC';
position: absolute;
top: 0;
right: 0;
bottom: 0;
font-size: 25px;
border: 1px solid #565656;
background: #0e7b53;
color: #fff;
padding: 11px 15px;
pointer-events: none;
}
input,
select {
height: 62px;
width: 100%;
background: #20232C;
border: none;
padding-right: 0px;
padding-left: 30px;
color: #fff;
}
.wpcf7-form-control-wrap {
position: relative;
}
span {
margin: 0;
padding: 0;
border: 0;
outline: 0;
}
<span class="wpcf7-form-control-wrap" data-name="menu-173">
<select name="menu-173" class="wpcf7-form-control wpcf7-select" aria-invalid="false">
<option value="test">test</option>
<option value="1">1</option>
<option value="2">2</option>
</select>
</span>
This thread details how to hide the default arrow on most browsers (not IE9 and below though), and add your own stylable arrow.
Snippet from linked thread.
Please read the thread to understand what this code entails.
select {
margin: 50px;
width: 150px;
padding: 5px 35px 5px 5px;
font-size: 16px;
border: 1px solid #CCC;
height: 34px;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
background: url(https://stackoverflow.com/favicon.ico) 96% / 15% no-repeat #EEE;
}
/* CAUTION: Internet Explorer hackery ahead */
select::-ms-expand {
display: none; /* Remove default arrow in Internet Explorer 10 and 11 */
}
/* Target Internet Explorer 9 to undo the custom arrow */
#media screen and (min-width:0\0) {
select {
background: none\9;
padding: 5px\9;
}
}
<select>
<option>Apples</option>
<option selected>Pineapples</option>
<option>Chocklate</option>
<option>Pancakes</option>
</select>

Bad dropdown arrow styling on firefox and safari

My dropdowns look like the left on Chrome, but looks like the right on Firefox and Safari
How can I style my dropdown to look like the chrome version on safari and firefox? I don't like the grey background for the caret that shows on firefox
(I would also like to move the caret symbol a little bit to the left)
This is my css and html for the dropdown. You can click "Run code snippet" on firefox and see that it looks like the one on the right.
select{
box-shadow: 0 0 0.2rem rgba(0, 0, 0, 0.7);
border-radius: 1rem;
padding: 0.25rem 0.5rem;
border: 0;
}
select:active, select:focus{
outline: none;
}
<select type="dropdown">
<option>Option 1</option>
<option>Option 2</option>
</select>
You should reset default styling and add your custom style that is uniform across browsers. This below snippet should help
select{
box-shadow: 0 0 0.2rem rgba(0, 0, 0, 0.7);
border-radius: 1rem;
padding-top: 0.25rem;
padding-bottom: 0.25rem;
padding-right: 1rem;
padding-left: 0.5rem;
border: 0;
appearance: none;
-moz-appearance: none;
-webkit-appearance: none;
background-image: url('data:image/svg+xml;charset=US-ASCII,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22292.4%22%20height%3D%22292.4%22%3E%3Cpath%20fill%3D%22%23007CB2%22%20d%3D%22M287%2069.4a17.6%2017.6%200%200%200-13-5.4H18.4c-5%200-9.3%201.8-12.9%205.4A17.6%2017.6%200%200%200%200%2082.2c0%205%201.8%209.3%205.4%2012.9l128%20127.9c3.6%203.6%207.8%205.4%2012.8%205.4s9.2-1.8%2012.8-5.4L287%2095c3.5-3.5%205.4-7.8%205.4-12.8%200-5-1.9-9.2-5.5-12.8z%22%2F%3E%3C%2Fsvg%3E');
background-repeat: no-repeat, repeat;
background-position: right .7em top 50%;
background-size: .65em auto;
}
<select type="dropdown">
<option>Option 1</option>
<option>Option 2</option>
</select>
Read more from this blog post: https://css-tricks.com/styling-a-select-like-its-2019/
select{
box-shadow: 0 0 0.2rem rgba(0, 0, 0, 0.7);
border-radius: 1rem;
padding-top: 0.25rem;
padding-bottom: 0.25rem;
padding-right: 1.5rem; /* increased to make space for arrow*/
padding-left: 0.5rem;
border: 0;
appearance: none; /* remove default arrow */
outline: none; /* looks better without outline */
}
.custom-select {
position: relative; /* container for pseudo element */
display: inline-block; /* make width to fit content */
}
.custom-select::after {
content: '⌄';
position: absolute;
background: transparent;
right: 10%;
top: -10%;
pointer-events: none; /* let clicks go through */
}
<div class="custom-select">
<select type="dropdown">
<option>Option 1</option>
<option>Option 2</option>
</select>
</div>
This is a really easy and effective way, consistent on every browser.
HTML:
Add a wrapper on select element
CSS:
Set appearance:none and increase padding-right accordingly on select element.
Set the wrapper position: relative; and display: inline-block; to make it as a container for an absolute positioned pseudo element.
Style and position the wrapper::after element how you prefer, with pointer-events:none so that your clicks will go through it, opening the select.

select not adding pseudo after selector

I want to add a font-awesome arrow to my select but the :after selector does not appear to be being applied:
The focus is not being applied either for some reason.
select {
border: 1px solid #727272;
-webkit-appearance: none;
border-radius: 0;
width: 50%;
padding: 10px;
}
.select:after {
content: "\F0DA";
font-family: FontAwesome;
font-size: 20px;
color: black;
}
select:focus: {
outline: 3px solid #ffbf47 !important;
outline-offset: 0;
}
<div>
<select class="select">
<option>One</option>
<option>Two</option>
</select>
</div>
As i said in comment you can not use pseudo on select instead wrap your select with a div then use pseudo on it.
select {
border: 1px solid #727272;
-webkit-appearance: none;
border-radius: 0;
width: 100%;
padding: 10px;
}
.select-option {
position: relative;
width: 50%;
}
.select-option::after {
content: "\F0DA";
font-family: FontAwesome;
font-size: 20px;
color: black;
position: absolute;
right: 10px;
top: 7px;
}
select:focus {
outline: 3px solid #ffbf47 !important;
outline-offset: 0;
}
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" integrity="sha384-wvfXpqpZZVQGK6TAh5PVlGOfQNHSoD2xbE+QkPxCAFlNEevoEH3Sl0sibVcOQVnN" crossorigin="anonymous">
<div class="select-option">
<select class="select">
<option>One</option>
<option>Two</option>
</select>
</div>
If you want to use this arrow instead of default select option arrow on your select you need set position: absolute for ::after element.
.select-option::after {
content: "\F0DA";
font-family: FontAwesome;
font-size: 20px;
color: black;
position: absolute;
right: 10px;
top: 7px;
}
Don't forget to set position: relative on parent .select-option and i change your code a little for move width: 50% to parent and set width: 100% on select.
And note that, correct is ::after not :after. CSS3 introduced the ::after notation (with two colons) to distinguish pseudo-classes from pseudo-elements. Browsers also accept :after, introduced in CSS2.
More info here.
And last word is, this is a common issue that you can't set ::after or ::before on select option possible there are many topics with this title, google, stackoverflow and etc.. anyway.

html remove the default select option arrow with extra space from options

I have a select option markup like this
<div class="styleselect">
<select onchange="setLocation(this.value)" class="selections">
<option selected="selected" value="position">Position</option>
<option value="name">Name</option>
<option value="price">Price</option>
</select>
</div>
Here I want to style the default arrow of select option and I changed my css like this
.styleselect {
background-color: #DFD3C3;
background-image: url("http://s21.postimg.org/nx05vn15f/dropdown_style.png");
background-position: 117px center;
background-repeat: no-repeat;
border: 1px solid #C5AF8A;
overflow: hidden;
vertical-align: middle;
width: 140px;
padding: 0;
margin: 0;
display: inline-block;
}
.styleselect select {
background-color: transparent;
margin: 0 0 1px;
padding: 4px;
vertical-align: middle;
width: 190px;
}
It worked fine. But again I got one problem that when I made click on the options the options came with the extra width from the actual width where it is looking really odd. I know that the extra width is coming from the width .styleselect select where I have put extra width. But that has been donefor the styling the arrow. Can someone kindly tell me how to fix the extrawidth so that the my custom arrow should come in place for default arrow in the select options and the extra width for the options will be also hide. The link for fiddle is here
Any help and suggestions will be really appreciable. Thanks
Here you go... I have added the same color for options also just to have an uniform look for the control. Hope it helps.
CSS code :
select{
appearance:none; -moz-appearance:none; -webkit-appearance: none;
}
.styleselect {
background-color: #DFD3C3;
background-image: url("http://s21.postimg.org/nx05vn15f/dropdown_style.png");
background-position: 117px center;
background-repeat: no-repeat;
border: 1px solid #C5AF8A;
overflow: hidden;
vertical-align: middle;
width: 140px;
padding: 0;
margin: 0;
display: inline-block;
}
.styleselect select {
background-color: transparent;
margin: 0 0 1px;
padding: 4px;
vertical-align: middle;
width: 140px;
}
.styleselect select option{
background-color: #DFD3C3;
overflow: hidden;
vertical-align: middle;
width: 140px;
padding: 0;
margin: 0;
display: inline-block;
}
Styling the select is cumbersome. You may get browser issues. But you can use advance plugin for styling select box like http://ivaynberg.github.io/select2/. This also provide lots of other features.
.styleselect select {
width=auto;
}

Pseudo element stopping event click

I am customizing select box by using css :after Attribute.
Html:
<div class="styled">
<select>
<option>India, Rupees (Rs.)</option>
<option>USA, Dollars ($) </option>
<option>United Kingdom, Pounds (£)</option>
</select>
</div>
css:
div.styled{
display: inline-block;
float: left;
position: relative;
border-right: 1px solid #CCC;
border-radius: 3px;
box-shadow: 1px 1px 1px #ddd;
}
.styled select option{
padding: 5px;
}
div.styled:after{
content: "";
background: #fff url("dn_arw.png") no-repeat 2px 4px;
display: inline-block;
float: left;
height: 18px;
position: absolute;
right: 8px;
top: 6px;
width: 15px;
}
The below is the image and js fiddle
http://jsfiddle.net/CtYnt/
The Problem is the area which is overlapped with "down arrow image" is not clickable
To make it work in Chrome, Firefox and Safari, you can use one line of CSS in the :after block:
pointer-events: none;
IE takes more work, the easiest way is to use conditional statement for IE on the :after block and set:
display:none;
Alternatively if your overlayed DIV MUST work in IE, there is a hack detailed here.