Search code examples
htmlcssprogressive-enhancement

How do I create a full screen click target to work with CSS-only navigation menu with :target?


Related to StackOverflow question: CSS only menu close on target, although the question seems to be poorly articulated and therefore didn't receive any answers.

I'm looking to create a navigations menu using progressive enhancement on a mobile-first design, so :hover isn't an option. The first step is to implement a JavaScript free navigation drop-down menu using the :target pseudo selector. I'll add a JavaScript solution on top of this later. The menu will be on a public website that requires support for users who have JS disabled.

Opening the menu is no problem -- my question comes when it's time to close the menu. The only way to do this is to remove the id from the URL hash.

For example, the menu appears when you click the following link: <a href="#nav">Menu</a> which changes the URL to www.something.com/#nav. In order to hide the menu I need to remove #nav from the URL. The solution is to add another link that changes the hash: <a href="#top">Close Menu</a>.

The user will expect that clicking anywhere outside of the menu will close the menu too. The first solution that comes to mind is to use a little z-index magic to create a full-screen anchor tag just below my menu.

Open to suggestions for other solutions, too.

HTML:

<header id="top">
    <a href="#nav" class="toggle-nav">Menu</a>

    <ul id="nav">
        <li><a href="#top">Close Menu</a></li>
        <li><a href="#">Nav Item 1</a></li>
        <li><a href="#">Nav Item 2</a></li>
        <li><a href="#">Nav Item 3</a></li>
    </ul>
</header>

SCSS:

#nav {
    position: relative;
    z-index: 2;

    &:not(:target) {
        display: none;
    }

    &:target {
        display: block;
    }

}

Solution

  • You could do it by using a checkbox and show & hide the navigation by :checked selector.

    JSFiddle - DEMO 1 and DEMO 2

    HTML:

    <header id="top">
        <label for="toggle-1">Menu</label>
        <input type="checkbox" id="toggle-1">
        <ul id="nav">
            <li><a href="#top">Close Menu</a></li>
            <li><a href="#">Nav Item 1</a></li>
            <li><a href="#">Nav Item 2</a></li>
            <li><a href="#">Nav Item 3</a></li>
        </ul>
    </header>
    

    CSS:

    input[type=checkbox] {
        position: absolute;
        top: -9999px;
        left: -9999px;
    }
    input[type=checkbox]:checked ~ ul#nav {
        display: block;
    }
    #nav {
        display: none;
    }
    label {
        cursor: pointer;
    }