De Div Soup a marcado semántico significativo: Una guía práctica de HTML semántico
Aprende por qué los div genéricos dañan la accesibilidad, el rastreo y la mantenibilidad, qué elementos semánticos usar en su lugar, y cómo refactorizar un componente de tarjeta real.
Al abrir el inspector de elementos en una aplicación web moderna típica, a menudo se observará la misma imagen: una pila profunda y anónima de elementos <div>, cada uno identificado únicamente por un nombre de clase. La página puede parecer perfecta, pero para los lectores de pantalla, los rastreadores de búsqueda y el próximo desarrollador del equipo, casi no proporciona información sobre su contenido. Esta guía explica cuáles son las consecuencias de esto, qué elementos semánticos reemplazan a la mayoría de esos divs, cómo decidir entre las opciones confusas (<article> o <section>, enlace o botón), y cómo refactorizar un componente realista paso a paso.
Aquí está el patrón en su forma más pura: un encabezado, navegación, contenido principal y pie de página, todo expresado como cajas genéricas.
<!-- The modern web's favorite anti-pattern -->
<div class="header">
<div class="nav-container">
<div class="nav-item">Home</div>
<div class="nav-item">About</div>
</div>
</div>
<div class="main-content">
<div class="article-title">Stop Using Divs</div>
<div class="article-body">
<div class="paragraph">Divs everywhere.</div>
</div>
</div>
<div class="footer">
<div class="copyright">© 2026</div>
</div>
Cada elemento estructural de ese fragmento se encuentra en los nombres de las clases. Si se eliminan las clases, no queda nada que indique a una máquina o a una persona dónde termina la navegación y comienza el artículo. Este estilo se conoce habitualmente como “sopa de divs” y es mucho más común de lo que debería ser.
Por qué HTML se convirtió en un andamio de estilo
A medida que frameworks como React, Vue, Angular y Svelte pasaron a dominar el trabajo frontend, y mientras que el CSS basado en funciones útiles hizo que el estilo fuera casi sencillo, el marcado perdió silenciosamente su función original. HTML comenzó a funcionar como un marco neutro al que se añaden clases y manejadores de eventos, en lugar de ser un lenguaje para describir contenido. Eso es una malentendida sobre la plataforma: HTML fue diseñado para expresar significado, no para ser un motor de maquetación.
Cuando ese significado desaparece, el daño se extiende a varias áreas al mismo tiempo. La tecnología de asistencia pierde sus herramientas de navegación, los motores de búsqueda reciben una señal más débil sobre lo que es importante en la página, el navegador ya no puede ofrecer comportamientos integrados, y la base de código se vuelve más difícil de leer para los colegas. Ninguno de estos problemas es visible en una captura de pantalla, y ese es precisamente el motivo por el cual persisten.
Los componentes por defecto son div
La arquitectura de componentes divide la interfaz en piezas pequeñas como <Button/>, <Card/>, <Navbar/> y <Sidebar/>. Cada componente necesita un elemento raíz para su JSX, y la opción más sencilla es utilizar <div>. Al anidar varios componentes uno dentro del otro, el DOM renderizado termina con diez capas de envoltorios anónimos, aunque cada componente por separado parecía razonable por sí mismo. (Si trabajas con React, vale la pena recordar que un fragmento elimina por completo la necesidad de un envoltorio cuando no se requiere ningún contenedor.)
Las clases utilitarias centran la atención en el aspecto visual
El CSS centrado en las utilidades es excelente para la velocidad, pero pone toda la atención en cómo se ve un elemento. Cuando el marcado es <div class="flex items-center space-x-4">, la pregunta que se responde es “¿cómo está organizado?”, y nunca se plantea la pregunta “¿qué es esto?”. La elección del elemento pasa a ser un detalle secundario.
Los píxeles son solo la capa superior
El hábito más peligroso es juzgar tu trabajo por lo que ve un usuario con mouse en una pantalla grande. Un <div> con fondo azul, esquinas redondeadas y texto en negrita ciertamente parece un botón. Pero debajo de los píxeles renderizados está el DOM, el árbol de accesibilidad que el navegador expone a las tecnologías de asistencia, la visión del rastreador del documento y el manejo de entradas del navegador. Para cada una de esas capas, el div con estilo sigue siendo simplemente un div.
Qué significa realmente el HTML semántico
“Semántico” se refiere al significado. El HTML semántico consiste en elegir elementos cuyos nombres describen la función del contenido que contienen, de modo que el navegador, las tecnologías de asistencia y los lectores humanos puedan comprender el documento sin tener que adivinar.
Contenedores genéricos
Hay dos elementos que intencionalmente no tienen significado:
<div>es un agrupamiento genérico a nivel de bloque.<span>es un agrupamiento genérico en línea.
El texto dentro de un <div> podría ser el título de una página, un enlace de navegación, un párrafo de una entrada de blog, una nota en la barra lateral o una cláusula legal de exención de responsabilidad. El navegador no puede distinguirlo, por lo que los trata a todos de manera idéntica.
Elementos que tienen significado
Los elementos semánticos indican cuál es su contenido:
<header>contiene el contenido introductorio de la página o sección, a menudo incluyendo elementos de navegación.<nav>marca un bloque con los enlaces de navegación principales.<main>envuelve el contenido principal y único de la página.<article>representa una composición autónoma como un artículo o noticia.<section>agrupa contenido relacionado con un mismo tema.<aside>contiene material solo indirectamente relacionado con el contenido principal, como una barra lateral.<footer>alberga información de cierre como los créditos, derechos de autor o enlaces legales.<button>es un control interactivo que realiza una acción.
Cuando el navegador se encuentra con un <article>, sabe que su contenido puede existir por sí solo. Cuando se encuentra con un <nav>, sabe que esos enlaces son la forma en que las personas navegan por el sitio. Ese conocimiento es la base sobre la cual se construye el resto de esta guía.
Cuatro razones por las que vale la pena usar marcado semántico
Elegir el elemento adecuado requiere un momento de reflexión, y un div con estilo muestra los mismos píxeles. Los beneficios se manifiestan en cuatro aspectos.
Accesibilidad: puntos de referencia y controles nativos
Muchas personas usan la web con lectores de pantalla como NVDA, JAWS o VoiceOver, o navegan exclusivamente con el teclado. Los lectores de pantalla ignoran tu CSS; funcionan a partir del árbol de accesibilidad que el navegador deriva de tu HTML.
Con un marcado bien estructurado, el navegador puede mostrar puntos de referencia, y la tecnología de asistencia puede presentarlos como una lista entre la cual el usuario puede navegar. En una página semántica, esa lista se ve más o menos así:
Landmark Navigation Map:
- Header
- Navigation (3 links)
- Main Content
- Heading 1: Stop Using Divs
- Article
- Sidebar (Aside)
- Footer
Un usuario puede presionar una sola tecla de atajo para saltarse docenas de enlaces de navegación y llegar directamente a <main>, o ir directamente al artículo. Ahora comparemos la misma página construida únicamente con divs:
Landmark Navigation Map:
- Division
- Division
- Division
- Division
En la práctica es incluso peor de lo que sugiere este boceto: los divs simples no son en absoluto puntos de referencia, por lo que la lista queda simplemente vacía. El usuario tiene que recorrer el elemento de la página uno por uno para encontrar lo que buscaba.
Los botones presentan el mismo problema a menor escala. Aquí hay un botón falso junto a uno real:
<!-- BAD: Fake Button -->
<div class="my-button" onclick="submitForm()">Submit</div>
<!-- GOOD: Native Button -->
<button type="submit">Submit</button>
El elemento nativo <button> incluye, sin costo adicional:
- Capacidad de recibir foco, por lo que aparece en el orden de tabulación.
La versión en div no puede recibir el foco, no responde al teclado y se lee como texto plano sin indicación alguna de que es interactiva. Para que funcione correctamente se necesitarían tabindex="0", role="button", manejadores de teclas para Enter y Espacio, estilos para el foco y manejo del estado deshabilitado. Eso implica mucho código para reproducir, generalmente de forma imperfecta, algo que la plataforma ya incluye.
Motores de búsqueda: una imagen más clara de la página
Rastreadores como Googlebot son, en cierto sentido, lectores de texto especializados que intentan averiguar de qué trata cada página. La estructura semántica les proporciona indicaciones útiles:
<h1>se refiere al tema principal.<main>separa el contenido único del encabezado y pie de página que se repiten en cada página.<article>indica un contenido editorial distinto.<nav>muestra la estructura de enlaces internos.
Una página compuesta por divs sin diferenciar obliga al rastreador a deducir todo esto únicamente a partir del diseño y el texto. Sin embargo, sea realista respecto al alcance de este efecto: el marcado es solo uno de los muchos factores, y los motores de búsqueda no establecen regla alguna que indique que las páginas semánticas tengan prioridad sobre otras. Considere una estructura limpia como algo que facilita la interpretación e indexación correcta de su contenido, no como garantía de mejor posición en los resultados.
Mantenibilidad: marcado que se documenta a sí mismo
El código es una forma de comunicarse con otros desarrolladores y consigo mismo meses después. Considere dos versiones del mismo diseño. La primera depende exclusivamente de los nombres de las clases:
<div class="top-bar">
<div class="logo-box">...</div>
<div class="menu-list">
<div class="menu-item"><a href="#">Home</a></div>
<div class="menu-item"><a href="#">Blog</a></div>
</div>
</div>
<div class="wrapper">
<div class="content-box">
<div class="title-text">My Post</div>
<div class="body-text">Hello world...</div>
</div>
<div class="right-bar">
<div class="widget">...</div>
</div>
</div>
<div class="bottom-bar">
<div class="legal">© 2026</div>
</div>
La segunda expresa la misma estructura mediante elementos semánticos:
<header>
<div class="logo">...</div>
<nav>
<ul>
<li><a href="#">Home</a></li>
<li><a href="#">Blog</a></li>
</ul>
</nav>
</header>
<main>
<article>
<h1>My Post</h1>
<p>Hello world...</p>
</article>
<aside>
<div class="widget">...</div>
</aside>
</main>
<footer>
<small>© 2026</small>
</footer>
En la primera versión hay que leer cada nombre de clase para comprender su propósito. Si alguien omite o nombra incorrectamente una clase, la estructura se convierte en un muro de cajas idénticas. En la segunda, la forma de la página es visible a simple vista: dónde comienza (<header>), dónde se encuentra el contenido principal (<main>), qué es complementario (<aside>) y dónde termina (<footer>). Observe que la navegación también se convierte en una lista real, lo que permite a los lectores de pantalla indicar cuántos elementos contiene.
El marcado autodescriptivo disminuye la carga mental durante las revisiones y reduce la posibilidad de que algo falle cuando cambia el diseño.
Rendimiento y comportamiento integrado del navegador
Los motores de navegadores como Chromium, Gecko y WebKit están ajustados para los elementos estándar, que ya vienen con estilos predeterminados, manejo de eventos y gestión de estado implementados. Los controles de formulario son el ejemplo más claro: <input type="email"> y <input type="date"> ofrecen a los usuarios de dispositivos móviles un teclado en pantalla adecuado o un selector de fechas nativo, mientras que <details> proporciona un widget de revelación funcional, todo ello sin necesidad de JavaScript de terceros.
Cada vez que reconstruyes un menú desplegable o un botón a partir de un div junto con scripts, envías código adicional por la red, aumentas el tamaño del paquete, consumes más recursos de la CPU y la batería del dispositivo, y creas otro componente que ahora debes mantener y probar. Para conocer más sobre esta idea, consulta seis características nativas de HTML que reemplazan a las bibliotecas UI comunes de JavaScript.
Resolviendo las difíciles elecciones semánticas
Saber cuál es la lista de elementos es la parte fácil. La verdadera confusión surge de algunos pares que parecen intercambiables.
article o section
Esta es la cuestión sobre la que más discuten los desarrolladores. Una prueba útil: ¿se podría extraer este contenido de la página, colocarlo en otro sitio y seguir teniendo sentido completo? Si es así, use <article>. Si solo tiene sentido en su contexto actual, use <section>.
Buenos candidatos para <article>:
- Un artículo de blog o noticia.
- Un comentario individual de usuario.
- Una ficha de producto en una cuadrícula de tienda.
- Un widget autónomo, como un panel meteorológico en tiempo real.
Cada uno de estos podría ser distribuido, incluido en un feed o incrustado en otro lugar sin la página que lo rodea.
Buenos candidatos para <section>:
- El bloque “Acerca de nosotros” en una página principal.
- Un capítulo dentro de un libro digital.
- El área de características en una página de destino.
- Un grupo de testimonios.
Un <section> agrupa el contenido bajo un mismo tema, por lo que casi siempre debe comenzar con un encabezado de <h2> a <h6>. Si no se le ocurre un encabezado adecuado, probablemente no sea una sección y <div> podría ser la opción más adecuada.
Los dos se anidan de forma natural. Un artículo puede dividirse en secciones, cada una con su propio encabezado:
<!-- Proper Nesting Example -->
<main>
<!-- Main article describing a topic -->
<article>
<h1>Understanding Semantic HTML</h1>
<p>Introductory paragraph...</p>
<!-- Sections dividing the article into sub-topics -->
<section>
<h2>Why Accessibility Matters</h2>
<p>Content about accessibility...</p>
</section>
<section>
<h2>SEO Benefits</h2>
<p>Content about SEO...</p>
</section>
</article>
</main>
Enlace o botón
Confundir enlaces y botones es uno de los errores de accesibilidad más frecuentes. La regla es sencilla:
- Use
<a>con unhrefreal cuando al activarlo se cambie la URL o se lleve al usuario a otra página o ubicación. - Use
<button>cuando al activarlo se realice alguna acción en la página actual: enviar datos, abrir un modal, alternar un menú o cambiar el estado de alguna manera.
Ambos tipos de errores son comunes, al igual que sus soluciones:
<!-- WRONG: A link styled like a button that triggers JavaScript -->
<a href="#" onclick="openModal()">Open Modal</a>
<!-- WRONG: A button that navigates to a new webpage -->
<button onclick="window.location.href='/about'">About Us</button>
<!-- RIGHT -->
<button type="button" onclick="openModal()">Open Modal</button>
<a href="/about">About Us</a>
La distinción es importante porque los lectores de pantalla anuncian el rol. “Enlace” genera la expectativa de que la ubicación cambiará; “botón” sugiere que ocurrirá algo aquí. Cometer un error al elegir el término adecuado rompe esa expectativa. También existen efectos secundarios prácticos: un enlace con href="#" puede llevar la página a la parte superior y no puede activarse con la tecla Espacio, mientras que un botón que permite navegar no se puede abrir en una pestaña nueva ni copiar su dirección.
Crear un esquema de encabezados sensato
Los encabezados forman el índice de su página, y tanto las tecnologías de asistencia como los rastreadores dependen de ellos. Los usuarios de lectores de pantalla suelen navegar únicamente mediante los encabezados. Algunas reglas ayudan a que el esquema sea útil:
- Utilice un
<h1>para el tema principal de la página, como el título del artículo o el nombre del panel de control. La especificación HTML no prohíbe estrictamente usar varios, pero se recomienda ampliamente utilizar un único encabezado de nivel superior, ya que proporciona el esquema más claro. - No salte niveles. Pasar directamente de
<h2>a<h4>porque se desea texto más pequeño es una decisión de estilo disfrazada de estructura; en su lugar, modifique el tamaño de la fuente con CSS. - Anídelos de forma lógica: debajo del título
<h1>se encuentran las secciones principales<h2>, cada una con sus propias subsecciones<h3>, seguidas del siguiente<h2>.
Tenga también en cuenta que el elemento <header> y los elementos de encabezado son cosas diferentes. Un <header> es una región de la página; <h1> hasta <h6> son los títulos que forman la estructura jerárquica.
Cuándo un div es la herramienta adecuada
Nada de esto significa que <div> esté prohibido. Tiene una función legítima: envolver contenido únicamente con fines de diseño o estilo cuando no aplica ningún significado semántico. Centrar algo con flexbox, crear un espacio entre elementos en una cuadrícula, aplicar un fondo degradado o utilizar animaciones CSS son todas razones perfectamente válidas para emplear un <div> (o un <span> para contenido en línea).
En la tarjeta siguiente, las partes con significado utilizan elementos semánticos, mientras que un único div existe únicamente para mostrar dos botones uno al lado del otro:
<!-- PERFECTLY VALID USE OF A DIV -->
<article>
<h1>Card Title</h1>
<p>Card description goes here...</p>
<!-- This div exists purely to align two buttons side-by-side with Flexbox -->
<div class="button-group flex gap-4 mt-4">
<button type="button">Save</button>
<button type="button">Cancel</button>
</div>
</article>
Los elementos <article>, <h1>, <p> y <button> describen el contenido; el <div> es únicamente una capa de diseño. Ese es todo el principio en una sola oración: usar elementos semánticos para el significado y divs para el diseño. (En una página real donde esta tarjeta se encuentra dentro de un documento más grande, su título sería típicamente un <h2> o <h3> para ajustarse al esquema de la página.)
Refactorización de una tarjeta de entrada de blog, paso a paso
Considere un componente de tarjeta del tipo que se encuentra en casi todos los sitios de contenido: una imagen, una etiqueta, un título, el autor y la fecha, un extracto y dos acciones. Aquí está la versión con divs:
<div class="card">
<div class="card-image">
<img src="tech.jpg" alt="Technology background" />
<div class="badge">Article</div>
</div>
<div class="card-content">
<div class="post-title" onclick="goToPost()">10 Tips for Better Code</div>
<div class="post-author">By Jane Doe</div>
<div class="post-date">August 12, 2026</div>
<div class="post-excerpt">
Learn how to write cleaner, more maintainable frontend code today...
</div>
<div class="card-footer">
<div class="share-btn" onclick="sharePost()">Share</div>
<div class="read-more" onclick="goToPost()">Read More</div>
</div>
</div>
</div>
Los problemas son fáciles de enumerar una vez que se buscan:
- El contenedor exterior es un
<div>, aunque la tarjeta es un elemento de contenido autónomo, que es exactamente para lo que sirve<article>. - El título es un div clickeable, por lo que los usuarios que usan teclado no pueden acceder a él y los lectores de pantalla no saben si se trata de un encabezado o de un enlace.
- El autor y la fecha se encuentran en contenedores genéricos que no tienen un significado legible por máquinas.
- "Compartir" y "Leer más" son botones ficticios que presentan los problemas de uso con el teclado y las notificaciones mencionados anteriormente.
Ahora la versión reescrita:
<article class="card">
<figure class="card-image">
<img src="tech.jpg" alt="Abstract technology grid pattern" />
<span class="badge">Article</span>
</figure>
<div class="card-content">
<h2>
<a href="/posts/10-tips-for-better-code">10 Tips for Better Code</a>
</h2>
<p class="meta-info">
Written by <span class="author">Jane Doe</span> on
<time datetime="2026-08-12">August 12, 2026</time>
</p>
<p class="post-excerpt">
Learn how to write cleaner, more maintainable frontend code today...
</p>
<footer class="card-footer">
<button type="button" onclick="sharePost()" aria-label="Share this article">
Share
</button>
<a href="/posts/10-tips-for-better-code" class="btn-primary">
Read More
</a>
</footer>
</div>
</article>
Qué cambió y por qué ayuda:
- El contenedor
<article>indica a la tecnología de asistencia y a los rastreadores que la tarjeta es un elemento independiente.
<figure>, y el texto alternativo ahora describe la imagen en lugar de etiquetarla de forma genérica.<h2> que contiene un enlace real, por lo que aparece en el esquema de encabezados, se puede acceder a él con Tab y expone su destino a los rastreadores.<time datetime="2026-08-12">, lo que proporciona a los scrapers, las herramientas de traducción y las integraciones con calendarios un valor legible por máquinas sin ambigüedades, independientemente de cómo esté formateado el texto visible.<button> porque actúa en la página actual, mientras que "Leer más" es un <a> porque permite navegar.aria-label del botón de compartir proporciona a los usuarios de lectores de pantalla más contexto sobre lo que se compartirá. Mantenga el texto visible dentro del etiquetado, como aquí (“Compartir” forma parte de “Compartir este artículo”), para que los usuarios que usan control por voz puedan activarlo diciendo lo que ven.Una mejora que vale la pena considerar: ahora la tarjeta contiene dos enlaces a la misma URL. Algunos equipos solo mantienen el enlace del título, o hacen que toda la tarjeta sea clickeable a través de ese único enlace, para que los usuarios que usan teclado y lectores de pantalla no lleguen dos veces al mismo destino.
Hábitos que mantienen semántica tu marcado
No es necesario volver a aprender desarrollo web para escribir HTML mejor. Un par de verificaciones rutinarias detectan la mayoría de los problemas.
Ejecutar una auditoría automatizada
Las extensiones del navegador como axe DevTools o WAVE, disponibles para Chrome y Firefox, escanean una página en segundos e identifican problemas como atributos ARIA inválidos, tipos de botones faltantes, orden incorrecto de los encabezados y elementos interactivos sin semántica adecuada. Las herramientas automatizadas solo detectan parte de lo importante, por lo que considere un informe limpio como punto de partida y no como prueba de accesibilidad.
Pruebe la página sin CSS
Deshabilite todos los estilos, ya sea a través de las herramientas de desarrollador o mediante una extensión que desactive el CSS, y observe qué queda. ¿Sigue siendo un documento legible? ¿Puede distinguir los encabezados de los párrafos y encontrar la navegación? Si el resultado es un bloque de texto sin diferenciación, la estructura depende del CSS para tener sentido. Un documento bien estructurado se mantiene organizado incluso sin ningún estilo.
Deje de usar el ratón
Intente operar su aplicación utilizando únicamente Tab, Shift + Tab, Enter, Espacio y las teclas de dirección, y verifique:
- Si se puede acceder a cada elemento interactivo.
- Si siempre puede ver qué elemento tiene el foco.
- Si los formularios, menús desplegables y ventanas modales funcionan correctamente.
Cada vez que se quede atascado con un div que ignora Enter o Espacio, cámbielo por un <button>. A menudo es una de las soluciones más rápidas para mejorar la accesibilidad.
Pregunte cuál es el contenido antes de escribir div
Antes de crear un nuevo contenedor, deténgase y pregúntese qué representa realmente su contenido:
- Las secciones de navegación requieren
<nav>. - Una barra lateral requiere
<aside>. - Una acción clickeable requiere
<button>. - Una tarjeta o publicación independiente requiere
<article>.
<main>.<div>.Lo mismo aplica dentro de los componentes: el elemento raíz de un componente React forma parte del documento final, por lo que también debe elegirse con la misma precaución. Para saber más sobre las diferencias entre JSX y HTML real, consulte JSX no es HTML: los reales intercambios detrás del markup de componentes.
Puntos clave
- Los píxeles renderizados son solo una capa; el árbol de accesibilidad, los rastreadores y el manejo de entradas del navegador leen todos tus elementos, no tus estilos.
- Los elementos nativos como
<button>,<a>,<input>y<details>brindan enfoque, soporte para teclado, roles y comportamiento móvil que resultaría costoso recrear a mano. - Utilice
<article>para contenido autónomo y<section>para partes temáticas de un conjunto más grande, y asigne un título a cada sección. - Los enlaces sirven para navegar, los botones para actuar; mezclarlos confunde a los usuarios y altera el comportamiento esperado del navegador.
- Mantenga una estructura de títulos clara sin niveles omitidos, y utilice CSS en lugar de los niveles de título para controlar el tamaño.
- Los Div siguen siendo la opción adecuada para un diseño puramente estructural. Los frameworks cambian cada pocos años, pero esta base ha resistido durante décadas, y el marcado que expresa su significado beneficia a los usuarios, a los motores de búsqueda y a su equipo por igual.
Lecturas relacionadas
- Seis características nativas de HTML que sustituyen a las bibliotecas UI comunes de JavaScript — Aprenda cómo popover, exclusive details, dialog, Declarative Shadow DOM, fetchpriority y datalist reemplazan al JavaScript personalizado, además de los límites que cada uno sigue teniendo.
- JSX no es HTML: Los reales compromisos detrás del markup de componentes — Entienda qué pierde cuando el markup se convierte en JSX, desde las herramientas y el análisis hasta los formularios, la accesibilidad y la portabilidad, así como los patrones que permiten recuperar gran parte de ello.