🌐 Fundamentos Web 🎨 Frontend

El DOM explicado a fondo: qué es, cómo funciona y por qué importa

El DOM no es el HTML: es la estructura viva en memoria que el navegador construye a partir de él. Árbol de nodos, coste de manipularlo y cómo lo abstraen React, Vue y compañía.

📅 18 de mayo de 2026 ⏱️ 8 min de lectura ✍️ Equipo ProgramacionWebs

Es habitual usar “HTML” y “DOM” como sinónimos, y no lo son. El HTML es el texto que escribes o que llega por la red: una cadena de caracteres con etiquetas. El DOM (Document Object Model) es otra cosa: la representación en memoria, viva y manipulable, que el navegador construye después de parsear ese texto. Esa diferencia no es sutileza académica — explica por qué document.body.innerHTML puede no coincidir con el HTML original que enviaste desde el servidor, por qué las herramientas de desarrollo muestran algo distinto de “ver código fuente”, y por qué “manipular el DOM” tiene un coste de rendimiento que manipular una cadena de texto no tiene.

El DOM no es el HTML

Cuando el navegador recibe HTML, lo tokeniza (identifica etiquetas de apertura, cierre, atributos, texto) y con esos tokens construye un árbol de objetos en memoria. Ese árbol es el DOM, y la especificación oficial —el DOM Living Standard, mantenido por WHATWG— lo define como un modelo neutral de plataforma para representar documentos como árboles de nodos, independiente del lenguaje que lo consulte.

Dos consecuencias importantes de esto:

  • El navegador corrige errores por ti. Si tu HTML tiene una etiqueta sin cerrar o mal anidada, el algoritmo de parseo de HTML (definido también en el propio estándar) aplica reglas de recuperación de errores y produce un DOM válido de todas formas. El DOM que ves en las herramientas de desarrollo puede tener una estructura distinta de lo que escribiste literalmente.
  • El DOM es mutable en tiempo real. Cuando JavaScript ejecuta element.remove() o document.body.appendChild(nuevoNodo), el HTML original no cambia —sigue siendo el mismo texto que llegó por la red— pero el DOM sí, inmediatamente, y el navegador vuelve a calcular todo lo necesario para reflejar ese cambio en pantalla.

Anatomía del árbol

El DOM organiza todo como nodos con relaciones padre-hijo-hermano. Los tipos de nodo más relevantes en el día a día son:

  • Document: el nodo raíz, uno por página. Es el punto de entrada (document) desde el que se accede a todo lo demás.
  • Element: cada etiqueta HTML (<div>, <p>, <article>…). En el contexto de un documento HTML, se especializa además en interfaces concretas como HTMLDivElement o HTMLAnchorElement, cada una con sus propias propiedades.
  • Text: el contenido textual dentro de un elemento, como un nodo independiente, no como una propiedad del elemento que lo contiene.
  • Comment: los comentarios HTML (<!-- ... -->), que existen en el DOM aunque no se muestren.
  • DocumentFragment: un contenedor ligero que no forma parte del árbol visible, pensado para construir subárboles en memoria antes de insertarlos de una sola vez.
graph TD
Doc[Document] --> HTML[html]
HTML --> Head[head]
HTML --> Body[body]
Head --> Title[title]
Title --> TextT["Text: 'Mi página'"]
Body --> H1[h1]
Body --> P[p]
H1 --> TextH1["Text: 'Hola'"]
P --> TextP["Text: 'Contenido'"]

Todo objeto del árbol, sin importar su tipo concreto, hereda de la interfaz base Node, que es la que aporta métodos comunes como parentNode, childNodes o appendChild. Es la razón por la que puedes recorrer el árbol de forma genérica sin preocuparte de si un nodo concreto es un elemento o un texto.

Cómo interactúa JavaScript con el DOM

El DOM no es JavaScript ni depende de él —es una API que cualquier lenguaje con los bindings adecuados puede consultar—, pero en el navegador la forma habitual de tocarlo es a través de JavaScript y las Web APIs expuestas en el objeto global document:

// Leer: seleccionar nodos existentes
const items = document.querySelectorAll('.item');

// Crear: construir nodos nuevos, todavía fuera del árbol visible
const li = document.createElement('li');
li.textContent = 'Nuevo elemento';

// Insertar: ahora sí, el navegador debe reflejar el cambio
document.querySelector('ul').appendChild(li);

// Escuchar: reaccionar a interacción del usuario
li.addEventListener('click', () => {
  li.classList.toggle('activo');
});

Cada una de esas líneas tiene un coste distinto. Leer (querySelectorAll) es relativamente barato. Crear un nodo con createElement sin insertarlo todavía en el árbol es casi gratis, porque no afecta a nada visible. Insertarlo es la operación que puede disparar trabajo real del navegador.

Por qué manipular el DOM es caro: reflow y repaint

Cuando una modificación del DOM afecta al tamaño o posición de elementos, el navegador tiene que recalcular el layout (a menudo llamado reflow): vuelve a determinar la geometría exacta —posición y tamaño en píxeles— de los nodos afectados y, en muchos casos, de sus vecinos. Si el cambio solo afecta a algo visual que no altera geometría (un color, una sombra), el navegador puede saltarse el layout y hacer directamente un repaint. Un reflow siempre implica trabajo adicional de pintado; un repaint sin reflow es más barato.

Cuando hay que insertar muchos nodos, agruparlos en un DocumentFragment antes de añadirlos al árbol real evita disparar un reflow por cada inserción individual: el navegador solo recalcula una vez, cuando el fragmento completo entra en el árbol visible de una sola vez.

Cómo lo abstraen los frameworks modernos

Manipular el DOM directamente, nodo a nodo, escala mal en aplicaciones grandes: es fácil perder de vista qué parte del árbol hay que actualizar cuando cambia un dato, y es fácil provocar más reflows de los necesarios. Los frameworks modernos existen en buena parte para resolver justo ese problema, aunque con estrategias distintas.

React popularizó el DOM virtual: mantiene una representación en memoria (ligera, no vinculada a las APIs reales del navegador) del árbol que debería existir dado el estado actual de la aplicación. Cuando el estado cambia, React construye un nuevo árbol virtual, lo compara con el anterior mediante un algoritmo de reconciliación —que asume que elementos del mismo tipo en la misma posición probablemente representan la misma cosa, para no tener que comparar exhaustivamente todo el árbol— y aplica al DOM real solo el conjunto mínimo de cambios detectados, en un lote, en lugar de una escritura por cada dato modificado.

Otros frameworks, como Vue o Svelte, se apoyan en sistemas de reactividad de grano más fino o en compilación previa, para determinar en tiempo de compilación o de forma más directa qué partes exactas del DOM necesitan actualizarse ante un cambio de estado, sin necesidad de reconstruir y comparar un árbol virtual completo. El objetivo de fondo es el mismo en todos los casos: minimizar cuántas veces y con cuánta imprecisión se toca el DOM real, porque cada toque potencialmente cuesta un reflow.

El árbol de accesibilidad: un DOM paralelo

El navegador construye, a partir del DOM, un segundo árbol llamado árbol de accesibilidad (Accessibility Tree), que es la representación semántica que consumen lectores de pantalla y otras tecnologías asistivas. Se actualiza cada vez que el DOM cambia, pero no es idéntico a él: elementos ocultos o puramente decorativos pueden quedar fuera. Este árbol es una de las razones de peso, junto con el SEO, por las que la estructura semántica del HTML —de la que hablamos en detalle en semántica HTML5: la guía completa— importa tanto: un <div> con onclick nunca generará la misma entrada en el árbol de accesibilidad que un <button> real, por muy idéntico que se vea en pantalla.

Errores comunes al pensar en el DOM

El primero es confundir “ver el código fuente” con “inspeccionar el DOM”: son cosas distintas, sobre todo en aplicaciones que renderizan contenido con JavaScript después de la carga inicial, donde el HTML original puede estar casi vacío y todo el contenido real solo existe en el DOM final.

El segundo es consultar el DOM más de lo necesario: llamar a document.querySelector repetidamente para el mismo elemento dentro de un bucle, en lugar de guardar la referencia una vez. No es solo estilo de código: cada consulta recorre el árbol.

El tercero, ya mencionado pero merece repetirse porque es el más caro en producción real: alternar lecturas y escrituras geométricas sin agrupar, provocando reflows síncronos innecesarios. Entender esto no es opcional para quien construye interfaces — es la diferencia entre una animación a 60fps y una que se siente pegajosa, entre listas que se renderizan instantáneamente y listas que bloquean el hilo principal mientras el usuario espera. El DOM completo de esta cadena, desde el HTML hasta los píxeles, lo cerramos en el pipeline de renderizado del navegador.

Compartir