CodeinWP CodeinWP

A JavaScript Content Switcher That Works Without JavaScript

A JavaScript Content Switcher That Works Without JavaScriptRecently, while doing research/work on a completely unrelated topic, I came across the beautiful illustrations on Rype Arts, which are displayed inside of a JavaScript-driven content switcher. For some reason, I happened to visit the page with JavaScript disabled and noticed that the content switcher was still working (albeit, with a few flaws).

At first I couldn’t figure out how it was functioning. Normally, with JavaScript disabled, this type of content switcher (or content slider) will just display one item, or else display all items, without allowing any “switching” functionality. After some poking around, I realized it’s not a very difficult thing to do. The switcher utilizes in-page anchors and overflow: hidden to keep the switchability intact.

View the Demo to preview what I’ll be describing below.

Here is the HTML that I’ll be using to demonstrate this effect with and without JavaScript:

<div id="content-slider">
  <ul id="content-slider-inside">
    <li id="one">1</li>
    <li id="two">2</li>
    <li id="three">3</li>
    <li id="four">4</li>
    <li id="five">5</li>

<ul id="navigation">
  <li><a href="#one">1</a></li>
  <li><a href="#two">2</a></li>
  <li><a href="#three">3</a></li>
  <li><a href="#four">4</a></li>
  <li><a href="#five">5</a></li>

The key part of this code is the <div> with the id “content-slider”. Normally, that element would not be necessary, as it seems to be doing nothing. In this case, however, it’s needed in order to hide the unselected content inside the list nested inside it. Also, each list item inside the content switcher is given a unique id, which is needed for the switching to work even without JavaScript.

The CSS to style the content switcher is as follows (I’ve excluded all irrelevant styles):

#content-slider {
  width: 650px;
  overflow: hidden;
  height: 300px;

#content-slider-inside {
  list-style: none;
  height: 320px;    // these 3 lines
  overflow: scroll; // help Opera
  overflow-y: hidden; // behave

  #content-slider-inside li {
    width: 650px;
    height: 300px;

A few things to note in the CSS above: The outer container has its overflow set to “hidden”. It also has a width equal to one of the content boxes (650px). Inside the container is the <ul> element that holds the list items that represent the content boxes. Finally, the list items are given dimensions of 650px by 300px. Since the container element is equal to one list item, and the container has overflow set to “hidden”, only one list item will be visible at a time.

Update: I added three new lines of code in the CSS above (commented), to get the non-JavaScript version (the first demo) to work in Opera. Thanks to comment by Damian Muti.

How it Works

The navigation links are linked to internal anchors. An HTML page, by default will search the page for an anchor set as <a name="one"></a>, and if it doesn’t find it, will then match the anchor to a corresponding id attribute. This is what allows the content switcher to still change the content inside of the container.

After the above code is in place, we just need to add some CSS to make it look a little nicer, then we have the option to enhance the switcher with JavaScript. The switcher also allows deep linking by means of the hash in the URL, which works with or without JavaScript.


This works in every browser. Take a look at the demo, which also includes a link to a JavaScript/jQuery-enhanced version that I coded myself, as a bonus. And just to demonstrate the deep-linking capabilities, the demo link appends “#three” to the URL — so you should see the number “3” in the content area, if it’s working correctly.

Update (March 23, 2013) Updated the code for the JavaScript version, it was pretty awful. Apparently, the JavaScript version was causing a page jump (thanks to comment from an anonymous person). I also added keyboard focus styles that show which link has been clicked/focused for the JS-free version.

102 Responses

  1. Jonathan says:

    Excellent, thanks Louis – another addition to my PE toolkit!

  2. James says:

    I like it, would be awesome if it worked in Opera too! :)

    • PfftOpera says:

      Who gives a crap if it works with Opera? That’s less than 1% of the market share. Not to mention they’re probably used to having to switch browsers for things to look right.

      If you’re paying a developer, and they’re wasting your time and money developing workarounds for Opera, it’s probably time to look for a replacement.

      • Deb says:

        Sadly that’s true, Opera probably will never make it to the mainstream user base. They keep changing versions with cosmetic changes but nothing much changes for the average user. Where Chrome is setting high standards & stealing Firefox loyals every month Opera is clearly lagging behind. I want them to succeed as well, but not sure if they ever will.

        Opera loyals don’t bash me but i was pretty happy to see the new shortened big O menu in 10.50 until i enabled Show Menu Bar and i see this

        • aza says:

          Opera is strange. As web developer I mentioned that if my design works fine with most browsers then IE 6 and Opera have still kind a similar bugs. Good article! I’m a big fan of css.

      • Stac says:

        This is very local specific.
        As for my projects in Russia, eg., Opera gives up to 30% of visitors,

        And I’ve used “content swither” just yesterday. Grrr…

  3. Mike Smedley says:

    Ha, very cool and simple way of doing this without JS, one of those that makes you think “why didn’t I think of that!”

  4. Johnny says:

    Pretty cool, good job. I love things like this that only use CSS and HTML to make something interactive :D

  5. Damian Muti says:

    Really nice tip, Louis.

    Actually you are right, Opera seems to fail pointing to anchors inside containers with overflow:hidden.
    Tried a few thing to make it work in Opera, and i`ve found a clean solution. Maybe there’s a better one, but as far as i’ve tested, works in IE6, 7, 8, Opera 10.10, Chrome 3.195 and FF 3.5.7.

    Here’s the trick:

    #content-slider-inside {
    	list-style: none;
    	height: 320px;

    As you can see, in the ul style you have to add a height of 20px more than the container div to hide de x overflow and use the CSS3 overflow-y property.
    Adding overflow:scroll makes it work.

    Thats it.

    Keep the good work, mate.

    Cheers! :)

    • Damian, great job in resolving that! I knew there had to be a way to get Opera to behave. I just didn’t have the time to hack away at it.

      I added your code to the demo and updated the article to give you credit.. Thanks!

  6. ricky says:

    Hey, this is really great. Thanks!

    But I noticed that it breaks the back button (using Firefox 3.0.17 on Linux). Is this happening for anyone else? Internal anchors on other pages I visit do not break the back button. But still an awesome tip.

    • The back button will fail with JavaScript enabled, which is a common problem with deep linking via JavaScript. In this case, it’s not as important because this is a content-switcher that would not take up the whole page anyhow.

  7. Jason says:

    Very nice, this will come in handy on a good number of projects, and Damian thanks for the tip to help it work properly in Opera. I’ll see how it goes and how this can be expanded.

  8. Nico Burns says:

    Not sure how it was supposed to work, but worked fine in opera for me (v10.5), just without the animation of the javascript version

    • It was the non-JavaScript version that was not working in Opera 10.10. It works fine now, but I would be curious to test in Opera 10.5. Were you talking about the JS version, or the non-JS version?

  9. eddie says:

    Interesting and very useful. I’ll try this soon. Thanks!

  10. SFdude says:

    Very nice!

    In both demo versions (with & w/o jQuery),
    when you click on a [#] button, the big #, switches OK.

    But…the entire page view jumps to the bottom.
    (ie: the Top Title:
    “Adding jQuery to Enhance the Content Switcher”
    disappears from view , and you see the bottom links of the page:
    “< Go back to the tutorial").

    Is there a way to avoid the page jumping to the bottom,
    when you click a [#] button?

    – in Firefox 3.5.8/XP-SP2 (jumps to page bottom)
    – in CHROME works fine! (no jumps, smooth transitions…)


  11. SFdude says:

    Please, disregard my previous post.
    It works just fine in Firefox 3.5.8.

    The jumping effect (described in my prev post),
    was due to my browser Zoom level being at 120%,
    (which I need due to poor vision),

    So, my new question is:
    how to modify the script to avoid the “jump effect”
    if the User has set his browser to a Zoom View > 100% ?


    • Hey SF,

      I’m glad you pointed that out. Basically, that’s happening because I’ve enabled deep-linking via JavaScript. Each click changes the hash (#) in the URL, thus “visiting” that hash, the same as an internal page link (for example, with JS disabled on the first demo).

      So, to prevent the “jump” from happening, just comment out lines 57-59 in the JS, which looks like this:

      if (location.hash !== "#") {
      	location.hash = "#"+myClicked[1];

      The jump will still happen, however, in the non-JS version, because it uses in-page anchors to work. And, as you pointed out, this really only occurs when the page is zoomed, so it wouldn’t really be much of an issue, I don’t think.

      • Ahmad Alfy says:

        I was just about to ask how to avoid the “jump”
        I just tried that and it works perfectly … Something weird it still jumping on the first item … but not a problem :)
        Thank you

  12. Behzad says:

    awesome !! Thanks Louis :) I’ll try this.

  13. ThaClown says:

    Thx alot really nice!

  14. Iggy Hammick says:

    I like it a lot. Just wonder how this affects accessibility with the back button. When you click through the different content, you cant then click the browser back button to return to the previous page.

    Regardless – great technique!

  15. Anderson Lee says:

    This is a great find, Louis. I’ve wanted a better way to present JS-less pages for months…I’m off to replace the js in my custom pages with this.

  16. Seif says:

    Is ther a way to personnalize links so they can gather information from server using Ajax?

  17. Rob says:


    Thanks alot for this, I love using jQuery, but am always trying to use methods that fallback nicely when javascript is disabled, and this is perfect.

    I’m ok implementing pre-built jQuery effects, but don’t really understand the language itself at the moment, something I want to work on this when I get some time… But is it possible to make this cross-fade between the different content, rather than the fade out to blank and then fade back in… I’ve attempted to modify sections of the coding, but to no reward so far lol….

    So if anyone could help, and guide me to what I’d need to modify to achieve a cross-fading effect it would be greatly appreciated.



  18. Docu says:

    Really a good work…
    Thank you !

  19. hello says:

    Thanks for the help, will try this out. Will be useful to me. Thanks for sharing.

  20. Mr. Won says:

    It would be great if there was a non-JS way to make this work for images of differing sizes and shapes, but as is, this is a fantastic solution for a fixed viewport image gallery.

    Thank you.

  21. This is pretty straight-forward, what every competent front-end web developer would do to make their site/slide accessible even without JS.

    A sliding example can be found here . Disable JS to see how it falls back.

    Its good to have a tutorial for it anyway :)

    • Jase says:

      WARNING! This is not a link to a tutorial or other information regarding a failable JS sliding alternative t to this content switcher (as the comment indicates). It’s really just a link to some assets you can purchase at Theme Forest. And what’s worse is that the assets linked herein are for vcard implementations, not sliding content management.. By principle alone, you should avoid any content provided by this spammer, I will.

      • I’m not sure why you take issue with his link. He linked to a content slider, and that’s what it is. Who cares if it’s not a tutorial?

        I don’t have a problem with that link, because it’s on topic.

  22. Vassilis says:

    This is a very open minded approach of a common problem.
    My first guess was an iframe (just lame), but looking your code was just surprising!

    Thanks for posting this.

  23. Interesting article. I never would of thought to do something like this. However now that I’ve read this it makes me wonder what more I could be doing with css. Thanxs for making me think.

  24. thekruser says:

    Have you any idea how to incorporate this script/css in a WordPress page? Would like to incorporate it into my home screen.

    Thanks for the awesome info!!

  25. Mitch Page says:


    Great content glider, thanks!
    I wonder just, why can’t I change the light blue colored back ground into an image, like
    background-image: url(../images/myimage.jpg);

    Am I missing something?

    • Mitch, are you talking about the grey background? It’s declared on the list element (<li>) as “background: #ccc;”. If you change it, you have to make sure you remove that declaration completely, replace it with the new “background-image” declaration, and make sure your image is in the correct location relative to the CSS file. Other than that, I don’t know what else to suggest..?

  26. ukm says:

    nice tips
    maybe I must implemented in my website..
    thank you

  27. Esteban says:

    HI, nice post!

    Any one, know if this can be adapted (supporting no javascript) to use only two buttons for the switch?(. Previous and Next button. )


  28. Stuart M says:

    Mine also jumps so how do you comment out ?
    I am very new to JavaScript, also can i get this to animate with a function is there
    a function we can add i didn’t see any in the post thanks for any help.

    • Stuart,

      For the “jump”, that only happens in the non-js version. If you have a larger screen size, you won’t see the jump, because the jump is just the fact that the page is trying to locate the internal anchor location (the hash in the URL).

      To view the JS version with animation, here is the link:

      You won’t see any jump on that one, because the JS code uses “return false” to prevent the value of the HREF from being followed.

      • Stuart M says:

        Louis thanks for the super fast response . It is a great slider as i had mentioned before i am so new to JavaScript. Making websites is a hobby of mine ,that i really enjoy. I am by profession a Musician
        so these forums give me hope for a better understanding thanks for your help. Stuart M.

      • Mike says:

        The jump definitely happens with the javascript version too, which makes the design unusable for designs that go off the bottom of the screen.

  29. Great little find, this. I’m redoing my site at the moment, and this perfectly balanced ease of use with flexibility. Thanks for publishing it, Louis.

  30. Jason Burnett says:

    I have been trying to adapt this code to use Ajax to load the various pages and I can’t get it to work.

    I have tried preloading the content and rebuilding the for the inner-div using AJAX, but that didn’t work.

    I have tried calling the AJAX loadpage function when a nav item is clicked, but that didn’t work either.

    Any suggestions? (Thanks for your great help, btw)

    • Jason,

      You’re going to have to provide an example page, so I can take a look at it. Or you could email me the whole thing. Use the contact page on this website, and we can discuss it, but only if you have an example to show me, otherwise I can’t really help you much.

  31. Dylan says:

    A great script and thanks very much for sharing :)

  32. jennifer says:

    This is fantastic! I’m a jQuery beginner and loved your tutorial on sliding folders — any chance you could do a similar one for the jQuery file behind the “enhanced” version of this content switcher?

  33. Mel0ne says:

    First: this is perfect! a easy to understand code even for beginners, Thanks

    Now, im using the JS Version and i wonder if it is possible to add a automatic rotator, like the content switches every few seconds.

  34. nsxer007 says:

    Is there an “easy” way to add previous/next buttons? (understanding it wont work without JS…. My target audience has JS enabled.) I like the simplicity of your slider and the hash tag access. I simply need to add prev/next and I’m set.

    Also, (without wanting to sound greedy) is it possible to target the hash tags from on the same page and still have it animate? for instance, redundant quick links that live on the page that would jump to a specific slide while keeping the animations. Thanks for any help. Great work.

  35. Andrew says:

    Unfortunately, it doesn’t seem to work with screen readers with JS turned off. I tested with three screen readers using Firefox 3.6 and IE8. Firefox crashed when using JAWS. Otherwise, all numbers in the first list are displayed. Being busy (lazy?), I haven’t checked out the code yet. If off-lefting or something similar is being used, that is not hidden from screen readers.


  36. Andrew says:

    Unfortunately, it doesn’t seem to work with screen readers. I have just tested with three in both Firefox 3.6 and IE8. Firefox crashed when using JAWS. Otherwise, all numbers in the first list appear. The enhanced version works well. Being busy (lazy?), I haven’t checked out the code yet. If something like off-lefting is used, screen readers will read that content.


  37. Alex Hall says:

    Without realising it I had this functionality working quite a few years ago on a site I built for the band I was in:

    It simply switches the profiles without javascript, but when js is enabled it slides between them. Should’ve written about it then, really!

    • Yep, it works the exact same way.

      The problem with yours, however, is that the “previous/next” buttons are still visible when JavaScript is turned off. Those buttons don’t work with JavaScript off. What you should do is insert those elements into the DOM with JavaScript, that way they will only appear to users viewing with JavaScript enabled.

  38. ossama says:

    hello, nice trick, but i think that “overflow:hidden” hide content from search engines, so it’s bad for SEO.

  39. mike foskett says:

    A beautifully simple method that I’m surprised hasn’t been seen before.
    Added the example to a Tesco miro-site for Garmin:
    and the direct homepage:

    Nice find.

  40. Ed says:

    How do you make the jQuery version automatically go through the slides. Could someone provide the code needed? I run a high-quality advertising agency, and to the avoid the ‘jack of all trades, master of none’ situation, I have somewhat neglected programming! ;) Thanks for your time.

  41. Omar Chavira says:

    I’m also interested in having the slides change automatically. Did anyone get this to work?

  42. Sam says:

    This is a brilliant post, @louis thank you!

    Regarding the ‘jump’ that other comments have described. It does unfortunately make the process particularly frustrating (from a user perspective) if you’re being moved about the screen all the time!

    The solution I’m assuming will work (although not tested) to avoid the jump, is to make sure the navigation and content is a) in the same window and b) the navigation is actually above the content. It is just a guess and I’m going to test it tomorrow.
    However, failing that is there another solution as it would be a shame not to use this because of the pesky jump!

    (I appreciate that there’s a workaround for when js is turned on it’s just I’m trying for a pure CSS design with no aesthetic javascript)

    Cheers, great job


  43. Michael says:

    There is quite a big problem with this whereby if there is a trailing hash in the url when the page is refreshed, then the whole thing breaks and all the content is displayed.

    Also, I don’t know why but I just can’t get my version to work in IE7

    I’ve included the website in my details, if you fancy a look.

  44. Joey says:

    Very cool! Is there a way to make the first piece of content that loads show an active state in the menu? Right now it doesn’t show it as active in the menu until you click it.

  45. Ash says:


    Love this app, however have a slight problem with it, the first li element doesn’t appear until you click the link for it. i want it to display immediately on loading the page, as in the demo!

    Any ideas why it would not automatically display?



  46. Vitz says:

    Great post. Is there a way to make the non-javascript version automatically scroll through the content blocks without having to press the button.

    I’m thinking of using this as of way of displaying some screenshots of a product, but without making the user click on small thumbs.

    I realize that the scroll script will have to be javascript.


  47. ThievingSix says:

    Here’s another tip, if you wish to change the link names e.g from “” to “”. You simply have to go into general.js and edit line 34 from:

    if (contentCollection[i].id !== "one") {


    if (contentCollection[i].id !== "Myname") {

    Or whatever you want to name the link

  48. JJ says:

    Hi Louis,

    great work, but I´m trying to give the active tab another color. It will not work. Can you help??

    • If you’re referring to the version without JavaScript, then you can declare “focus” styles. For example:

      a:focus {
      /* styles in here */

      And that’s probably something I should add to mine! :)

      • JJ says:

        If you’re referring to the version without JavaScript, then you can declare “focus” styles. For example:

        a:focus {
        /* styles in here */
        And that’s probably something I should add to mine! :)

        thank you for your answer, yes I use the version without JavaScript, but your suggestion (#navigation li a:focus { background: #630000;}) doesn’t help :-(
        Maybe an other idea?

        • JJ, you’re correct. the “:focus” pseudo-class sets the styles for the element that has keyboard focus, so it won’t work for that. It does work if you tab through the links with the keyboard, though. And “:active” doesn’t work either, because that’s only for while the link is actually being clicked.

          The only way to do it (from what I can tell) is via JavaScript, as in the JavaScript-enhanced version.

  49. NattheCataz says:

    I am using a non-javascript version of this example at the moment and cannot get the page to load the “home” content be default without explicitly setting a redirect page. It keeps loading the “links” content instead. Should I reorder the html? I know I am probably missing something simple here, but what? Otherwise my transitions work great in all browsers. is what I want to appear when the user goes to the page .

    • Hi, Nat.

      This is easy to fix: In your HTML, you’ve put the <div id="home"> section second in the markup, after the “link” section. Just swap those around in the HTML so the “home” section is first, and that one will be the one that will appear by default.

      • NattheCataz says:

        Thanks, but that didn’t fix it either. I am still seeing the links div by default. I am just going to redirect until I figure this out. I am also seeing the page jump around when loaded in smaller resolutions. Not a huge issue, but one that I cannot leave alone.
        thanks again.

      • NattheCataz says:

        I tried that too and still it is defaulting to the link div, and not the home div. I am going to do a redirect until I can fix this and also apply the javascript. Thanks.

  50. henning says:

    Hey Louis,
    thanks a lot for this tutorial, for a newbie like me it’s perfect.
    Still i encountered a little Problem. The first content I’ll show in my content-slider-inside is always more to the left than the rest. when I change the content with a click, everything looks ok (margin / padding). Only the first Element seems to be “unmarginable”.
    I tried the Version without JS and I’m just curious, never found a solution.

    with best regards

    • Hey, I’m glad to help you debug this, but I would need to see an actual example. If you want, use the contact form on this website to send me a link to a demo so I can see what’s going on. Thanks!

  51. Interesting and very useful. I’ll try this soon. Thanks!

  52. Fernando Díaz says:

    ¡Muchas gracias! Me salvaste.

  53. Guest says:

    This is awesome BUT anchor links are scrolling the page :(
    I’ve spend several hours and couldn’t figure how to prevent site from scrolling. If you don’t know what I’m talking about just go to your demo, scale window down, scroll a little bit down and press content switcher link, page will jump to the top. I can’t use it like this in my page and I need this so much.


  54. Neil says:

    I get the jump on the non-js version and I’m on a large screen res. I also get the jump on the js version so not able to use this.

  55. Andrew says:

    Hi Louis, i loved your Content Switcher and I have a question for you:
    I’m trying to turn it into a slideshow (keeping navigation), so that the slides switch automatically and when the cursor is on the slide, the slideshow stops … may you will prompt as this can be done?
    (I tried a few hours but could not achieve required effect)

  56. Silly Simon says:

    I love the simple code and the fact that it doesn’t depend on Javascript. I wonder if previous and next buttons can be implemented by using PHP. Any ideas?

  57. Rick White says:

    Thank you for this tutorial. I would like to implement it on my website. What can I do to center the navigation buttons under the slideshow?

  58. John says:

    How do you add transitions with CSS3 to make the content fade or slide in?

  59. bayu says:

    i am so long search this I found a solution here

Leave a Reply

Comment Rules: Please use a real name or alias. Keywords are not allowed in the "name" field and deep URLs are not allowed in the "Website" field. If you use keywords or deep URLs, your comment or URL will be removed. No foul language, please. Thank you for cooperating.

Markdown in use! Use `backticks` for inline code snippets and triple backticks at start and end for code blocks. You can also indent a code block four spaces. And no need to escape HTML, just type it correctly but make sure it's inside code delimeters (backticks or triple backticks).