Skip to content

Instantly share code, notes, and snippets.

Created May 4, 2016 18:31
Show Gist options
  • Save anonymous/5beb17ff95db7ec9ed4f5775b23240d4 to your computer and use it in GitHub Desktop.
Save anonymous/5beb17ff95db7ec9ed4f5775b23240d4 to your computer and use it in GitHub Desktop.
Select styles with CSS only // source http://jsbin.com/horebic
<!doctype html>
<html>
<head>
<title>Select styles with CSS only</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
/* Some basic page styles */
body {
background-color: #fff;
font-family: helvetica, sans-serif;
margin: 4% 10%
}
/* Label styles: style as needed */
label {
display:block;
margin-top:2em;
font-size: 0.9em;
color:#777;
}
/* Container used for styling the custom select */
.custom-select {
position: relative;
display:block;
margin-top:0.5em;
padding:0;
}
/* Button "theme" styles, style as you like */
.button {
border: 1px solid #bbb;
border-radius: .3em;
box-shadow: 0 1px 0 1px rgba(0,0,0,.04);
background: #f3f3f3;
background: -moz-linear-gradient(top, #ffffff 0%, #e5e5e5 100%);
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#ffffff), color-stop(100%,#e5e5e5));
background: -webkit-linear-gradient(top, #ffffff 0%,#e5e5e5 100%);
background: -o-linear-gradient(top, #ffffff 0%,#e5e5e5 100%);
background: -ms-linear-gradient(top, #ffffff 0%,#e5e5e5 100%);
background: linear-gradient(to bottom, #ffffff 0%,#e5e5e5 100%);
}
/* Native select: make everything but the text invisible */
.custom-select select {
width:100%;
margin:0;
background:0 0;
border: 1px solid transparent;
outline: none;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
/* Font size must the 16px or larger to prevent iOS page zoom on focus */
font-size:16px;
font-family: helvetica, sans-serif;
font-weight: normal;
color: #444;
padding: .3em .6em .2em .7em;
line-height:1.3;
}
/* Custom arrow pseudo sits over the select */
.custom-select::after {
content: " ";
width: 0;
height: 0;
border-left: 4px solid transparent;
border-right: 4px solid transparent;
border-top: 7px solid #666;
position: absolute;
top: 50%;
right: 1em;
z-index: 2;
margin-top: -3px;
/* These hacks make the select behind the arrow clickable in some browsers */
pointer-events:none;
display:none;
}
/* Only kick in these styles if the browser supports appearance */
@supports ( -webkit-appearance: none ) or ( -moz-appearance: none ) or ( appearance: none ) {
/* Show custom arrow */
.custom-select::after {
display: block;
}
/* Remove select styling */
.custom-select select {
appearance: none;
-webkit-appearance: none;
-moz-appearance:none;
}
/* TODO: Figure out why old FF is showing the custom arrow with hacks removed, this negates it for now */
@-moz-document url-prefix() {
.custom-select::after {
display:none;
}
}
}
/* Hover style */
.custom-select:hover {
border:1px solid #888;
}
/* Focus style */
.custom-select select:focus {
outline:none;
box-shadow: 0 0 1px 3px rgba(180,222,250, 1);
background-color:transparent;
color: #222;
border:1px solid #aaa;
}
/* ------------------------------------------- */
/* START OF UGLY BROWSER-SPECIFIC HACKS */
/* DELETE IF YOU'RE OK WITH ALL IE AND FF <35 */
/* DISPLAYING NATIVE SELECT ARROWS */
/* -------------------------------------------- */
/* FIREFOX */
/* Firefox won't let us hide the native select arrow, so we have to make it wider than needed and clip it via overflow on the parent container. The percentage width is a fallback since FF 4+ supports calc() so we can just add a fixed amount of extra width to push the native arrow out of view. We're applying this hack across all FF versions because all the previous hacks were too fragile and complex. You might want to consider not using this hack and using the native select arrow in FF. Note this makes the menus wider than the select button because they display at the specified width and aren't clipped. Targeting hack via http://browserhacks.com/#hack-758bff81c5c32351b02e10480b5ed48e */
/* Show only the native arrow */
@-moz-document url-prefix() {
.custom-select {
overflow: hidden;
}
/* Make the native select extra wide so the arrow is clipped */
.custom-select select {
overflow: -moz-hidden-unscrollable;
width: calc(100% + 2.4em);
}
.custom-select::after {
display:block;
}
/* Firefox 35+ supports styling the native select, no need for the overflow clip trick */
@supports ( mask-type: alpha ) {
.custom-select select {
-moz-appearance: none;
width: 100%;
padding-right: 1em;
}
}
}
/* Firefox focus has odd artifacts around the text, this kills that. See https://developer.mozilla.org/en-US/docs/Web/CSS/:-moz-focusring */
.custom-select select:-moz-focusring {
color: transparent;
text-shadow: 0 0 0 #000;
}
/* INTERNET EXPLORER */
/* IE 8/9 shows the native select arrow and the custom arrow which is bad. This hides the custom arrow in IE8/9 but also kills it in Android and Safari 4. See below for the Android/Safari fix. Targeting hack: http://browserhacks.com/#hack-a60b03e301a67f76a5a22221c739dc64 */
@media screen and (min-width:0\0) {
.custom-select::after {
display:none;
}
}
/* Special double layered hack to un-negate the hack above to restore Android and Safari 4. Targeting hack: http://browserhacks.com/#hack-f4ade0540d8e891e8190065f75acb186 */
.custom-select:not(*:root)::after {
display:block;
}
/* IE 10/11+ - This hides native dropdown button arrow so it will have the custom appearance. Targeting media query hack via http://browserhacks.com/#hack-28f493d247a12ab654f6c3637f6978d5 - looking for better ways to achieve this targeting */
@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) {
.custom-select select::-ms-expand {
display: none;
}
/* Show custom arrow */
.custom-select::after {
display:block;
}
/* Removes the odd blue bg color behind the text in the select button - fix via http://stackoverflow.com/questions/17553300/change-ie-background-color-on-unopened-focused-select-box */
.custom-select select:focus::-ms-value {
background: transparent;
color: #222;
}
}
/* ------------------------------------ */
/* END OF UGLY BROWSER-SPECIFIC HACKS */
/* ------------------------------------ */
/* Demo style: no arrow for multi-line */
.noarrow .custom-select::after {
display:none;
}
</style>
</head>
<body>
<h1>CSS-only custom-styled selects v9</h1>
<h4><a href="http://www.filamentgroup.com">Filament Group Inc.</a> - <a href="https://github.com/filamentgroup/select-css">Select CSS repo</a></h4>
<p><strong>Last updated Feb 26, 2016:</strong>Firefox 35 finally implemented <code>-moz-appearance:none</code> to make the native select invisible. For older FF versions, we can use <code>-moz-calc()</code> which works back to FF4 to over-size the select by 1.5em to make things looks great back to FF4. Qualify styles inside a support block.</p>
<p><Strong>How this works:</strong> This styles a <b>native</b> select consistently cross-platform with only minimal CSS. The native select is styled so it is essentially invisible (no appearance, border, bg) leaving only the select's text visible. There is a wrapper around the select that has the majority of the button styles (gradient, shadow, border, etc.). We then add the custom arrow via a pseudo element to the right. </p>
<label>Native select</label>
<select style="width:200px">
<option>Apples</option>
<option>Bananas</option>
<option>Grapes</option>
<option>Oranges</option>
<option>A very long option name to test wrapping</option>
</select>
<div style="width:200px">
<label class="wrapper">Custom styled select
<div class="button custom-select">
<select>
<option>Apples</option>
<option>Bananas</option>
<option>Grapes</option>
<option>Oranges</option>
<option>A very long option name to test wrapping and visual collisions</option>
</select>
</div>
</label>
</div>
<label class="wrapper">This label wraps the select
<div class="button custom-select">
<select>
<option>Apples</option>
<option>Bananas</option>
<option>Grapes</option>
<option>Oranges</option>
<option>A very long option name to test wrapping</option>
</select>
</div>
</label>
<label class="wrapper" for="states">This label is stacked above the select</label>
<div class="button custom-select">
<select id="states">
<option value="AL">Alabama</option>
<option value="AK">Alaska</option>
<option value="AZ">Arizona</option>
<option value="AR">Arkansas</option>
<option value="CA">California</option>
<option value="CO">Colorado</option>
<option value="CT">Connecticut</option>
<option value="DE">Delaware</option>
<option value="FL">Florida</option>
<option value="GA">Georgia</option>
<option value="HI">Hawaii</option>
<option value="ID">Idaho</option>
<option value="IL">Illinois</option>
<option value="IN">Indiana</option>
<option value="IA">Iowa</option>
<option value="KS">Kansas</option>
<option value="KY">Kentucky</option>
<option value="LA">Louisiana</option>
<option value="ME">Maine</option>
<option value="MD">Maryland</option>
<option value="MA">Massachusetts</option>
<option value="MI">Michigan</option>
<option value="MN">Minnesota</option>
<option value="MS">Mississippi</option>
<option value="MO">Missouri</option>
<option value="MT">Montana</option>
<option value="NE">Nebraska</option>
<option value="NV">Nevada</option>
<option value="NH">New Hampshire</option>
<option value="NJ">New Jersey</option>
<option value="NM">New Mexico</option>
<option value="NY">New York</option>
<option value="NC">North Carolina</option>
<option value="ND">North Dakota</option>
<option value="OH">Ohio</option>
<option value="OK">Oklahoma</option>
<option value="OR">Oregon</option>
<option value="PA">Pennsylvania</option>
<option value="RI">Rhode Island</option>
<option value="SC">South Carolina</option>
<option value="SD">South Dakota</option>
<option value="TN">Tennessee</option>
<option value="TX">Texas</option>
<option value="UT">Utah</option>
<option value="VT">Vermont</option>
<option value="VA">Virginia</option>
<option value="WA">Washington</option>
<option value="WV">West Virginia</option>
<option value="WI">Wisconsin</option>
<option value="WY">Wyoming</option>
</select>
</div>
<div style="width:50%; min-width:10em;">
<label class="wrapper">In 50% wide container
<div class="button custom-select">
<select>
<option>Apples</option>
<option>Bananas</option>
<option>Grapes</option>
<option>Oranges</option>
<option>A very long option name to test wrapping and visual collisions</option>
</select>
</div>
</label>
</div>
<div style="width:50%; min-width:10em;">
<label class="wrapper noarrow">Multiple select, multi-row
<div class="button custom-select">
<select size="4" multiple>
<option>Apples</option>
<option>Bananas</option>
<option>Grapes</option>
<option>Oranges</option>
<option>Lemons</option>
<option>Limes</option>
<option>Watermelon</option>
<option>Grapefruit</option>
<option>Strawberries</option>
<option>Raspberries</option>
</select>
</div>
</label>
</div>
<h2>Confirmed to work in the following browsers</h2>
<p>This technique seems to be functional everywhere since we're still leaving the native select in place. Worst case, the native select styling and the custom arrow will both show up but in all popular platforms, this looks very good and consistent. One minor caveat: setting the select to 110% means the menu may open up a bit wider than expected in Firefox. <a href="http://postimg.org/image/g7i0o6mr1/">Visual Test results</a></p>
<h3>Custom select styled consistently</h3>
<ul>
<li>iOS 4/5/6/7/8 - looks good, iOS3 even works fine but isn't quite as pretty</li>
<li>Android 2.2/2.3 (Browser) - looks good</li>
<li>Android 4.0/4.1/4.2 (Browser) - looks good</li>
<li>Android 4.0/4.1/4.2/4.3/4.4 (Chrome) - looks good</li>
<li>WP8 - looks good</li>
<li>Kindle Fire 2/HD - looks good</li>
<li>IE 10/11 - looks good</li>
<li>Safari 5 - looks good</li>
<li>Chrome 22-35 - looks good</li>
<li>Opera 15-22 - looks good</li>
</ul>
<h3>Custom select with minor visual issues</h3>
<ul>
<li>iOS3 even works fine but isn't quite as pretty</li>
<li>Firefox (version 4-34) - select menu when open is wider than it needs to be (by ~20px) to clip off the native arrow. Note that the select text can run under the arrow, no solution found for that.</li>
<li>Opera Mini - alignment of text and arrows is a bit off but it works</li>
<li>Opera Mobile - custom and native arrows both appear</li>
<li>Nokia Asha - Long options can break outside the box</li>
</ul>
<h3>Native select</h3>
<ul>
<li>WP 7.5-7.8 - native select</li>
<li>IE 6/7/8/9 - native select</li>
<li>Opera pre-14 - native select</li>
</ul>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment