Tabla de contenido dinámica en Webflow CMS: la forma más fácil

Publicado: 2022-03-22
Recientemente hemos hecho posible agregar estados activos a una tabla de contenido fija. ¡Consulte el final del artículo para obtener instrucciones!

Antecedentes

En Flowrite, recientemente comenzamos a escribir piezas de contenido más largas y queríamos que nuestros blogs fueran más legibles, comenzando desde el elemento más básico: la tabla de contenido.

Usamos Webflow y nos encanta, pero resultó que crear ToC de manera escalable para los elementos de CMS no fue tan sencillo. Todas las soluciones existentes se basan en la configuración de identificadores y enlaces manualmente o en el uso de complementos de terceros.

Queríamos un sistema simple que generara automáticamente ToCs basados ​​en los encabezados de nuestros blogs. Eso es lo que construimos, ¡y así es como usted puede hacer lo mismo!

¿Cómo funciona?

  1. Diseñe sus artículos ToC. Hágalos de la forma que desee: cree estados de desplazamiento, animaciones, etc.
  2. Cree un div para el ToC con una identificación específica en cualquier parte de su página de CMS.
  3. Inserte un fragmento de código al final de la etiqueta <body> en su página de CMS.
  4. Las TdC se generan automáticamente para cada elemento de CMS.

Creación de su tabla de contenido dinámica

Diseñe sus artículos ToC

Dale una clase a tu elemento ToC (usamos "tocitem") y dale el estilo que quieras.

Mi recomendación es usar una página privada separada para diseñar estos elementos. De esa manera, puede modificar fácilmente el diseño más adelante si es necesario.

Nos encantó la simplicidad de los elementos de la tabla de contenido de Notion, así que la usamos como punto de referencia.


Si desea incluir más de un tipo de encabezado, asegúrese de darles una clase adicional ("toc-h2", "toc-h3", etc.)

Cree el elemento para su ToC

Agregue un div donde quiera que esté su ToC y asígnele una identificación "toc". Una vez más, puede diseñar este elemento de la forma que desee.

Si desea tener su ToC dentro de su elemento de texto enriquecido, consulte el final de este artículo para obtener más detalles.

Por último, asigne al elemento de texto enriquecido un id "contenido". Esto será necesario más adelante para asegurarnos de que usamos los encabezados correctos en el ToC.

Elige entre dos opciones

Dado que los ToC se generarán automáticamente, debemos indicar qué encabezados queremos incluir en ellos. En esta publicación, cubrimos dos opciones:

  1. Generación de TdC basadas en un único tipo de encabezado estático, por ejemplo, H2.
  2. Generar ToC basados ​​en múltiples encabezados de su elección, por ejemplo, H2 y H3 para una publicación de blog y H2 y H4 para otra.

Opción 1: TdC de un solo título

En esta opción, las ToC siempre se generarán en función del mismo encabezado.

Inserta el siguiente código al final de tu etiqueta <body> en las páginas de tu colección. Consulte los comentarios al final de cada línea si desea comprender cómo funciona.

  <script> document.getElementById("content").querySelectorAll("h2").forEach(function(heading, i) { // runs a function for all h2 elements inside your rich text element heading.setAttribute("id", "toc-" + i); // gives each h2 a unique id let str = heading.innerHTML; // adds section titles to slugs str = str.replace(/\s+/g, '-').replace(/[°&\/\\#,+()$~%.'":;*?<>{}]/g, "").toLowerCase(); // replaces spaces with hyphens, removes special characters and extra spaces from the headings, and applies lowercase in slugs heading.setAttribute("id", str); // gives each heading a unique id const item = document.createElement("a"); // creates an anchor element called "item" for each h2 item.innerHTML = heading.innerHTML // gives each item the text of the corresponding heading item.setAttribute("class", "tocitem"); // gives each item the correct class item.setAttribute("href", "#" + str); // gives each item the correct anchor link document.querySelector("#toc").appendChild(item); // places each item inside the Table of Contents div }); </script>
<script> document.getElementById("content").querySelectorAll("h2").forEach(function(heading, i) { // runs a function for all h2 elements inside your rich text element heading.setAttribute("id", "toc-" + i); // gives each h2 a unique id let str = heading.innerHTML; // adds section titles to slugs str = str.replace(/\s+/g, '-').replace(/[°&\/\\#,+()$~%.'":;*?<>{}]/g, "").toLowerCase(); // replaces spaces with hyphens, removes special characters and extra spaces from the headings, and applies lowercase in slugs heading.setAttribute("id", str); // gives each heading a unique id const item = document.createElement("a"); // creates an anchor element called "item" for each h2 item.innerHTML = heading.innerHTML // gives each item the text of the corresponding heading item.setAttribute("class", "tocitem"); // gives each item the correct class item.setAttribute("href", "#" + str); // gives each item the correct anchor link document.querySelector("#toc").appendChild(item); // places each item inside the Table of Contents div }); </script>

Publica el sitio y listo.

Opción 2: TdC de varios encabezados

Esta opción le brinda la oportunidad de determinar caso por caso qué encabezados se utilizarán para generar las TdC.

Comencemos por crear un nuevo campo de texto en su Colección. Lo llamamos "TOC basado en...". Aquí es donde especifica los encabezados que se utilizarán en el ToC de cada elemento de CMS. Sepárelos con una coma y no incluya espacios.


Ahora, inserte el siguiente código al final de su etiqueta <body> en las páginas de su colección. Consulte los comentarios al final de cada línea si desea comprender cómo funciona.

  <script> document.getElementById("content").querySelectorAll("[HEADINGS]").forEach(function(heading, i) { // runs a function for all headings inside your rich text element let str = heading.innerHTML; // adds section titles to slugs str = str.replace(/\s+/g, '-').replace(/[°&\/\\#,+()$~%.'":;*?<>{}]/g, "").toLowerCase(); // replaces spaces with hyphens, removes special characters and extra spaces from the headings, and applies lowercase in slugs heading.setAttribute("id", str); // gives each heading a unique id const item = document.createElement("a"); // creates an anchor element called "item" for each heading item.innerHTML = heading.innerHTML; // gives each item the text of the corresponding heading ("[HEADINGS]").split(",").forEach(function(x) { // runs a function for each item in your headings list if (heading.tagName.toLowerCase()==x) { item.classList.add("tocitem", "toc-" + x); // gives each item the correct class } }); item.setAttribute("href", "#" + str); // gives each item the correct anchor link document.querySelector("#toc").appendChild(item); // places each item inside the Table of Contents div }); </script>
<script> document.getElementById("content").querySelectorAll("[HEADINGS]").forEach(function(heading, i) { // runs a function for all headings inside your rich text element let str = heading.innerHTML; // adds section titles to slugs str = str.replace(/\s+/g, '-').replace(/[°&\/\\#,+()$~%.'":;*?<>{}]/g, "").toLowerCase(); // replaces spaces with hyphens, removes special characters and extra spaces from the headings, and applies lowercase in slugs heading.setAttribute("id", str); // gives each heading a unique id const item = document.createElement("a"); // creates an anchor element called "item" for each heading item.innerHTML = heading.innerHTML; // gives each item the text of the corresponding heading ("[HEADINGS]").split(",").forEach(function(x) { // runs a function for each item in your headings list if (heading.tagName.toLowerCase()==x) { item.classList.add("tocitem", "toc-" + x); // gives each item the correct class } }); item.setAttribute("href", "#" + str); // gives each item the correct anchor link document.querySelector("#toc").appendChild(item); // places each item inside the Table of Contents div }); </script>

Por último, asegúrese de reemplazar [TÍTULOS] con el valor de su campo CMS "ToC basado en...".


Eso es todo, ya está listo para publicar.

personalización

Estados activos en una tabla de contenido pegajosa

Inspirándonos en la publicación de Chris Coyier sobre CSS-Tricks, construimos una forma de agregar estados activos a los elementos de ToC visibles, una gran característica para ToC pegajosos.

En primer lugar, agregue "observer.observe(heading);" al comienzo del código que implementó anteriormente. Vea la captura de pantalla para la ubicación correcta.

Luego, agregue el siguiente fragmento de código encima de todo el código ToC existente:

  <script> const observer = new IntersectionObserver(entries => { entries.forEach(entry => { const id = entry.target.getAttribute("id"); if (entry.isIntersecting) { document.querySelectorAll(".active").forEach((z) => { z.classList.remove("active") }); document.querySelector(`a[href="#${id}"]`).classList.add("active"); } }); }, { rootMargin: '0px 0px -75% 0px' }); </script>
<script> const observer = new IntersectionObserver(entries => { entries.forEach(entry => { const id = entry.target.getAttribute("id"); if (entry.isIntersecting) { document.querySelectorAll(".active").forEach((z) => { z.classList.remove("active") }); document.querySelector(`a[href="#${id}"]`).classList.add("active"); } }); }, { rootMargin: '0px 0px -75% 0px' }); </script>

El código agrega una clase llamada "activa" a un tocitem visible y elimina la clase cuando aparece un nuevo tocitem.

Por último, asegúrese de diseñar la clase "activa" dándole un color de fondo diferente, por ejemplo.

Mostrar ToC solo en algunos de los elementos de CMS

Si no desea que aparezca una ToC en algunos de sus elementos de CMS, complete los siguientes pasos:

1. Deje el campo "ToC basado en..." vacío.
Si está utilizando la Opción 1, agregue un interruptor en su colección de CMS para indicar si la ToC debe aparecer o no.

2. Haga que la visibilidad de su div ToC sea condicional según el selector en el paso 1.

3. Cree una instrucción if al comienzo de su fragmento de código de ToC para evitar ejecutar la función si el campo está vacío. Recuerda cerrar con "}".

ToC dentro de su elemento de texto enriquecido

Si desea colocar su tabla de contenido dentro de su elemento de texto enriquecido, puede replicar el elemento div de la tabla de contenido con un código de inserción.

Cree un elemento de código personalizado dentro de su texto enriquecido y copie y pegue "<div id="toc" class="toc"></div>" en el campo de código.


Si desea tener una TdC en línea solo en algunos de los elementos del CMS y una TdC "normal" en otros, necesita hacer un par de trucos adicionales:

1. Cree un selector de opciones con una sola opción: ".getElementById('content'). Selecciónelo en aquellos elementos del CMS en los que desee tener una tabla de contenido dentro del texto enriquecido.

2. Mostrar la ToC "normal" solo si el selector no está configurado.


3. Agregue el valor del selector a la siguiente parte del código. Ahora, si se seleccionó el selector, el código agregará los elementos de la tabla de contenido dentro del div de tabla de contenido correcto.

Evite la superposición de la barra de navegación en el desplazamiento

Es posible que observe que al hacer clic en un enlace ToC, la página se desplaza hacia abajo hasta el encabezado correcto, pero la barra de navegación la bloquea.

Para arreglar esto:

  1. Asegúrese de que la posición de su elemento de navegación esté configurada como "fija"
  2. Cambie la etiqueta del elemento de navegación a "Encabezado"

¡Eso es todo! En caso de que tenga algún problema en el camino, no dude en enviarme un correo electrónico o comunicarse a través de Twitter / LinkedIn.

También me encantaría saber si termina usando este sistema, así que envíeme un mensaje si lo hizo y comparta la publicación con alguien más que pueda beneficiarse de ella ️