Barra de navegación de Bootstrap sin JavaScript

Bootstrap se distribuye con un archivo JavaScript llamado bootstrap.js que requiere jQuery. Este archivo permite, entre otras cosas, hacer funcionar la barra de navegación cuando hay menús desplegables, y desplegar y ocultar los enlaces de navegación, que se encuentran ocultos en pantallas con baja resolución.

El problema es que Bootstrap no ofrece la misma funcionalidad básica sin JavaScript. Es decir, si no tienes JavaScript activado, no puedes acceder a los menús desplegables ni ocultar y mostrar el menú de navegación en dispositivos móviles o con baja resolución. Sin embargo, es posible ofrecer esta funcionalidad sin JavaScript. En este artículo os muestro cómo hacerlo.

Para empezar vamos a crear un menú de navegación que funciona con JavaScript. Recuerda asegurarte de que la ruta de los archivos JavaScript y CSS es correcta; puedes descargarlos y guardarlos en las carpetas css y js en el mismo directorio donde se encuentra el archivo HTML. La versión de Bootstrap utilizada es la 3.3.7.

<!DOCTYPE html>
<html lang="es">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width">
    <title>Con 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>
  </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="#">Otra sección</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">Software libre <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>

Puedes comprobar cómo funciona este ejemplo. Cuando pulsas el menú desplegable llamado «Software libre», aparecen otras opciones debajo; cuando la resolución es pequeña, basta con pulsar un botón para mostrar y ocultar el menú de navegación. Pero estas dos funcionalidades no funcionan cuando JavaScript está desactivado.

¿Para una página tan sencilla es necesario cargar jQuery y bootstrap.js? No. Vamos a dejar de utilizarlos y realizar la misma funcionalidad con CSS.

Los cambios que debemos realizar son los siguientes, las líneas borradas empiezan por - y las nuevas por + (salida obtenida con la instrucción diff -u con-javascript.html sin-javascript.html):

--- con-javascript.html 2017-09-16 15:02:49.883637402 +0200
+++ sin-javascript.html 2017-09-22 11:30:50.332252781 +0200
@@ -3,21 +3,37 @@
   <head>
     <meta charset="UTF-8">
     <meta name="viewport" content="width=device-width">
-    <title>Con JavaScript | Barra de navegación de Bootstrap</title>
+    <title>Sin 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">

El código fuente completo se muestra a continuación.

<!DOCTYPE html>
<html lang="es">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width">
    <title>Sin 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="#">Otra sección</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">Software libre <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>

Puedes comprobar cómo funciona este ejemplo. Ahora no hace falta pulsar en «Software libre», sino simplemente pasar el ratón por encima. El botón para ocultar y mostrar los enlaces en resoluciones menores ha sido reemplazado en la versión sin JavaScript por una casilla de verificación oculta. La casilla de verificación se activa al pulsar el elemento <label> que está asociado a esta (for="navbar-toggle-cbox"). Cuando la casilla está activa, se muestran con CSS (display: block) los enlaces del menú de navegación.

A diferencia de la versión con JavaScript, la versión sin JavaScript no cuenta con una animación cuando se oculta o se muestra el menú de navegación. Es imposible hacer cambiar de valor el atributo aria-expanded (el cual debería cambiar a true cuando el menú está desplegado), así que se debe eliminar. Además, puede que para dispositivos móviles no sea suficiente usar el pseudoelemento :hover. Lo más recomendable, en mi opinión, es evitar usar un menú desplegable en la barra de navegación.

En conclusión, si estamos usando otras funcionalidades que ofrece el archivo bootstrap.js o no queremos perder funcionalidad, no tiene sentido eliminarlo.

Lo que se debe hacer para que le funcione bien a todo el mundo1 es incluir el código que añadimos en la versión sin JavaScript dentro de la etiqueta <noscript> para que la página web les funcione tanto a quienes activan JavaScript como a quienes no. Para ocultar el botón que se necesita en la versión con JavaScript cuando JavaScript esté desactivado se puede asignar un id al botón y darle el valor display: none. La solución la reproduzco a continuación.

<!DOCTYPE html>
<html lang="es">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width">
    <title>Con JavaScript y sin 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>
      #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="#">Otra sección</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">Software libre <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>

Puedes comprobar cómo funciona este ejemplo. Las diferencias entre la versión con JavaScript y esta solución son las siguientes:

--- con-javascript.html 2017-09-16 15:02:49.883637402 +0200
+++ con-y-sin-js.html   2017-09-22 11:31:18.527150186 +0200
@@ -3,17 +3,49 @@
   <head>
     <meta charset="UTF-8">
     <meta name="viewport" content="width=device-width">
-    <title>Con JavaScript | Barra de navegación de Bootstrap</title>
+    <title>Con JavaScript y sin 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>
+      #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. Obviamente quienes desactiven JavaScript tendrán algo menos de funcionalidad, pero la página será usable. 

Comentarios