Pestañas que se adaptan al contenedor con el botón “Más”

Índice
  1. Planificación
  2. prototipo inicial
  3. Ocultar y mostrar pestañas en las listas
  4. Mejoras
  5. Casos extremos
  6. Algo a tener en cuenta
  7. Compatibilidad del navegador

O el patrón de navegación prioritario, o el menú de navegación que se contrae progresivamente. Podemos denominarlo al menos de tres formas.

Existen múltiples soluciones UX para pestañas y menús y cada una de ellas tiene sus propias ventajas sobre otras, solo necesitas elegir la mejor para el caso que estás tratando de resolver. En la agencia de diseño y desarrollo Kollegorna estábamos debatiendo sobre la técnica UX para pestañas más adecuada para la web de nuestros clientes…

Estuvimos de acuerdo en que debería ser de una sola línea porque se desconoce la cantidad de elementos de pestaña y redujimos nuestras opciones a dos: desplazamiento horizontal y adaptable con el botón “más”. En primer lugar, el problema con el primero es que el desplazamiento horizontal como característica no siempre es visualmente obvio para los usuarios (especialmente para elementos estrechos como pestañas), mientras que ¿qué otra cosa puede ser más obvia que un botón (“más”? ?), verdad? En segundo lugar, desplazarse horizontalmente usando un dispositivo controlado por mouse no es algo muy cómodo, por lo que es posible que necesitemos hacer nuestra interfaz de usuario más compleja con botones de flecha adicionales. Considerando todo esto, terminamos eligiendo la última opción:

Planificación

La principal intriga aquí es si es posible lograrlo sin JavaScript. En parte sí, sin embargo, las limitaciones que conllevan probablemente hagan que solo sea bueno para un museo conceptual en lugar de escenarios de la vida real (de todos modos, Kenan hizo un trabajo realmente bueno). Aún así, la dependencia de JS no significa que no podamos hacerlo utilizable si por alguna razón la tecnología no está disponible. ¡Mejora progresiva y degradación elegante para ganar!

Dado que la cantidad de elementos de la pestaña es incierta o volátil, utilizaremos Flexbox, que garantiza que los elementos estén bien distribuidos en el elemento contenedor sin establecer los anchos.

prototipo inicial

Hay dos listas, tanto visuales como técnicas: una es para los artículos que caben en el contenedor y otra para los artículos que no. Dado que dependeremos de JavaScript, es bueno tener nuestro marcado inicial con una sola lista (la duplicaremos con JS):

end', ` li button type="button" aria-haspopup="true" aria-expanded="false" More darr; /button ul ${primary.innerHTML} /ul /li`)const secondary = container.querySelector('.-secondary')const secondaryItems = secondary.querySelectorAll('li')const allItems = container.querySelectorAll('li')const moreLi = primary.querySelector('.-more')const moreBtn = moreLi.querySelector('button')moreBtn.addEventListener('click', (e) = { e.preventDefault() container.classList.toggle('--show-secondary') moreBtn.setAttribute('aria-expanded', container.classList.contains('--show-secondary'))})

Aquí anidamos la lista secundaria en la primaria y usamos algunas aria-*propiedades. Queremos que nuestro menú de navegación sea accesible, ¿verdad?

También hay un controlador de eventos adjunto al botón “más” que alterna el --show-secondarynombre de la clase en el elemento contenedor. Lo usaremos para mostrar y ocultar la lista secundaria. Ahora diseñamos las piezas nuevas. Es posible que desees resaltar visualmente el botón “más”.

.tabs {  position: relative;}.tabs .-secondary {  display: none;  position: absolute;  top: 100%;  right: 0;}.tabs.--show-secondary .-secondary {  display: block;}

Aquí es donde eso nos llevó:

Obviamente, necesitamos algún código que oculte y muestre las pestañas…

Ocultar y mostrar pestañas en las listas

Gracias a Flexbox, los elementos de las pestañas nunca se dividirán en varias líneas y se reducirán a su ancho mínimo posible. Esto significa que podemos recorrer cada elemento uno por uno, sumar sus anchos, compararlos con el ancho del .tabselemento y alternar la visibilidad de pestañas particulares en consecuencia. Para eso, crearemos una función llamada doAdapty la incluiremos en el código que aparece a continuación en esta sección.

Para comenzar con el ancho, debemos revelar visualmente todos los elementos:

allItems.forEach((item) = {  item.classList.remove('--hidden')})

En una nota al margen, .--hiddenfunciona de la manera que probablemente esperabas:

.tabs .--hidden {  display: none;}

¡Hora de matemáticas! Tendré que decepcionarte si esperabas algo de matemáticas avanzadas. Entonces, como se describió anteriormente, recorremos cada pestaña principal sumando sus anchos en stopWidthvariable. También verificamos si el elemento cabe en el contenedor, lo ocultamos si no y guardamos su índice para su uso posterior.

let stopWidth = moreBtn.offsetWidthlet hiddenItems = []const primaryWidth = primary.offsetWidthprimaryItems.forEach((item, i) = {  if(primaryWidth = stopWidth + item.offsetWidth) {    stopWidth += item.offsetWidth  } else {    item.classList.add('--hidden')    hiddenItems.push(i)  }})

A partir de ahora, debemos ocultar los elementos equivalentes de la lista secundaria que permanecieron visibles en la principal. Además de ocultar el botón “más” si no se ocultan las pestañas.

if(!hiddenItems.length) {  moreLi.classList.add('--hidden')  container.classList.remove('--show-secondary')  moreBtn.setAttribute('aria-expanded', false)}else {    secondaryItems.forEach((item, i) = {    if(!hiddenItems.includes(i)) {      item.classList.add('--hidden')    }  })}

Por último, asegúrese de que doAdaptla función se ejecute en los momentos correctos:

doAdapt() // adapt immediately on loadwindow.addEventListener('resize', doAdapt) // adapt on window resize

Lo ideal sería que el controlador de eventos de cambio de tamaño no rebote para evitar cálculos innecesarios.

Damas y caballeros, este es el resultado (juega cambiando el tamaño de la ventana de demostración):

Probablemente podría terminar mi artículo aquí, pero hay un paso más que podemos hacer para mejorarlo y algunas cosas a tener en cuenta…

Mejoras

Se implementó en la demostración anterior, pero no hemos visto un pequeño detalle que mejora la UX de nuestro widget de pestañas. Oculta la lista desplegable automáticamente si el usuario hace clic en cualquier lugar fuera de la lista. Para eso, podemos vincular un detector de clics global y verificar si el elemento en el que se hizo clic o cualquiera de sus padres es la lista secundaria o el botón “más”. De lo contrario, la lista desplegable se descarta.

document.addEventListener('click', (e) = {  let el = e.target  while(el) {    if(el === secondary || el === moreBtn) {      return;    }    el = el.parentNode  }  container.classList.remove('--show-secondary')  moreBtn.setAttribute('aria-expanded', false)})

Casos extremos

Títulos de pestañas largas

Quizás te hayas preguntado cómo se comporta el widget con títulos de pestañas largos. Bueno, tienes al menos dos opciones aquí…

  1. Deje que los títulos pasen a la siguiente línea, que es como se comportan de forma predeterminada (también puede habilitar el ajuste de palabras con word-wrap: break-word):
  1. O puede desactivar todo tipo de ajuste en la lista principal con white-space: nowrap. El script es lo suficientemente flexible como para colocar los elementos demasiado largos en el menú desplegable (donde los títulos pueden ajustarse libremente) dejando de lado a los elementos más cortos:

muchas pestañas

Aunque la lista secundaria es, position: absoluteno importa qué tan larga sea la altura de su documento. Siempre que el elemento contenedor o sus padres no lo sean position: fixed, el documento se adaptará y podrá acceder a los elementos inferiores desplazándose hacia abajo en la página.

Algo a tener en cuenta

Las cosas pueden complicarse si las pestañas son botones en lugar de anclas semánticamente, lo que significa que su respuesta a los clics se decide mediante JavaScript, por ejemplo: pestañas dinámicas. El problema aquí es que los controladores de eventos de los botones de pestaña no se duplican junto con el marcado. Veo al menos dos enfoques para resolver eso:

  • Coloque los archivos adjuntos del controlador de eventos dinámicos justo después del código de pestaña adaptable;
  • Utilice un método de delegación de eventos en su lugar (piense en jQuery live()).

Desafortunadamente, los eventos ocurren en cantidad: lo más probable es que sus pestañas tengan un estado seleccionado que indique visualmente la pestaña actual, por lo que también es importante administrar los estados simultáneamente. De lo contrario, voltea la tableta y estarás perdido.

Compatibilidad del navegador

Aunque utilicé la sintaxis ES6 en los ejemplos y la demostración, debería convertirse en ES5 mediante un compilador como Babel para ampliar significativamente la compatibilidad del navegador (hasta IE9 incluido).

También puede ampliar la implementación de Flexbox con una versión y sintaxis anteriores (hasta IE10). Si también necesita admitir navegadores que no sean Flexbox, siempre puede realizar la detección de funciones con CSS @supports, aplicar la técnica progresivamente y confiar en el desplazamiento horizontal para navegadores más antiguos.

¡Feliz tabulación!

SUSCRÍBETE A NUESTRO BOLETÍN 
No te pierdas de nuestro contenido ni de ninguna de nuestras guías para que puedas avanzar en los juegos que más te gustan.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Subir

Este sitio web utiliza cookies para mejorar tu experiencia mientras navegas por él. Este sitio web utiliza cookies para mejorar tu experiencia de usuario. Al continuar navegando, aceptas su uso. Mas informacion