Full CSS Responsive Navigation Toggle, No Javascript

full-css-toggle

A short tutorial to do responsive/mobile navigation toggle with only CSS (no javascript/jquery needed).

I do understand, to disable javascript in browser is not common anymore, and more website rely on javascript to work properly. But it’s interesting subject isn’t it? We can use this as a fallback if javascript is disabled.

HTML

the navigation html is very simple and basic navigation in WordPress.

<nav id="menu-primary">

    <div class="menu-container">

        <div id="menu-toggle-primary">
            <a class="open-menu-primary" href="#menu-primary"><span>Open this menu</span></a>
            <a class="close-menu-primary" href="#"><span>Close this menu</span></a>
        </div><!-- .menu-toggle -->

        <div class="wrap">
            <ul class="menu-items" id="menu-primary-items">
                <li class="menu-item"><a href="#">Menu 1</a></li>
                <li class="menu-item"><a href="#">Menu 2</a></li>
                <li class="menu-item"><a href="#">Menu 3</a>
                    <ul class="sub-menu">
                        <li class="menu-item"><a href="#">Menu 3.1</a></li>
                        <li class="menu-item"><a href="#">Menu 3.2</a></li>
                    </ul>
                </li>
                <li class="menu-item"><a href="#">Menu 4</a></li>
            </ul>
        </div><!-- .wrap -->

    </div><!-- .menu-container -->

</nav>

as you can see, before menu items, we create a div for navigation toggle, and inside the div we have 2 link, one for opening the menu, and one for closing the menu.

        <div id="menu-toggle-primary">
            <a class="open-menu-primary" href="#menu-primary"><span>Open this menu</span></a>
            <a class="close-menu-primary" href="#"><span>Close this menu</span></a>
        </div><!-- .menu-toggle -->

CSS (before toggle, closed state)

Default css is simple, we just need to hide our menu ul#menu-primary-items and hide the link to close the navigation because it’s already closed (hidden).

/* Hide Menu */
#menu-primary-items{
    display: none;
}
#menu-toggle-primary a.close-menu-primary{
    display: none;
}

CSS (toggle open)

As you can see in the demo/html source, in the link to open the toggle linked to #menu-primary element. So when we click the link, the browser will go to http://yourpageurl/#menu-primary.

Now the interesting part, we can actually style the targeted element using CSS :target selector.

URLs with an # followed by an anchor name, link to a certain element within a document. The element being linked to is the target element.

The :target selector can be used to style the current active target element.

So, if we add this CSS it will only do stuff for selected element when it’s active (targeted using #element in url).

#element:target{
    /* do stuff */
}

we are going to use :target CSS selector and we can do something like this:

/* Display Menu Items */
#menu-primary:target #menu-primary-items{
    display: block;
}
/* Hide Open Toggle Link */
#menu-primary:target #menu-toggle-primary a.open-menu-primary{
    display: none;
}
/* Show Close Toggle Link */
#menu-primary:target #menu-toggle-primary a.close-menu-primary{
    display: block;
}

At this state, the menu items will be displayed, and the link to open the menu will be hidden.

FAQ

Using only CSS will make the page “jump”

It’s unavoidable, using javascript/jquery we can prevent this using event.preventDefault(). in the demo I add the navigation at the top of the page to prevent the “jumping” experience. If you create the navigation toggle in other position (for example, after the header), you can prevent/make it less jumpy by linking the to the right/nearest div/element id.

Browser Support

:target CSS is supported by all major browser, but not supported in Internet Explorer 8, and earlier versions.

I hope this simple explanation is enough 🙂
If you have any question feel free to ask in the comment.

8 Comments

  1. Tanja lee

    Hi,

    thanks for a great tuturial. I have one question though. How do I make the navigation fixed? When I add ‘position:fixed’ to the navigation, I can’t scroll on my mobile.

    Thanks.

    Tanja

    • David

      maybe you can try:

      #menu-primary {
      	position: fixed;
      	top: 0;
      	width: 100%;
      	max-width: 600px;
      }
      #container {
      	position: relative;
      	margin: 0 auto;
      	width: 100%;
      	max-width: 600px;
      }
      
  2. Anna

    This is great, is there a way of making the list horizontal instead? so it would open across the top?

  3. Santana

    Hi Shellcreeper, I like your tutorial very much and I am trying to addapt it to my template, but I have one problem that is when I move the open & close buttons to a other div I can’t get them to target the menu anymore.

    Here is a Fiddle of what I am trying to do http://jsfiddle.net/SanMoll/k8ej4fmo/2/

    Hope you can give some advice, thanks

  4. Elias

    Very useful implementation, but I have an observation.
    Probably has been fixed but here goes:
    If you open and close the menu, say 7 times, it ‘ll take you equal amount of times pressing the BACK browser button just to go to the previous website.

  5. Tonguc

    Thank you so much for this tutorial! I like it because, it’s so easy & without JS. Even though one question. On my Side if I open the menu, it jumps to top. I tried with “position:fixed;” and “onclick=return false;” No chance! Do you have any Idea, how can I fix the problem?
    Thanks again
    Tonguc

  6. fatih

    If you want to use animation, try this code:
    @import url(https://fonts.googleapis.com/css?family=Open+Sans);

    $bg-color: #537ec5;
    $text-color: #010038;
    $inactive-item-color: #537ec5;
    $active-item-color: #010038;

    .fa-2x {
    font-size: 26px;
    }

    .menu-container {
    width: 500px;
    height: 80px;
    padding: 4px 20px 0px 20px;
    background: #fff;
    border-radius: 0 0 30px 30px;
    position: relative;
    z-index: 0;
    }

    .menu {
    width: 100%;
    height: 100%;
    margin: 0;
    padding: 0;
    display: flex;
    position: relative;
    }

    input[type=”radio”] {
    display: none;
    }

    label {
    color: $inactive-item-color;
    cursor: pointer;
    z-index: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 25%;
    transition: 0.25s ease-in;
    }

    .item {
    text-align: center;
    }

    .item-title {
    margin-top: 14px;
    margin-bottom: -6px;
    color: $text-color;
    font-weight: 600;
    font-size: 11px;
    }

    .blob-container {
    position: absolute;
    z-index: 0;
    width: 25%;
    transition: transform 0.2s ease-out;
    }

    .blob {
    background: $active-item-color;
    width: 50px;
    height: 50px;
    border-radius: 25px;
    margin: 2px auto;
    }

    input[type=”radio”] {
    &:checked {
    & + label {
    color: #fff;
    }
    }
    }

    input[id=”radio-0″] {
    &:checked {
    ~ .blob-container {
    transform: translateX(0%);
    .blob {
    animation: scaleY-0 .2s linear;
    }
    }
    }
    }

    input[id=”radio-1″] {
    &:checked {
    ~ .blob-container {
    transform: translateX(100%);
    .blob {
    animation: scaleY-1 .2s linear;
    }
    }
    }
    }

    input[id=”radio-2″] {
    &:checked {
    ~ .blob-container {
    transform: translateX(200%);
    .blob {
    animation: scaleY-2 .2s linear;
    }
    }
    }
    }

    input[id=”radio-3″] {
    &:checked {
    ~ .blob-container {
    transform: translateX(300%);
    .blob {
    animation: scaleY-3 .2s linear;
    }
    }
    }
    }

    @keyframes scaleY-0 {
    0% { transform: scale(0);}
    60% { transform: scaleY(0.5) translateY(30px); }
    100% { transform: scaleY(1);}
    }

    @keyframes scaleY-1 {
    0% { transform: scale(0);}
    60% { transform: scaleY(0.5) translateY(-30px); }
    100% { transform: scaleY(1);}
    }

    @keyframes scaleY-2 {
    0% { transform: scale(0); }
    60% { transform: scaleY(0.5) translateY(30px); }
    100% { transform: scaleY(1); }
    }

    @keyframes scaleY-3 {
    0% { transform: scale(0); }
    60% { transform: scaleY(0.5) translateY(-30px); }
    100% { transform: scaleY(1); }
    }

    body {
    min-height: 100vh;
    display: flex;
    justify-content: center;
    align-items: center;
    background: $bg-color;
    font-family: ‘Open Sans’;
    }

Comments are closed.