Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
CSS only custom-styled select Todd Parker - Filament Group Inc. How this works: 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 majori…
<html>
<head>
<title>Select styles with CSS only</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
body {
background-color: #fff;
font-family: helvetica, sans-serif;
margin: 4% 10%
}
label {
display:block;
margin-top:2em;
font-size: 0.9em;
color:#777;
}
.dropdown {
position: relative;
display:block;
margin-top:0.5em;
overflow:hidden;
width:100%;
max-width:100%;
}
select {
/* Make sure the select is wider than the container so we can clip the arrow */
width:110%;
max-width:110%;
min-width:110%;
/* Remove select styling */
appearance: none;
-webkit-appearance: none;
/* Ugly Firefox way of doing it */
-moz-appearance: window;
text-indent: 0.01px;
text-overflow: "";
/* Magic font size number to prevent iOS text zoom */
font-size:16px;
font-weight: bold;
background:none;
border: none;
color: #444;
outline: none;
/* Padding works surpringly well */
padding: .4em 19% .4em .8em;
font-family: helvetica, sans-serif;
line-height:1.2;
margin:.2em;
}
/* This hides native dropdown button arrow in IE */
select::-ms-expand {
display: none;
}
/* Custom arrow - could be an image, SVG, icon font, etc. */
.dropdown:after {
background: none;
color: #bbb;
content: "\25BC";
font-size: .7em;
padding:0;
position: absolute;
right: 1em;
top: 1.2em;
bottom: .3em;
z-index: 1;
/* This hack makes the select behind the arrow clickable in some browsers */
pointer-events:none;
}
/* Hover style - tricky because we're clipping the overflow */
.dropdown:hover {
border:1px solid #888;
}
/* Focus style */
select:focus {
outline: none;
box-shadow: 0 0 3px 3px rgba(180,222,250, .85);
}
/* This hides focus around selected option in FF */
select:-moz-focusring {
color: transparent;
text-shadow: 0 0 0 #000;
}
/* 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 */
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ffffff', endColorstr='#e5e5e5',GradientType=0 ); /* IE6-9 */
}
</style>
</head>
<body>
<h1>CSS only custom-styled select</h1>
<h4><a href="https://twitter.com/toddmparker">Todd Parker</a> - <a href="http://www.filamentgroup.com">Filament Group Inc.</a></h4>
<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>
<p>Opera, Firefox and older IE don't allow you to consistently style away the select arrow so we're setting the select width to 110% and clipping it with <code>overflow:hidden</code> on the parent. We then add extra right padding on the native select so the text won't run over the custom arrow or be clipped by the wrapper.</p>
<label class="wrapper">This label wraps the select
<div class="button dropdown">
<select>
<option>Apples</option>
<option>Bananas</option>
<option>Grapes</option>
<option>Oranges</option>
<option selected>A very long option name to test wrapping and visual collisions</option>
</select>
</div>
</label>
<label class="wrapper" for="states">This label is stacked above the select</label>
<div class="button dropdown" id="states">
<select>
<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">This is in a container set to 50% width
<div class="button dropdown">
<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 select in place. Worst case, the native selct styling and hte custom arrow will both show up, or the text won't be perfectly aligned but in all populat platforms, this looks very consistent. One minr caveat: setting the select to 110% means the meanu may open up a bit wider than expected. We set a style to set it to 100% on focus, but thsi doesn't seem to take effect everywhere.</p>
<ul>
<li>iOS 4- 7 - looks good, iOS3 even works fine but isn't quite as pretty</li>
<li>Android 2.3 (Browser) - looks good</li>
<li>Android 4.3 (Chrome) - looks good</li>
<li>WP8 - looks good</li>
<li>WP7.8 (missing arrow, double border but works)</li>
<li>Kindle Fire HD - looks good</li>
<li>IE 6- 9 (no customarrow), good on 10 - 11</li>
<li>Safari 5 Mac - looks good</li>
<li>Chrome latest - looks good</li>
<li>Firefox latest, 3.6 - looks good</li>
<li>Firefox OS - shows custom and default arrows</li>
<li>Opera - looks perfect</li>
<li>Opera Mini - alignment of text and arrows is a bit off but it works</li>
<li>Nokia Asha - Long options can break outside the box</li>
</ul>
</body>
</html>
@pyk

This comment has been minimized.

Copy link

pyk commented Oct 8, 2014

for those who want quickly see the demo of this gist http://jsbin.com/telegu/1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.