Esto lo dimos al principio de todo en clase, y es de los conceptos que se me quedaron bastante claros desde el primer momento: <div> crea un bloque de código donde metes lo que quieras, y <span> es para señalar algo específico dentro de un texto, normalmente para darle propiedades con CSS después.

<div>: un contenedor de bloque, sin significado propio

<div> (division) es el contenedor genérico por excelencia. No aporta ningún significado sobre lo que hay dentro — a diferencia de <article> o <header>, un <div> no dice nada de sí mismo. Su única función es agrupar contenido para poder aplicarle estilos o comportamiento como conjunto.

<div style="background-color: orange; border: 3px solid #C00;">
  Este texto está dentro del div.
</div>
Este texto está fuera del div

Por defecto, <div> es un elemento de bloque: ocupa todo el ancho disponible de su contenedor y fuerza un salto de línea antes y después, aunque tú no hayas puesto ningún <br>.

<span>: una marca en línea, dentro del propio texto

<span> es justo lo contrario en cuanto a comportamiento: es un elemento en línea (inline). No fuerza ningún salto — convive dentro de la misma línea que el texto que lo rodea, ocupando solo el espacio justo de su contenido.

<p>Hola en inglés se dice <span lang="en-GB">Hello</span></p>

Aquí, <span> marca solo la palabra “Hello” dentro de una frase, sin romper el flujo del párrafo. Esto es exactamente lo que hace útil a <span>: te permite señalar una parte concreta de un texto (para aplicarle un idioma distinto, un color, una clase de CSS) sin alterar la estructura del párrafo que lo contiene.

La clasificación de fondo: inline vs block

La diferencia entre <div> y <span> es en realidad un caso concreto de una clasificación más general que agrupa todos los elementos HTML en dos tipos:

Elementos de bloqueElementos en línea
OcupanTodo el ancho del contenedorSolo el espacio de su contenido
Fuerzan salto de líneaNo
Pueden contenerOtros bloques o inlineSolo inline o texto
Ejemplosp, h1-h6, blockquote, div, section, article, figurestrong, em, span, mark, abbr

div es, literalmente, el representante genérico de los elementos de bloque — igual que span es el representante genérico de los elementos en línea. Cuando <section> o <article> no encajan porque no hay ningún significado semántico que aportar, <div> sigue siendo la herramienta correcta. Y cuando <strong>, <em> o <mark> tampoco encajan porque no hay ningún significado semántico concreto que marcar dentro del texto, <span> cumple el mismo papel a nivel de línea.

Un ejemplo que junta los dos

<div class="tarjeta-producto">
  <h3>Teclado mecánico</h3>
  <p>
    Precio: <span class="precio">49,99 €</span>
    (<span class="descuento">-15%</span> hoy)
  </p>
</div>

Aquí <div class="tarjeta-producto"> agrupa toda la tarjeta como bloque independiente, mientras que los dos <span> marcan fragmentos concretos dentro del párrafo — el precio y el descuento — para poder darles un color o un tamaño distinto con CSS sin tener que crear un párrafo nuevo para cada uno.

El atributo que da su verdadero poder a ambos: class e id

Ni <div> ni <span> valen gran cosa por sí solos sin los atributos class o id, que son los que permiten engancharles estilos de CSS o comportamiento de JavaScript concretos, en vez de aplicar un estilo genérico a todos los div o span de la página por igual:

<span id="precio-destacado" class="texto-rojo">49,99 €</span>

id identifica un elemento único en toda la página (no puede repetirse), mientras que class puede reutilizarse en tantos elementos como quieras — de hecho, un mismo elemento puede tener varias clases a la vez, separadas por espacio. En la práctica, para estilos que vas a reutilizar en varios sitios (como el color de los precios rebajados) se usa class; para algo único de la página, como un ancla a la que saltar con un enlace interno, se usa id.

No confundir “en línea” con “sin formato”

Un matiz que conviene aclarar: que <span> no tenga significado semántico propio no significa que sea idéntico a otros elementos en línea que sí lo tienen. <strong> marca importancia (y los navegadores lo muestran en negrita por defecto), <em> marca énfasis (cursiva por defecto) — ambos comunican algo sobre el contenido, igual que <article> o <header> lo hacen a nivel de bloque. <span>, en cambio, es puramente un gancho para aplicar estilo o comportamiento con CSS o JavaScript, sin decir nada por sí mismo sobre lo que contiene. Por eso, si lo que quieres es remarcar que un texto es importante, <strong> es semánticamente más correcto que un <span> con font-weight: bold en CSS — comunican lo mismo visualmente, pero solo uno de los dos le dice algo real al lector de pantalla o al buscador sobre el contenido.

El error típico: usar <div> donde tocaría <span> (o al revés)

Un fallo habitual al empezar es usar <div> para resaltar una palabra suelta dentro de una frase — como <div> fuerza salto de línea, el texto se rompe en dos líneas sin que se entienda por qué a simple vista. Y el error contrario, menos común pero también real, es intentar usar <span> para agrupar bloques grandes de contenido (como una tarjeta completa), lo que produce un HTML técnicamente válido pero que no se comporta como uno esperaría, porque <span> no está pensado para eso.

Pon a prueba lo que has entendido

Quieres resaltar en negrita y otro color solo una palabra en mitad de un párrafo de texto, sin romper la línea. ¿Qué elemento usarías?

Resumen rápido

<div> es un contenedor de bloque genérico, sin significado propio, que ocupa todo el ancho y fuerza salto de línea. <span> es su equivalente en línea, que no rompe el flujo del texto y sirve para marcar fragmentos concretos dentro de un párrafo. Ambos son los “comodines” de sus respectivas categorías (bloque e inline) para cuando ningún elemento semántico como <article> o <strong> encaja mejor. Si quieres ver cuándo sí merece la pena dar el salto a los elementos con significado propio, lo tienes en elementos semánticos de HTML5 vs hacerlo todo con <div>.