Skip to main content
April 1, 2026Dan Rodney/16 min read

Off-Screen Side Nav Using Only CSS

Master CSS-Only Mobile Navigation Without JavaScript

Pure CSS Solution

This tutorial demonstrates how to create fully functional off-screen navigation using only CSS - no JavaScript required. We'll leverage CSS pseudo-classes and HTML form elements for interactive behavior.

Topics Covered in This Mobile & Responsive Web Design Tutorial:

Responsive Off-screen Navigation, Toggling the Navigation with a Checkbox, CSS Transitions

Key Concepts You'll Learn

Responsive Off-screen Navigation

Learn to create mobile-friendly navigation that slides in from the side using CSS positioning and transitions.

Checkbox Toggle Technique

Master the CSS-only approach using checkboxes and labels to create interactive navigation without JavaScript.

CSS Transitions

Add smooth animations and transitions to create professional sliding effects for your navigation menu.

Exercise Preview

offscreen nav done

Exercise Overview

In this exercise, you'll master one of the most elegant solutions in responsive web design: creating an off-screen navigation menu that slides into view when activated. This technique has become a cornerstone of modern mobile UX, offering users clean, uncluttered interfaces while maintaining full navigation access. What makes this approach particularly powerful is that you'll achieve all functionality using pure CSS—no JavaScript required. This CSS-only method ensures faster load times, better accessibility, and fewer dependencies in your project stack.

By the end of this tutorial, you'll understand how to leverage CSS pseudo-classes, sibling selectors, and transitions to create professional-grade mobile navigation that rivals any JavaScript-powered solution.

What You'll Build

0/4

Styling the Nav

  1. Navigate to the Off-Screen Nav folder (Desktop > Class Files > yourname-Mobile and Responsive Class > Off-Screen Nav). Open this folder in your code editor—modern editors like Sublime Text, VS Code, or Atom allow you to open entire project folders for better file management.
  2. Preview index.html from the Off-Screen Nav folder in your browser.

    You'll notice the navigation is already coded with basic styling applied. Keep this file open in your browser throughout the exercise—live preview will help you understand how each CSS change affects the final result. This iterative approach is crucial for developing responsive design intuition.

  3. Open main.css from the css folder within the Off-Screen Nav directory. Understanding the existing CSS structure will help you see how responsive breakpoints are organized in professional projects.
  4. Locate the Media Queries comment (line 78) and add the following code below it:

    @media (max-width: 700px) {
       nav {
          position: fixed;
       }
    }

    The position: fixed property removes the navigation from the normal document flow, allowing it to overlay content—essential for off-screen navigation functionality.

  5. Save the file and reload your browser.
  6. Resize the window to mobile dimensions. Notice how the nav now sits atop the page content rather than pushing it down—this is the foundation of our off-screen behavior.
  7. Now we'll optimize the navigation dimensions for mobile use. Return to main.css.
  8. Enhance the navigation rule with width and height properties (around line 81):

    nav {
       position: fixed;
       width: 12em;
       height: 100%;
    }

    Using em units ensures the navigation scales appropriately with user font size preferences—a critical accessibility consideration. The height: 100% creates a full-screen overlay effect.

  9. Save and reload to see the updated navigation dimensions.
  10. Test the navigation's behavior by resizing your window to a very short height, simulating a phone in landscape orientation.
  11. Attempt to scroll within the navigation when content is cut off—you'll discover it's currently impossible, creating a significant usability issue on smaller screens.
  12. Solve the scrolling limitation by adding overflow properties to the nav rule:

    nav {
       position: fixed;
       width: 12em;
       height: 100%;
       overflow-y: auto;
       -webkit-overflow-scrolling: touch;
    }

    The -webkit-overflow-scrolling: touch property enables momentum scrolling on iOS devices, providing the smooth, native scrolling experience users expect.

  13. Save and test the scrolling functionality—navigation items should now be accessible regardless of screen height.
  14. Switch back to desktop view (resize window wider than 700px) to style the large-screen navigation.
  15. Return to main.css and add a complementary media query for desktop screens:
  16. After the mobile media query, add this desktop-focused rule:

    @media (min-width: 701px) {
       nav ul li {
          display: inline-block;
       }
    }

    This creates a horizontal navigation layout appropriate for desktop screens where vertical space is at a premium but horizontal space is abundant.

  17. Save and reload—the navigation now displays as a single horizontal row on desktop.
  18. Fine-tune the desktop navigation alignment by returning to your editor.
  19. Expand the desktop media query with navigation positioning:

    @media (min-width: 701px) {
       nav {
          text-align: right;
          padding-right:.6em;
       }
       nav ul li {
          display: inline-block;
       }
    }

    Right-aligned navigation follows established web conventions and creates better visual hierarchy with left-aligned logos or content.

  20. Save and reload to see the improved desktop layout.
  21. Test your responsive navigation by resizing the browser window. You should now have a solid foundation that adapts appropriately to both mobile and desktop contexts.

With the basic navigation styling complete, we'll now implement the interactive mechanism that allows users to show and hide the mobile menu. The next section introduces a clever CSS-only technique using checkboxes and labels.

Mobile vs Desktop Navigation Layout

FeatureMobile (max-width: 700px)Desktop (min-width: 701px)
PositionFixed sidebarTop horizontal bar
DisplayVertical stackInline-block
Width12em fixed widthFull width with right alignment
ScrollingVertical scroll enabledNo scroll needed
Recommended: Use media queries at 700px breakpoint for optimal responsive behavior
Overflow Scrolling Best Practice

Adding overflow-y: auto and -webkit-overflow-scrolling: touch ensures navigation items remain accessible even on small screens or when held horizontally.

Adding a Clickable Element to Open & Close the Nav

Creating interactive elements without JavaScript requires leveraging HTML form controls in creative ways. The checkbox input type provides a perfect solution because it maintains state (checked/unchecked) and offers the :checked pseudo-class selector. This CSS-only approach to interactive navigation has become increasingly popular among performance-conscious developers, as it eliminates JavaScript dependencies while providing rock-solid functionality across all browsers.

  1. Open index.html in your code editor to add the control mechanism.
  2. Insert the checkbox input immediately after the opening body tag:

    <body>
       <input id="nav-checkbox" type="checkbox">
       <img src="img/nyc-logo.svg" class="nyc-logo" ALT="NYC Logo">

    Positioning the checkbox early in the DOM is crucial for the CSS sibling selectors we'll use later. HTML order directly impacts CSS selector functionality.

  3. Save the HTML file and switch to main.css.
  4. Add basic positioning for the checkbox below the nav li a:hover rule (around line 73):

    #nav-checkbox {
       position: absolute;
       left: 50%;
    }

    We're temporarily making the checkbox visible and centered for testing purposes—this helps debug the functionality before hiding the element.

  5. Save and reload your browser. The small checkbox should appear centered at the top of the page.
  6. Now we'll connect the checkbox state to navigation visibility. Return to main.css.
  7. Within the mobile media query (max-width: 700px), add this rule after the nav styling (around line 85):

    #nav-checkbox:checked ~ nav {
       display: none;
    }

    This CSS uses the general sibling combinator (~) to target the navigation when preceded by a checked checkbox. The relationship only works when both elements share the same parent and the checkbox appears first in the HTML structure—this is why element order matters in CSS-based interactions.

  8. Save and reload, ensuring your browser window is narrower than 700px.

  9. Test the checkbox functionality by clicking it—the navigation should disappear when checked and reappear when unchecked. This demonstrates the core mechanism we'll build upon.

The checkbox provides the foundation for our interactive navigation, but we need to refine the behavior and create a more user-friendly interface. The next section transforms this basic functionality into a professional off-screen sliding menu.

A checkbox has a :checked pseudo-class selector that allows us to style an element based on whether the element is checked or not
This is the core technique that enables CSS-only interactivity without JavaScript

Checkbox Toggle Implementation

1

Add Checkbox Input

Place checkbox with unique ID directly after opening body tag for proper DOM positioning

2

Style Checkbox Position

Position checkbox temporarily in visible location for testing purposes

3

Create Checked State Rule

Use sibling selector to target nav element when checkbox is checked

Moving the Nav Off-Screen

Professional off-screen navigation doesn't simply appear and disappear—it slides smoothly into view, providing visual continuity and a polished user experience. Instead of using display: none, we'll position the navigation off-screen and use CSS transforms to slide it into view. This approach also enables smooth CSS transitions that make the interaction feel responsive and intentional.

  1. Return to main.css to implement the off-screen positioning.
  2. Modify the navigation rule within the mobile media query to include off-screen positioning:

    nav {
       position: fixed;
       width: 12em;
       left: -12em;
       height: 100%;
       overflow-y: auto;
       -webkit-overflow-scrolling: touch;
       z-index: 100;
    }

    The negative left value must exactly match the navigation width to ensure complete concealment. The z-index ensures the navigation appears above other page elements when visible—essential for overlay functionality.

  3. Update the checkbox-triggered rule to bring the navigation on-screen:

    #nav-checkbox:checked ~ nav {
       left: 0;
    }

    This changes the navigation position from off-screen (-12em) to fully visible (0) when the checkbox is checked.

  4. Save and reload your browser to test the updated functionality.
  5. Toggle the checkbox to see the navigation appear and disappear. The functionality works, but the abrupt movement lacks professional polish.

    CSS transitions will transform this jarring change into smooth, animated movement that feels natural and responsive.

  6. Add visual polish with CSS transitions. Return to main.css.
  7. Enhance the navigation rule with a transition property:

    nav {
       position: fixed;
       width: 12em;
       left: -12em;
       height: 100%;
       overflow-y: auto;
       -webkit-overflow-scrolling: touch;
       z-index: 100;
       transition: all.2s ease;
    }

    The transition applies to all animatable properties (in this case, the left position), with a duration of 0.2 seconds and easing function for natural movement. This timing strikes the right balance—quick enough to feel responsive, slow enough to appear smooth.

  8. Save and reload to experience the enhanced interaction.
  9. Toggle the checkbox to see the navigation slide smoothly from the side. This small addition significantly improves the perceived quality and professionalism of the interface.

The smooth sliding animation elevates the user experience, but the checkbox interface remains unsuitable for real users. The following section replaces this developer testing tool with proper user interface elements.

Critical Positioning Rule

The left position value must be equal to the width of the element to ensure the entire navigation is hidden off-screen. In this case, width: 12em requires left: -12em.

Essential CSS Properties for Off-Screen Navigation

Negative Positioning

Use left: -12em to move the 12em wide navigation completely off-screen to the left.

Z-Index Layering

Set z-index: 100 to ensure navigation appears above all other page content when visible.

Smooth Transitions

Add transition: all .2s ease for professional sliding animation instead of abrupt appearance.

Adding a Proper Menu Button

While checkboxes provide excellent functionality for CSS-only interactions, they're not intuitive interface elements for navigation control. HTML form labels offer the perfect solution—they can trigger associated form controls when clicked, and they can be styled to look like proper buttons. This technique maintains the CSS-only approach while providing a professional user interface that meets modern usability expectations.

  1. Open index.html to add a user-friendly menu trigger.
  2. Add a label element immediately after the checkbox input:

    <input id="nav-checkbox" type="checkbox" >
    <label for="nav-checkbox" class="menu-button">MENU</label>

    The for attribute creates an association with the checkbox's id. This relationship allows the label to control the checkbox state, enabling our CSS-only interaction system.

  3. Save the HTML and switch to main.css for styling.
  4. Within the mobile media query, add styling for the menu button after the checkbox rule:

    .menu-button {
       position: absolute;
       top: 10px;
       right: 10px;
       color: #fff;
    }

    Positioning the menu button in the upper-right corner follows established mobile navigation conventions and ensures it's easily accessible with thumb navigation.

  5. Save and reload your browser to see the new menu button.
  6. Test the button functionality by clicking "MENU" in the upper-right corner. You should notice:

    • The checkbox state changes even though you're clicking the label—this demonstrates the form association working correctly.
    • The cursor doesn't change to a pointer when hovering over the button, which may confuse users expecting clickable feedback.
    • Double-clicking the button selects the text like a paragraph rather than behaving like a button, breaking the interface illusion.
  7. Address these usability issues by enhancing the button styling. Return to main.css.
  8. Expand the .menu-button rule with interactive improvements:

    .menu-button {
       position: absolute;
       top: 10px;
       right: 10px;
       color: #fff;
       cursor: pointer;
       -webkit-user-select: none;
       -moz-user-select: none;
       -ms-user-select: none;
       user-select: none;
    }

    The cursor: pointer provides visual feedback consistent with other clickable elements. The user-select: none properties (with vendor prefixes for maximum compatibility) prevent text selection, making the label behave like a proper button.

  9. Save and reload to test the improvements.
  10. Verify that hovering shows the pointer cursor and double-clicking no longer selects text.
  11. Test the button at different screen sizes. When you resize beyond 700px, the menu button should be hidden since desktop users need the always-visible horizontal navigation.
  12. Add responsive visibility rules in main.css.
  13. Within the desktop media query (min-width: 701px), add a rule to hide the mobile menu button:

    .menu-button {
       display: none;
    }

    This ensures the menu button only appears on mobile devices where the off-screen navigation is active.

  14. Save and reload to verify the button disappears in desktop view while remaining functional on mobile.
  15. Return to mobile view to continue development.

With a functional menu button in place, users can now open the navigation menu. However, they need an equally clear way to close it. The next section adds multiple closing mechanisms to enhance usability.

Form Label Technique

Labels with matching 'for' attributes can control form elements. When you click a label, it focuses or checks the associated form element, enabling our CSS-only toggle functionality.

User Experience Improvements

0/3

Adding a Close Button

Excellent mobile navigation provides multiple ways to close an open menu—both explicit close buttons and intuitive gestures like tapping outside the menu area. This redundancy ensures users never feel trapped in an interface state, which is crucial for mobile usability where screen real estate is limited and users expect efficient navigation patterns.

  1. Open index.html to add an internal close mechanism.
  2. Insert a close button at the top of the navigation element (around line 16):

    <nav>
       <label for="nav-checkbox" class="close-button">
          <img src="img/close.svg" ALT="close">
       </label>
       <ul>

    Notice this label uses the same for attribute as the menu button. Multiple labels can control a single checkbox, allowing us to create different interface elements that all trigger the same functionality—a powerful pattern in CSS-only interactions.

  3. Switch to main.css to style the close button appropriately.
  4. Within the mobile media query, add styling for the close button after the menu button rule:

    .close-button img {
       width: 30px;
       margin: 15px;
       cursor: pointer;
    }

    Styling the image rather than the label directly provides more precise control over sizing and spacing. The generous margin ensures the close button is easily tappable on touch devices.

  5. Ensure the close button remains hidden on desktop by updating the desktop media query. Modify the existing rule to include both buttons:

    .menu-button,.close-button img {
       display: none;
    }

    The comma creates a selector group, applying the same styles to both elements efficiently.

  6. Save and reload your browser.
  7. Test the dual-button functionality: click "MENU" to open the navigation, then click the circular close button to close it.

    The system works immediately because both labels control the same checkbox. When the menu opens (checkbox checked), clicking either label unchecks the box and closes the menu. This demonstrates the elegant simplicity of the CSS-only approach.

Users now have a clear, visible way to close the navigation menu. However, modern mobile interfaces also support closing menus by tapping outside the content area—a pattern users expect from native mobile applications. The next section implements this advanced usability feature.

We can have multiple labels for the same checkbox, allowing us to create two different buttons that both control a single checkbox
This demonstrates the flexibility of the CSS-only approach using HTML form relationships

Creating an Overlay

Professional mobile interfaces allow users to close overlay menus by tapping outside the content area—a pattern so common it's become an expected behavior. Implementing this with CSS-only techniques requires creating an invisible clickable area that covers the entire screen behind the navigation menu. This overlay serves dual purposes: it provides the tap-to-close functionality users expect, and it can include a subtle background tint that helps focus attention on the navigation content.

  1. Return to index.html to add the overlay element.
  2. Insert an overlay label immediately after the menu button:

    <label for="nav-checkbox" class="menu-button">MENU</label>
    <label for="nav-checkbox" class="overlay"></label>

    This empty label will expand to cover the entire screen, providing a large click target for closing the menu.

  3. Switch to main.css to implement the overlay functionality.
  4. Within the mobile media query, add overlay styling after the close button rule:

    .overlay {
       position: fixed;
       height: 100%;
       width: 100%;
       background: rgba(0,0,0,.5);
    }

    The position: fixed with full dimensions creates a screen-covering element. The semi-transparent black background provides visual feedback that content behind the menu is temporarily inaccessible.

  5. Save and reload to see the overlay effect.
  6. Click anywhere on the darkened area—notice the menu opens because the overlay is another label controlling the same checkbox.
  7. The overlay should only appear when the menu is open, not constantly. Return to main.css to fix this behavior.
  8. Hide the overlay by default by adding to the existing rule:

    .overlay {
       display: none;
       position: fixed;
       height: 100%;
       width: 100%;
       background: rgba(0,0,0,.5);
    }
  9. Create a rule to show the overlay only when the menu is open:

    #nav-checkbox:checked ~.overlay {
       display: block;
    }

    This selector targets the overlay only when it follows a checked checkbox, creating the conditional visibility we need.

  10. Save and reload to test the refined behavior.
  11. Open the menu using the "MENU" button—the overlay should appear with its darkened background.
  12. Click anywhere on the dark area to close the menu, demonstrating the tap-outside-to-close functionality.
  13. The dark background provides good visual feedback, but some designs prefer invisible overlays that maintain functionality without visual distraction.
  14. To create an invisible overlay, return to main.css and remove the background property from the .overlay rule.
  15. Save and reload to test.
  16. The menu still closes when you click outside it, but without the visual background tint. Choose the approach that best fits your design requirements.

The overlay completes our interactive functionality, giving users multiple intuitive ways to control the navigation menu. However, the original checkbox remains visible, serving no user purpose now that we have proper interface controls. The final section addresses this cleanup.

Overlay Implementation Process

1

Create Full-Screen Label

Add label element that covers entire viewport with position: fixed and 100% dimensions

2

Add Conditional Visibility

Use display: none by default, then show with #nav-checkbox:checked ~ .overlay selector

3

Remove Visual Background

Delete background property to maintain click functionality while keeping overlay invisible

Hiding the Checkbox with CSS

With our label-based interface complete, the original checkbox serves purely as a functional element that should be hidden from users. Simply using display: none might seem obvious, but this approach can create accessibility issues by removing the element from keyboard navigation entirely. Professional developers use the CSS clip property to visually hide elements while maintaining their presence in the accessibility tree.

  1. Return to main.css to properly hide the checkbox.
  2. Locate the #nav-checkbox rule in the general styles section (around line 76).
  3. Remove the temporary left: 50% positioning we used for testing.
  4. Replace the positioning with accessibility-friendly hiding techniques:

    #nav-checkbox {
       position: fixed;
       clip: rect(0,0,0,0);
    }

    Key considerations for this approach:

    • The clip property visually hides the element while preserving accessibility—screen readers and keyboard navigation still function properly.
    • Changing to position: fixed prevents some browsers (particularly Chrome) from jumping to the top of the page when the checkbox state changes.
    • While the clip property is technically deprecated in favor of clip-path, the newer property lacks support in Internet Explorer and Edge as of 2026. The clip property provides better cross-browser compatibility for this use case.
  5. Save the file and reload your browser for final testing.
  6. Thoroughly test all functionality: menu button opening, close button functionality, tap-outside-to-close behavior, and responsive breakpoint transitions. The navigation should work flawlessly without any visible checkbox.

Congratulations! You've built a professional-grade, CSS-only off-screen navigation system that rivals JavaScript-powered solutions while maintaining better performance and accessibility. This technique forms the foundation for countless modern responsive navigation patterns.

Checkbox Hiding Methods

Featureclip: rect(0,0,0,0)display: none
AccessibilityMaintains keyboard navigationRemoves from tab order
Browser SupportUniversal supportUniversal support
FunctionalityPreserves all interactionsBreaks some interactions
Recommended: Use clip property despite deprecation for better accessibility and browser compatibility
Position Fixed Prevents Jumping

Changing checkbox position to fixed prevents browsers like Chrome from jumping to the top of the page when the checkbox is toggled.

Optional Bonus: Flipping the Nav to the Right Side

Design flexibility is one of the strengths of this CSS-only approach. With minimal changes, you can adapt the navigation to slide in from different directions, accommodating various design requirements or cultural preferences (such as right-to-left reading languages where right-side navigation might feel more natural).

  1. To demonstrate this flexibility, return to main.css.
  2. Within the mobile media query, change the positioning properties from left to right in both navigation rules:

    nav {
       position: fixed;
       width: 12em;
       right: -12em;
       height: 100%;
       overflow-y: auto;
       -webkit-overflow-scrolling: touch;
       z-index: 100;
       transition: all.2s ease;
    }
    #nav-checkbox:checked ~ nav {
       right: 0;
    }

    This simple change repositions the off-screen navigation to the right side while maintaining all functionality.

  3. Save and reload to test the right-side sliding navigation.
  4. The navigation now enters from the right side, demonstrating how easily this technique adapts to different design requirements.

  5. For additional learning, explore the Slide-Down Top Nav Using Only CSS bonus exercise later in this book, which shows how similar principles can create top-sliding navigation menus.

Easy Customization

The entire navigation can be flipped to slide in from the right by simply changing 'left' properties to 'right' in two CSS rules. This demonstrates the flexibility of the CSS-only approach.

Key Takeaways

1CSS-only navigation is possible using checkbox inputs and the :checked pseudo-class selector, eliminating the need for JavaScript
2Media queries at 700px provide optimal breakpoint for switching between mobile off-screen and desktop horizontal navigation layouts
3Multiple label elements can control a single checkbox, enabling menu button, close button, and overlay functionality with one form element
4The clip property is preferred over display: none for hiding checkboxes because it maintains accessibility for keyboard users
5Negative positioning equal to element width ensures complete off-screen hiding, while z-index controls layering when visible
6CSS transitions with ease timing create professional sliding animations that enhance user experience without performance overhead
7Form label and input relationships provide semantic HTML structure that supports both functionality and accessibility requirements
8Overflow scrolling properties ensure navigation remains usable on small screens and different device orientations

RELATED ARTICLES