Bootstrap navigation bar without JavaScript

Bootstrap is distributed with a JavaScript file called bootstrap.js which requires jQuery. This file allows, among other things, making the navigation bar work when there are dropdown menus, and toggle the navigation links, which are hidden in low-resolution screens.

The problem is that Bootstrap doesn't offer the same basic functionality without JavaScript. Namely, if you don't have JavaScript enabled, you cannot access the dropdown menu nor toggle the navigation menu in mobile or low-resolution devices. However, it's possible to offer this features without JavaScritp. In this article I show you how to do it.

First, we are going to create a navigation bar which works with JavaScript. Remember to make sure that the path of the JavaScript and CSS files is correct; you can download them and save them in the css and js folders in the same directory where the HTML file is found. The version of Bootstrap used is the 3.3.7.

<!DOCTYPE html>
<html lang="es">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width">
    <title>With JavaScript | Bootstrap navigation bar</title>
    <link rel="stylesheet" href="css/bootstrap.css" type="text/css">
    <script src="/theme/js/jquery-3.1.1.min.js"></script>
    <script src="js/bootstrap.js"></script>
  </head>
  <body>
    <nav class="navbar navbar-default navbar-fixed-top">
      <div class="container">
        <div class="navbar-header">
          <a href="/" class="navbar-brand">Freak Spot</a>
          <button aria-expanded="false" class="navbar-toggle" type="button" data-toggle="collapse" data-target="#navbar-main">
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
          </button>
        </div>
        <div class="navbar-collapse collapse" id="navbar-main">
          <ul class="nav navbar-nav">
            <li>
              <a href="#">Another section</a>
            </li>
            <li>
              <a href="https://es.wikipedia.org/wiki/Wikipedia:Portada">Wikipedia</a>
            </li>
            <li class="dropdown">
              <a class="dropdown-toggle" data-toggle="dropdown" href="#" id="themes">Free Software <span class="caret"></span></a>
              <ul class="dropdown-menu" aria-labelledby="themes">
                <li><a href="https://www.fsf.org/">FSF</a></li>
                <li><a href="https://www.gnu.org/">GNU</a></li>
                <li><a href="https://peers.community/">Peers Community</a></li>
              </ul>
            </li>
          </ul>
        </div>
      </div>
    </nav>
  </body>
</html>

You can find out how this example works. When you press on the togglable menu called "Free Software", other options appear below; when the resolution is small, you just have to press a button to toggle the navigation menu. But these two functionalities don't work when JavaScript is disabled.

The changes we must do are the following, the removed lines start with - and the new ones with +, (output obtained with the command diff -u with-javascript.html without-javascript.html):

--- with-javascript.html    2017-09-16 15:02:54.167637691 +0200
+++ without-javascript.html 2017-09-22 11:32:11.008899729 +0200
@@ -3,21 +3,37 @@
   <head>
     <meta charset="UTF-8">
     <meta name="viewport" content="width=device-width">
-    <title>With JavaScript | Bootstrap navigation bar</title>
+    <title>Without JavaScript | Barra de navegación de Bootstrap</title>
     <link rel="stylesheet" href="css/bootstrap.css" type="text/css">
-    <script src="/theme/js/jquery-3.1.1.min.js"></script>
-    <script src="js/bootstrap.js"></script>
+    <style>
+      .dropdown:hover > .dropdown-menu {
+        display: block;
+      }
+
+      label[for=navbar-toggle-cbox] {
+        cursor: pointer;
+      }
+
+      #navbar-toggle-cbox:checked ~ .collapse {
+        display: block;
+      }
+
+      #navbar-toggle-cbox {
+        display: none;
+      }
+    </style>
   </head>
   <body>
     <nav class="navbar navbar-default navbar-fixed-top">
       <div class="container">
+        <input aria-controls="navbar-main" id="navbar-toggle-cbox" role="button" type="checkbox">
         <div class="navbar-header">
           <a href="/" class="navbar-brand">Freak Spot</a>
-          <button aria-expanded="false" class="navbar-toggle" type="button" data-toggle="collapse" data-target="#navbar-main">
+          <label class="navbar-toggle collapsed" for="navbar-toggle-cbox">
             <span class="icon-bar"></span>
             <span class="icon-bar"></span>
             <span class="icon-bar"></span>
-          </button>
+          </label>
         </div>
         <div class="navbar-collapse collapse" id="navbar-main">
           <ul class="nav navbar-nav">

The complete source code is shown below.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width">
    <title>Without JavaScript | Barra de navegación de Bootstrap</title>
    <link rel="stylesheet" href="css/bootstrap.css" type="text/css">
    <style>
      .dropdown:hover > .dropdown-menu {
        display: block;
      }

      label[for=navbar-toggle-cbox] {
        cursor: pointer;
      }

      #navbar-toggle-cbox:checked ~ .collapse {
        display: block;
      }

      #navbar-toggle-cbox {
        display: none;
      }
    </style>
  </head>
  <body>
    <nav class="navbar navbar-default navbar-fixed-top">
      <div class="container">
        <input aria-controls="navbar-main" id="navbar-toggle-cbox" role="button" type="checkbox">
        <div class="navbar-header">
          <a href="/" class="navbar-brand">Freak Spot</a>
          <label class="navbar-toggle collapsed" for="navbar-toggle-cbox">
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
          </label>
        </div>
        <div class="navbar-collapse collapse" id="navbar-main">
          <ul class="nav navbar-nav">
            <li>
              <a href="#">Another Section</a>
            </li>
            <li>
              <a href="https://en.wikipedia.org/wiki/Main_Page">Wikipedia</a>
            </li>
            <li class="dropdown">
              <a class="dropdown-toggle" data-toggle="dropdown" href="#" id="themes">Free Software <span class="caret"></span></a>
              <ul class="dropdown-menu" aria-labelledby="themes">
                <li><a href="https://www.fsf.org/">FSF</a></li>
                <li><a href="https://www.gnu.org/">GNU</a></li>
                <li><a href="https://peers.community/">Peers Community</a></li>
              </ul>
            </li>
          </ul>
        </div>
      </div>
    </nav>
  </body>
</html>

You can find out how this example works. Now, pressing on "Free Software" is not necessary, you can simply hover it with the mouse. The button for toggling the links in smaller resolution has been replaced in the version without JavaScript with a hidden checkbox. The checkbox is activated pressing the <label> element that is associated with it (for="navbar-toggle-cbox"). When the checkbox is active, the links of the navigation menu are shown with CSS (display: block).

Unlike the JavaScript version, the version without JavaScript doesn't have an animation when you toggle the navigation menu. It's impossible to change the value of the attribute aria-expanded (which should change to true when the menu is shown), so it must be removed. Furthermore, maybe it's not enough to use the pseudoelement :hover. In my opinion, the best thing is to avoid using a dropdown menu in the navigation bar.

To sum up, if we are using other features offered by the file bootstrap.js or we don't want to lose any functionality, there is no point in removing it.

What we must do to make it work for everyone1 is include the code we added to the version without JavaScript inside the <noscript> tag, so that the website works for people who enable JavaScript and people who don't. To hide the button needed for the JavaScript version when JavaScript is disabled, we can assign an id to the button and give it the value display: none. The solution is shown below.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width">
    <title>With JavaScript and without JavaScript | Bootstrap navigation bar</title>
    <link rel="stylesheet" href="css/bootstrap.css" type="text/css">
    <script src="/theme/js/jquery-3.1.1.min.js"></script>
    <script src="js/bootstrap.js"></script>
    <style>
      #navbar-toggle-cbox {
        display: none;
      }
    </style>
    <noscript>
      <style>
        .dropdown:hover > .dropdown-menu {
          display: block;
        }

        label[for=navbar-toggle-cbox] {
          cursor: pointer;
        }

        #navbar-toggle-cbox:checked ~ .collapse {
          display: block;
        }

        #toggle-navbar {
          display: none;
        }
      </style>
    </noscript>
  </head>
  <body>
    <nav class="navbar navbar-default navbar-fixed-top">
      <div class="container">
        <input aria-controls="navbar-main" id="navbar-toggle-cbox" role="button" type="checkbox">
        <div class="navbar-header">
          <a href="/" class="navbar-brand">Freak Spot</a>
          <noscript>
            <label class="navbar-toggle" for="navbar-toggle-cbox">
              <span class="icon-bar"></span>
              <span class="icon-bar"></span>
              <span class="icon-bar"></span>
            </label>
          </noscript>
          <button aria-expanded="false" class="navbar-toggle" id="toggle-navbar" type="button" data-toggle="collapse" data-target="#navbar-main">
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
          </button>
        </div>
        <div class="navbar-collapse collapse" id="navbar-main">
          <ul class="nav navbar-nav">
            <li>
              <a href="#">Another Section</a>
            </li>
            <li>
              <a href="https://en.wikipedia.org/wiki/Main_Page">Wikipedia</a>
            </li>
            <li class="dropdown">
              <a class="dropdown-toggle" data-toggle="dropdown" href="#" id="themes">Free Software <span class="caret"></span></a>
              <ul class="dropdown-menu" aria-labelledby="themes">
                <li><a href="https://www.fsf.org/">FSF</a></li>
                <li><a href="https://www.gnu.org/">GNU</a></li>
                <li><a href="https://peers.community/">Peers Community</a></li>
              </ul>
            </li>
          </ul>
        </div>
      </div>
    </nav>
  </body>
</html>

You can find out how this example works. The differences between the version with JavaScript and this solution are the following:

--- with-javascript.html    2017-09-16 15:02:54.167637691 +0200
+++ with-and-without-js.html    2017-09-22 11:32:31.276762097 +0200
@@ -3,17 +3,49 @@
   <head>
     <meta charset="UTF-8">
     <meta name="viewport" content="width=device-width">
-    <title>With JavaScript | Bootstrap navigation bar</title>
+    <title>With JavaScript and without JavaScript | Bootstrap navigation bar</title>
     <link rel="stylesheet" href="css/bootstrap.css" type="text/css">
     <script src="/theme/js/jquery-3.1.1.min.js"></script>
     <script src="js/bootstrap.js"></script>
+    <style>
+      #navbar-toggle-cbox {
+        display: none;
+      }
+    </style>
+    <noscript>
+      <style>
+        .dropdown:hover > .dropdown-menu {
+          display: block;
+        }
+
+        label[for=navbar-toggle-cbox] {
+          cursor: pointer;
+        }
+
+        #navbar-toggle-cbox:checked ~ .collapse {
+          display: block;
+        }
+
+        #toggle-navbar {
+          display: none;
+        }
+      </style>
+    </noscript>
   </head>
   <body>
     <nav class="navbar navbar-default navbar-fixed-top">
       <div class="container">
+        <input aria-controls="navbar-main" id="navbar-toggle-cbox" role="button" type="checkbox">
         <div class="navbar-header">
           <a href="/" class="navbar-brand">Freak Spot</a>
-          <button aria-expanded="false" class="navbar-toggle" type="button" data-toggle="collapse" data-target="#navbar-main">
+          <noscript>
+            <label class="navbar-toggle" for="navbar-toggle-cbox">
+              <span class="icon-bar"></span>
+              <span class="icon-bar"></span>
+              <span class="icon-bar"></span>
+            </label>
+          </noscript>
+          <button aria-expanded="false" class="navbar-toggle" id="toggle-navbar" type="button" data-toggle="collapse" data-target="#navbar-main">
             <span class="icon-bar"></span>
             <span class="icon-bar"></span>
             <span class="icon-bar"></span>

  1. Obviously, the ones who disable JavaScript will have less features, but the website will be usable. 

Comments