Using a <select> dropdown menu to create navigation isn’t as common as it once was, but it’s still around. It got ripped on pretty good for being an inaccessible / obtrusive. Indeed a lot of the scripts you’ll find out there for creating a menu like this are this way. Bummer. Let’s make one that works with OR without JavaScript!
The OBTRUSIVE Way
<form>
<select onchange="window.open(this.options[this.selectedIndex].value)">
<option value="">Go to page...</option>
<option value="https://css-tricks.com/">CSS-Tricks</option>
<option value="http://digwp.com/">Digging Into WordPress</option>
<option value="http://quotesondesign.com/">Quotes on Design</option>
</select>
</form>
Inline JavaScript… it works, but only if JavaScript is enabled. Without, you’ll have a dropdown menu that does absolutely nothing.
The UNOBTRUSIVE Way
<form id="page-changer" action="" method="post">
<select name="nav">
<option value="">Go to page...</option>
<option value="https://css-tricks.com/">CSS-Tricks</option>
<option value="http://digwp.com/">Digging Into WordPress</option>
<option value="http://quotesondesign.com/">Quotes on Design</option>
</select>
<input type="submit" value="Go" id="submit" />
</form>
Pretty similar, but no inline JavaScript. Instead we give the form and ID we will use later to target. The form now POSTs to itself, and we have added a submit button, so the form is functional. The select now has a name value, so when the submit button is pressed, it will POST a value.
At the very top of our page, we’ll check for a POST value from that form. If it is there, we’ll redirect the page to that value.
<?php
if (isset($_POST['nav'])) {
header("Location: $_POST[nav]");
}
?>
No JavaScript needed at all, the page redirect is handled entirely via server-side PHP. NOTE: this is just the way-simplified PHP. You should probably sanitize that submitted value before passing it to the header function (esp. if running PHP prior to 4.4.2 or 5.1.2) to prevent “header injection” attacks.
We can make it behave identically to the obtrusive method though, with just a few lines of jQuery.
- Hide the submit button.
- When the select is changed…
- Redirect to value of option
$(function() {
$("#submit").hide();
$("#page-changer select").change(function() {
window.location = $("#page-changer select option:selected").val();
})
});
Update
Reader David Vandenbroek writes in:
I found that using:
<select onChange="window.open(this.options[this.selectedIndex].value)">
opens a Popup warning dialog, and if allowed, a new window on iPhone/iPad when iOS Safari has the setting ‘Block Pop-ups’ set to OFF. When the setting is set to ON, nothing happens.
To avoid both undesirable behavior, I used :
<select onChange="window.location.replace(this.options[this.selectedIndex].value)">
instead.
I am freaking out I have been searching around for an hour for this EXACTLY! I said to myself, “I know that CSS-TRICKS will have it, let me take a look.” No search needed. Thanks so much for such a comprehensive site.
Also nice to note that the unobtrusive way also doesn’t force a new window.
Or is that another cause :D
Isn’t it smart to have some sort of validation before the header function? Or am I missing something here?
This would be one way:
It’s funny.Most of the time I got projects where client ask for something .First thing I do is check out the css-tricks and all the time I’m surprised ,yes there is new post and it’s exactly what I’m looking for.It’s like this dude is reading my mind!
I probably won’t find this useful, but very nice though :P
Another thing, there was once an article about no-css no-images solutions, and it seems to have vanished. Where is it? Thanks :P
i like the new design css tricks !
nice work chris! ..
Kiss (K)
would love to see how to style these
Nice… Less then a week ago i thought a feature like this would make a nice addition to my custom startpage at work, just didn’t take the time to look up how it’s done yet. Your timing couldn’t be much better.
Thanx.
This is cool. Falls back nicely when Javascript is disabled. I agree with Kristoffer, the url should be validated/checked before it goes into header().
You should also put an exit; after header() to prevent the code below the header() call from executing.
See the PHP manual page for the info: http://nl.php.net/manual/en/function.header.php
I never seemed to like drop down navigation menus, however I might actually consider implementing something like this, given the right circumstances. Nice post!
Chris, I have to admit that do not really get the clue how to get the unobtrusive working. A new podcast culd help :)
Using combobox for page selection is very bad user interface design. Always use anchors for that purpose and think about PDA/Mobile users.
The downside is that this kind of navigation isn’t accessible at all. What I did was HTML like
And a javascript that converted the html to a select box.
That’s because our designer loved to use select boxes as a navigational element which is imho just wrong, because it’s an abusive use of a form element.
I prefer just using the ul and styling it as a kind of menu using either suckerfish or neat javascript effects.
This is fine, if you only have 3 selections to choose from.
However, I plan to use this for selling tickets to concerts/events using Brown Paper Tickets. And, we have 20 events a month. That gets a bit unwieldy in a list.
This is a good solution.
My point is that you either rewrite the list via Javascript to a select box (which enables users w/o javascript and search engines) or to use css to style a list like a select box (by setting it to position:absolute, it’s height to one line and a hover to let it expand (optionally via scriptaculous)).
So you can take best of both worlds.
I’m with Dmitry here. I am struggling to see the point of using a form element to provide navigation – it’s non semantic and bad usability in my opinion. Why not use a styled list and if you really must, a bit of JS.
I don’t normally like these solutions, but its perfect for a sub menu mobile navigation for smaller sites!
So now I have to write all my pages in PHP just so that I can have a semi-inaccessible navigation that will be ignored by the search engines?
Wheres the advantage?
YES. YOU HAVE TO REWRITE EVERYTHING THIS INSTANT.
Erm. No. IF you ALREADY have a dropdown menu like this, THIS is a way you can make it a less obtrusive. And PHP isn’t a requirement, you can use and server side technology that can accept form data and do a redirect.
James, if the links inside the form would be ignored by search engines, millions of websites would not be in the index. Spidering a page made by Dreamweaver is harder than ruling Afghanistan. It contains hardly anything what we call HTML. It is a hell of click-events. What I wanna say:
If there’s a link, Google gets it.
nice way to do it, thanks for sharing :)
your blog is so cool! i am seeking ways to promote my blog. this is especially helpful. please visit my blog.
http://www.ishtihari.blogspot.com
Great job Chris. Thanks
This is a misuse of POST; it should use GET instead.
yeah..this dude really can read our mind…thx Dude…
Sent in via Hendrik Walter
This is a way to combine the obtrusive method with the PHP stuff to make it work the same way, only without jQuery:
Thank you Chris!
Sorry Chris I personally think this is the worst article I’ve read on CSS Tricks.
You appear to be endorsing a very poor practice by example.
At the very least remove the onchange behaviour and get that “go” button out of the noscript.
That’d make it at least usable to most people.
It is better to use
location.assign(this.options[this.selectedIndex].value)
instead of
window.location.replace(this.options[this.selectedIndex].value)
because location replace is not in browser history and it dissalow back button