August 5, 2016
Create a Discreet "Dropdown" Menu
The select Element
The select
element is mainly associated with drop-down menus/lists. That's the default after all. You add a select element to a page and you see a white rectangle with an arrow pointing down at one end. You click on it, and based on the default behaviour you see a drop-down list of options for you to choose from.
This is the default behaviour on desktop browsers (and tablets?), but have you ever tabbed on a select
element on a mobile browser? There are 2 behaviours I've seen:
- Options displayed in a popup at the bottom of the screen (where the keyboard pops up)
- Options displayed in a popup at the centre of the screen
On mobile browsers, users see a list of options but not in a drop-down list. Tabbing the select
element when styled using its default styling (white rectangle with an arrow pointing down) doesn't trigger the expected behaviour based on its visual representation. The user doesn't get a drop-down list.
Besides, the W3C's definition of the select
element doesn't explicitly describe it as a drop-down list.
"The select element represents a control for selecting amongst a set of options."
So styling the select
element differently may make sense in some situations. Here's a semantically correct, pure CSS method to do just that.
What we will do
- Remove the default styling of the
select
element (including the arrow) - Position the
label
to overlap theselect
element and make it look clickable without affecting functionality or semantics (in reality the user will be clicking theselect
element not thelabel
)
1<div id="wrapper">2 <label for="select-options">Change</label>3 <select id="select-options">4 <option>Option 1</option>5 <option>Option 2</option>6 <option>Option 3</option>7 </select>8</div>
All you need is an explicit label
and the select
element itself (just like you would normally create it).
We need to edit the styling of their parent element. If your markup allows you to apply the below styles without affecting your page's layout, do so. Otherwise, you may need to add a div
wrapper.
Now we have an explicit text label using the label
element. And we have set the value of the for
attribute on the label
element to match the value of the id
attribute on the select
element. This is semantically correct and there shouldn't be accessibility concerns.
Parent Element
1.wrapper {2 position: relative;3 width: 300px;4}
For the parent element, in this case our div
wrapper, we set the position
property to relative because we will be applying absolute positioning for the label
. The width can be whatever suits your layout.
select Element
1select { 2 /* remove default styles */ 3 background: transparent; 4 border: none; 5 -webkit-appearance: none; 6 -moz-appearance: none; 7 appearance: none; 8 9 /* keep on top so it's clickable */10 position: relative;11 z-index: 99;12 cursor: pointer;13 14 /* padding-right to prevent text overlap with label */15 /* padding-bottom to assist with :focus styling */16 width: 100%;17 padding: 7px 70px 7px 0;18 19 /* some browsers support text wrap in select element */20 white-space: normal;21 font-size: 1em;22 line-height: 1.35;23}
Here we remove the default styles of the select
element. Setting the appearance
property to none is what removes the arrow.
Because we will be absolute positioning the label
in an overlapping manner, we have to increase the z-index of the select
element to make sure the user can interact with it. Setting the cursor to pointer makes it more user friendly on desktop browsers.
Adding some padding-right
will prevent the text of the select
element from overlapping with the label
. The padding-bottom
is needed for the styling of select:focus.
Setting white-space
to normal will make the text of the select
element wrap to another line if it's too long (doesn't work in all browsers).
Label
1label { 2 position: absolute; 3 top: 50%; 4 right: 0; 5 transform: translateY(-50%); 6 font-size: 0.8em; 7} 8 9.wrapper:hover label {10 color: #6feaa2;11}
We vertically centre the label
and position it to the right of the parent element.
The aim is to make the user think they can click/tab on the label
to select another option, but in reality they are clicking on the select
element. So you may want to style it to look like a button.
Note if you want to change the position of the label
, just make sure the select
element covers the new position (adjust height, width or padding).
Accessible & Tidy
By default browsers add an outline to focusable elements such as links and some input elements because of accessibility reasons. The outline provides a visual cue for users who are visually impaired or users who are unable to use a mouse. These users often rely on using the Tab key or assistive technologies to navigate through a page.
Leaving the outline for the select
element here causes a problem: when it is clicked or in focus the outline overlaps with the label
and it looks a bit messy. Removing it also causes a problem: it makes the page less accessible for some users.
Alternative :focus Styling
1select:focus {2 outline: none;3 border-bottom: 2px solid #8eb0e7;4 /* decrease padding-bottom by border-bottom-width */5 /* This prevents it from affecting the layout */6 padding-bottom: 5px;7}
So here we're defining a custom visual cue for this group of users. It's just a border-bottom
, but should do the trick (choose the colour carefully).
Uses & Limitations
The first possible use case is what I discussed at the very start: for mobile devices. You could easily reset the defaults for wider viewports.
Another possible use case is if you want to use the select
element not only to provide a control for selecting an option, but also to display the selected option as information. I’ve used it in an audio visualisation experiment in which I made it possible for the user to change the streaming track via a select
element. I didn’t want to have a select
element where the track title is visible and display the track title some where else as well.
There are some limitations though. Given that not all browsers support text wrap in the select
element means the options have to be short to use this method. And since the select
element and the label
have to overlap, the label
text needs to be short as well (unless you position it above or below the select
element and increase the select
element's height or padding).
I have not done any user testing. I have no idea whether this method will generate any confusion to some users. On the other hand, most users are already familiar with the default styling of the select
element, so when they see it they know there are options to choose from straight away.
Your choice of the label
text has to be made carefully. Using verbs like 'change' or 'choose' will make it clearer to the user that there is some interaction required.
Browser Support
This solution relies on setting the appearance
property value to none which is supported in most browsers with vendor prefixes. IE desktop doesn't support it all, but surprisingly IE Mobile 11 does!
Check browser support