Skip to content

Instantly share code, notes, and snippets.

@joseph-turner
Created February 19, 2015 17:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save joseph-turner/a1e5c0782743a8b3f156 to your computer and use it in GitHub Desktop.
Save joseph-turner/a1e5c0782743a8b3f156 to your computer and use it in GitHub Desktop.
CSS Selects
<h1>CSS-only custom-styled selects v7</h1>
<h4><a href="https://twitter.com/toddmparker">Todd Parker</a> - <a href="http://www.filamentgroup.com">Filament Group Inc.</a></h4>
<p><strong>NOTE:</strong> This is still an experiement and are currently refining the targeting and styles for IE and Firefox. Once everything is settled, we will do a post on the Filament Group site. We're debating whether the tower of hacks is worth it for Firefox because it still doesn't have a reliable way to hide the native select's arrow and new versions can break this. Stay tuned.</p>
<p><Strong>How this works:</strong> This styles a native select consistently cross-platform with only minimal CSS. The native select is then 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>
<option>Apples</option>
<option>Bananas</option>
<option>Grapes</option>
<option>Oranges</option>
<option selected>A very long option name to test wrapping</option>
</select>
<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>
<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. We set a style to set it to 100% on focus, but this doesn't seem to take effect everywhere.</p>
<h3>Custom select styled consistently</h3>
<ul>
<li>iOS 4/5/6/7 - 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>Firefox 7-30 - 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 6 - looks good but has the native + custom arrow</li>
<li>Firefox OS - shows custom and default arrows, minor issue</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>Firefox 3-6 - native select</li>
<li>Firefox OS - shows custom and default arrows</li>
<li>Opera pre-14 - native select</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>
v.38
/* 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, the buttom class adds the bg gradient, corners, etc. */
.custom-select {
position: relative;
display:block;
margin-top:0.5em;
padding:0;
}
/* This is the native select, we're making everything but the text invisible so we can see the button styles in the wrapper */
.custom-select select {
width:100%;
margin:0;
background:none;
border: 1px solid transparent;
outline: none;
/* Prefixed box-sizing rules necessary for older browsers */
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
/* Remove select styling */
appearance: none;
-webkit-appearance: none;
/* Magic font size number to prevent iOS text zoom */
font-size:16px;
/* General select styles: change as needed */
font-family: helvetica, sans-serif;
font-weight: bold;
color: #444;
padding: .6em 1.9em .5em .8em;
line-height:1.3;
}
/* Custom arrow sits on top of the select - could be an image, SVG, icon font, etc. or the arrow could just baked into the bg image on the select */
.custom-select::after {
content: "";
position: absolute;
width: 9px;
height: 8px;
top: 50%;
right: 1em;
margin-top:-4px;
background-image: url(http://filamentgroup.com/files/select-arrow.png);
background-repeat: no-repeat;
background-size: 100%;
z-index: 2;
/* These hacks make the select behind the arrow clickable in some browsers */
pointer-events:none;
}
/* IE 10/11+ - This hides native dropdown button arrow so it will have the custom appearance, IE 9 and earlier get a native select - targeting hack via http://browserhacks.com/#hack-f1070533535a12744a0381a75087a915 */
_:-ms-input-placeholder, :root .custom-select select::-ms-expand {
display: none;
}
/* Removes the odd blue bg color behind the text in the select button in IE 10/11 and sets the text color to match the focus style's - fix via http://stackoverflow.com/questions/17553300/change-ie-background-color-on-unopened-focused-select-box */
_:-ms-input-placeholder, :root .custom-select select:focus::-ms-value {
background: transparent;
color: #222;
}
/* Firefox >= 2 -- Older versions of FF (v2 - 6) won't let us hide the native select arrow, so we'll just hide the custom icon and go with native styling. Targeting hack via http://browserhacks.com/#hack-756739b33c37fb7db4cce645bbf7ea5f */
/* Show only the native arrow */
body:last-child .custom-select::after, x:-moz-any-link {
display: none;
}
/* reduce padding */
body:last-child .custom-select select, x:-moz-any-link {
padding-right: .8em;
}
/* Firefox 6+ -- Hide the native select and arrow. We've found the simplest way to hide the native styling in FF is to make the select bigger than its container and clip it. */
/* The specific FF selector used below successfully overrides the previous rule that turns off the custom icon; other FF hacky selectors we tried, like `*>.custom-select::after`, did not undo the previous rule. Targeting hack via http://browserhacks.com/#hack-443a4eb168ccf066e7c2909be4911af1 */
/* Show the custom arrow again */
_::-moz-progress-bar, body:last-child .custom-select:after {
display: block;
}
/* Hacks to hide the native select appearance */
_::-moz-progress-bar, body:last-child .custom-select select {
-moz-appearance: window;
text-indent: 0.01px;
text-overflow: "";
/* increase padding to make room for menu icon */
padding-right: 13%;
}
/* In FF 30+ -- Set overflow:hidden on the wrapper to clip the native select's arrow. Need to get extra wide (120%) because newest Firefox/Android is terrible. The downside is this makes the menu 20% wider than it should be when it opens. Hack targeting via http://browserhacks.com/#hack-cfd4c21603b122acfda8e81f41cdb320 */
@supports (-moz-appearance:meterbar) and (background-blend-mode:difference,normal) {
/* Clip select with the container */
_::-moz-progress-bar, body:last-child .custom-select {
overflow: hidden;
}
/* Make select extra wide */
_::-moz-progress-bar, body:last-child .custom-select select {
width: 120%;
}
}
/* Firefox 7+ focus style - This works around the issue that -moz-appearance: window kills the normal select focus. Using semi-opaque because outline doesn't handle rounded corners */
_::-moz-progress-bar, body:last-child .custom-select select:focus {
outline: 2px solid rgba(180,222,250, .7);
}
/* Opera - Pre-Blink nix the custom arrow, go with a native select button */
x:-o-prefocus, .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;
}
/* Firefox focus has odd artifacts around the text, this kills that */
.custom-select select:-moz-focusring {
color: transparent;
text-shadow: 0 0 0 #000;
}
.custom-select option {
font-weight:normal;
}
/* These are just demo button-y 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; /* Old browsers */
background: -moz-linear-gradient(top, #ffffff 0%, #e5e5e5 100%); /* FF3.6+ */
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#ffffff), color-stop(100%,#e5e5e5)); /* Chrome,Safari4+ */
background: -webkit-linear-gradient(top, #ffffff 0%,#e5e5e5 100%); /* Chrome10+,Safari5.1+ */
background: -o-linear-gradient(top, #ffffff 0%,#e5e5e5 100%); /* Opera 11.10+ */
background: -ms-linear-gradient(top, #ffffff 0%,#e5e5e5 100%); /* IE10+ */
background: linear-gradient(to bottom, #ffffff 0%,#e5e5e5 100%); /* W3C */
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment