Ir al contenido principal

HTML

Introducción: qué hace HTML y en qué se diferencia de CSS

HTML (HyperText Markup Language) es el lenguaje con el que se describe qué es cada cosa en una página: esto es un título, esto un párrafo, esto una lista, esto un campo donde se escribe. No es un lenguaje de programación —no calcula, no decide, no recuerda— sino un lenguaje de marcado: un conjunto de etiquetas que envuelven el contenido y le dicen al navegador qué representa.

CSS (Cascading Style Sheets) hace otra cosa: describe cómo se ve lo anterior. De qué color, de qué tamaño, con cuánto espacio alrededor, en qué posición.

  HTML CSS
Se ocupa de La estructura y el significado del contenido. La presentación: aspecto, color, tamaño, posición.
Qué es Un lenguaje de marcado. Un lenguaje de hojas de estilo.
Cómo se reconoce Una lista de elementos con etiquetas. Una lista de reglas propiedad: valor.
Si se cambia Cambia el contenido de la página. Cambia cómo se ve el mismo contenido.
Si se quita La página se queda sin contenido. La página sigue completa, pero sin diseño.

Esa separación no es un capricho técnico: es lo que permite cambiar todo el aspecto de un sitio —colores, tipografías, tamaños— tocando un solo archivo, sin abrir ni una de las páginas. Y es también lo que hace que un mismo contenido pueda verse distinto en una pantalla de computadora y en un celular.

Hay una consecuencia menos visible y más importante. Como HTML significa y CSS solo muestra, un texto marcado como título es un título para todos: para el navegador, para el buscador que indexa la página y para el lector de pantalla que usa una persona ciega. Un párrafo agrandado y puesto en negrita con CSS se ve como un título y no lo es: quien no lo ve con los ojos nunca se va a enterar de que ahí empieza una sección. La apariencia engaña; el significado, no.

Estructura básica: DOCTYPE, html, head, title y body

Toda página HTML, por larga y compleja que sea, tiene el mismo esqueleto. Cinco piezas:

<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="utf-8">
    <title>Alta de socios</title>
</head>
<body>
    <h1>Alta de socios</h1>
    <p>Complete los datos del nuevo socio.</p>
</body>
</html>
Pieza Se ve Para qué
<!DOCTYPE html> No No es una etiqueta sino una declaración: avisa que el documento es HTML5 y que se interprete con las reglas actuales.
<html> No Es la raíz. Todo el documento va adentro, y el lang declara el idioma.
<head> No Los metadatos: datos sobre la página que no se muestran. Codificación, título, hojas de estilo, íconos.
<title> En la pestaña El nombre de la página. Aparece en la pestaña, en favoritos y en el resultado del buscador.
<body> Todo El contenido visible. Lo que está adentro del <head> no se muestra nunca.

Vale detenerse en el <!DOCTYPE html>. Parece un detalle decorativo y no lo es: si falta, el navegador entra en un modo de compatibilidad con páginas de los años noventa y empieza a interpretar medidas y espacios con reglas viejas. La página «se ve» parecida, pero con diferencias molestas de tamaño y márgenes que después cuesta muchísimo encontrar.

Y el <meta charset="utf-8"> merece mención aparte en un sitio en castellano: es lo que hace que las eñes y los acentos se vean bien. Sin esa línea, un apellido como Martínez puede aparecer como MartÃnez. Es un error que solo se nota en el navegador y que suele echarse la culpa a la base de datos, cuando en realidad es un dato que se perdió en el camino.

Etiquetas y atributos: apertura, cierre y anidamiento

Una etiqueta es una marca que envuelve contenido. Casi siempre vienen de a dos: una de apertura y una de cierre, y la de cierre se distingue por la barra.

<p>Este es un párrafo.</p>
 ↑                          ↑
 apertura                 cierre

Hay unas pocas que no tienen cierre porque no envuelven nada: no contienen texto, son la cosa en sí. Se llaman etiquetas vacías, y son <br>, <hr>, <img>, <input> y <meta>, entre otras. Escribir </br> no rompe nada, pero está mal.

El anidamiento

Las etiquetas se meten una dentro de otra, y hay una sola regla: la última que se abre es la primera que se cierra.

<!-- Bien: se cruzan como los paréntesis -->
<p>Un texto con <strong>una parte en negrita</strong> y sigue.</p>

<!-- Mal: las etiquetas se pisan -->
<p>Un texto con <strong>una parte en negrita</p></strong>

El segundo caso es el error más frecuente de quien empieza, y es peligroso justamente porque el navegador lo perdona: hace lo que puede y muestra algo parecido a lo esperado. Entonces el error no se ve, queda escondido, y aparece después cuando el diseño deja de funcionar como uno espera.

Los atributos

Un atributo da información extra sobre una etiqueta. Se escribe siempre en la etiqueta de apertura, con la forma nombre="valor". La de cierre nunca lleva atributos.

<a href="/socios" class="boton" target="_blank">Ver los socios</a>
   ↑ atributo        ↑ atributo    ↑ atributo

Las convenciones son pocas y ayudan a no perderse: nombres de etiquetas y atributos en minúscula, valores entre comillas dobles y sin repetir un atributo en la misma etiqueta. Ninguna de las tres la exige el navegador, y las tres hacen que el código se pueda leer y revisar años después.

Textos: títulos, párrafos, énfasis y texto destacado

La mayor parte del contenido de una página es texto, y HTML tiene una etiqueta para cada papel que ese texto puede cumplir.

Etiqueta Qué significa Cómo se ve
<h1> … <h6>Título de nivel 1 a 6. <h1> es el principal, <h6> el más subordinado.Más grande cuanto más importante.
<p>Un párrafo: una idea.Bloque de texto con espacio arriba y abajo.
<strong>Importancia. Lo que hay que leer aunque se lea rápido.Negrita.
<em>Énfasis. Cambia el sentido de lo que se dice.Cursiva.
<mark>Texto destacado, al estilo de un resaltador.Fondo amarillo.
<br>Un salto de línea dentro del mismo bloque.Corta el renglón.
<hr>Una separación entre temas.Línea horizontal.
<small>Texto al margen: una aclaración, la letra chica.Más chico.

Hay dos distinciones que cuestan al principio, y las dos tienen que ver con lo mismo: hay etiquetas que significan y etiquetas que solo pintan. <strong> y <b> se ven igual —los dos en negrita— pero solo el primero dice que ese texto es importante. Lo mismo pasa con <em> y <i>: los dos en cursiva, pero solo <em> indica énfasis. Como la apariencia se puede cambiar con CSS en cualquier momento, conviene usar siempre las que significan: si mañana el diseñador decide que lo importante va en otro color y no en negrita, el significado sigue ahí.

Los títulos tienen dos reglas que no son de estilo sino de estructura. La primera: hay un solo <h1> por página, porque es el título de todo el documento. La segunda: no se saltean niveles. De un <h1> se pasa a <h2>, y de un <h2> a <h3>; nunca de <h1> a <h4>. Eso arma el índice de la página, el que usan los lectores de pantalla para navegar y los buscadores para entender de qué se habla.

Listas: ordenadas y no ordenadas

Una lista agrupa elementos del mismo tipo. Hay dos, y la diferencia es una sola pregunta: ¿importa el orden?

Lista Cuándo se usa Ejemplos
<ul>
no ordenada
Cuando los elementos son intercambiables: el orden no cambia el significado. Provincias, materias, ingredientes, opciones de un menú.
<ol>
ordenada
Cuando el orden es parte del contenido. Un procedimiento paso a paso, un ranking, un reglamento.

Cada elemento va dentro de un <li>, sin importar de qué tipo sea la lista:

<!-- No importa el orden -->
<ul>
    <li>Provincia de Buenos Aires</li>
    <li>Córdoba</li>
    <li>Santa Fe</li>
</ul>

<!-- Sí importa el orden -->
<ol>
    <li>Completar el formulario</li>
    <li>Presentar el DNI</li>
    <li>Retirar el carnet</li>
</ol>

Las listas se pueden anidar, y para eso hay un detalle que se equivoca siempre: la lista de adentro va dentro del <li> al que pertenece, no antes ni después.

<ul>
    <li>Buenos Aires
        <ul>
            <li>La Plata</li>
            <li>Bahía Blanca</li>
        </ul>
    </li>
    <li>Córdoba</li>
</ul>

Y hay un tercer tipo, para glosarios: <dl> con pares de <dt> (el término) y <dd> (su definición). Es la estructura correcta para un diccionario de datos o una lista de siglas. Lo que no hay que hacer es simular una lista con guiones y saltos de línea —«- Provincial», «- Municipal»—: se ve parecido y no es una lista, así que el lector de pantalla lo lee como un texto cualquiera y no anuncia cuántos elementos tiene.

Enlaces: navegación entre páginas y rutas relativas

El enlace es lo que hace que la web sea una telaraña y no una pila de documentos sueltos. Se arma con <a> y su atributo href, que es la dirección de destino.

<a href="/socios/listado">Ver el listado de socios</a>

La parte que más problemas trae es cómo se escribe esa dirección, porque hay dos formas y no son intercambiables:

Forma Ejemplo Significa
Absoluta https://sitio.com.ar/socios La dirección completa, con protocolo y dominio. No depende de dónde esté la página.
Relativa a la raíz /socios/listado Desde la raíz del dominio. Empieza con barra.
Relativa a la carpeta listado.html
../socios/listado.html
Desde donde está la página actual. Sin barra al principio. Los dos puntos suben un nivel.

Las relativas son cómodas mientras se trabaja en la propia computadora, pero tienen una trampa: si el sitio se mueve de carpeta o de dominio, todos los enlaces se rompen de golpe. Las absolutas se bancan el cambio, y las relativas a la raíz también —siempre que el sitio esté en la raíz del dominio—. Es exactamente el problema que aparece cuando un sitio se publica dentro de una subcarpeta: los enlaces que funcionaban en la máquina de quien lo hizo empiezan a dar error 404 en el servidor.

Tres detalles más que conviene tener presentes. Los enlaces internos de una misma página se hacen con un id y una almohadilla: <a href="#resumen"> salta al elemento con id="resumen"; es lo que usan los índices laterales. Los enlaces que abren en otra pestaña llevan target="_blank" y conviene acompañarlos de rel="noopener". Y el texto del enlace debería describir a dónde lleva: «Ver el listado de socios» informa; «clic aquí» no dice nada, y quien usa un lector de pantalla suele recorrer la página salteando de enlace en enlace, así que escucha una lista de «clic aquí» sin saber a dónde va ninguno.

Imágenes: inserción, atributo alt y dimensiones

Una imagen se inserta con <img>, que es una etiqueta vacía: no envuelve nada. Necesita dos atributos, y uno de los dos no es opcional.

<img src="/img/carnet.jpg" alt="Foto del socio en el carnet" width="240" height="320">
Atributo Para qué Qué pasa si falta
src La ruta del archivo de imagen. No hay imagen.
alt El texto alternativo: describe la imagen para quien no puede verla. La imagen es inaccesible, y el buscador no sabe qué muestra.
width y height Las dimensiones, para reservar el espacio antes de que la imagen cargue. El contenido «salta» cuando la imagen termina de cargar.

El alt cumple tres funciones a la vez, y las tres se notan en momentos distintos. Cuando la imagen no carga —la ruta está mal, se cayó la conexión—, el navegador muestra ese texto en su lugar y el usuario al menos entiende qué faltaba. Cuando alguien no puede ver y usa un lector de pantalla, el texto es lo único que hay. Y cuando un buscador indexa la página, es lo único que le dice de qué se trata la imagen.

Escribirlo bien no es describir el archivo sino su contenido y su función: «Foto del socio en el carnet» sirve; «imagen1.jpg» o «foto», no. Y hay un caso en el que el atributo va vacío a propósito: cuando la imagen es puramente decorativa y no aporta información, se escribe alt="". Eso le avisa al lector de pantalla que la saltee, en lugar de hacerle escuchar la descripción de un adorno.

width y height no son para agrandar ni achicar: si el valor no respeta la proporción original, la imagen se deforma. Para eso está CSS. Lo que hacen acá es decirle al navegador cuánto espacio reservar antes de que el archivo llegue, y así evitar que el texto se mueva de golpe cuando la imagen aparece —ese salto molesto, sobre todo cuando alguien está por tocar un botón y el botón se corre solo—.

Dos cosas más que valen para cualquier sitio. Los formatos: JPG para fotografías, PNG cuando hace falta fondo transparente, SVG para dibujos y gráficos hechos con líneas —que además no se pixelan al agrandarse— y WebP, que comprime mejor que los anteriores. Y el peso: una foto de cuatro megabytes arruina la carga de la página en un celular con datos móviles. Antes de subir una imagen conviene reducirla al tamaño real al que se va a mostrar. Una imagen de 4000 píxeles de ancho que se muestra en 300 no es una imagen mejor: es la misma imagen, mucho más lenta.

Estructura semántica: header, nav, main, section y footer

Antes de estas etiquetas, todas las partes de una página se marcaban con <div>, que no significa absolutamente nada: es una caja y punto. Entonces el código terminaba diciendo <div class="cabecera">, <div class="menu">, <div class="pie">: el significado estaba puesto a mano en un atributo, y solo lo entendía quien lo había escrito.

HTML5 incorporó etiquetas que ya significan:

Etiqueta Qué representa
<header>El encabezado de la página o de una sección: el título, el logo, el lema.
<nav>Un bloque de navegación: el menú principal, un índice.
<main>El contenido principal de la página. Va uno solo, y es lo que se saltea todo lo repetitivo.
<section>Una sección temática, que casi siempre arranca con un título.
<article>Una pieza que tiene sentido por sí sola: una noticia, una ficha, un comentario.
<aside>Contenido al margen: una nota lateral, información relacionada.
<footer>El pie: autoría, contacto, derechos.

La diferencia entre <section> y <article> se resuelve con una pregunta: ¿tendría sentido esto si lo saco de la página? La respuesta completa de un examen tiene sentido sola: es un <article>. El bloque «Preguntas frecuentes» de esa misma página, no: es una <section>.

Usar estas etiquetas tiene tres beneficios concretos. El primero es la accesibilidad: quien usa un lector de pantalla puede pedirle que lo lleve directo al contenido principal, y el lector sabe cuál es el menú y cuál el contenido. El segundo son los buscadores, que entienden mejor de qué trata la página. Y el tercero es el más subestimado: el código se vuelve legible para otras personas. Un <nav> se entiende sin explicación; un <div class="menu-2">, no. <div> y <span> siguen existiendo, pero como último recurso: se usan cuando no hay una etiqueta que signifique lo que se necesita, no como envase universal.

Tablas: filas, columnas, encabezados y presentación de datos

La tabla HTML sirve para una sola cosa: mostrar datos tabulados, es decir información que se organiza en filas y columnas y donde el cruce de las dos tiene sentido. Un listado de socios, un plan de cuentas, una grilla de horarios.

La estructura tiene una pieza que casi siempre se omite y que es la que le da sentido a todo: el encabezado.

<table>
    <caption>Préstamos del mes</caption>
    <thead>
        <tr>
            <th scope="col">Socio</th>
            <th scope="col">Libro</th>
            <th scope="col">Devolución</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>Ana Pérez</td>
            <td>Cien años de soledad</td>
            <td>12/05</td>
        </tr>
    </tbody>
</table>
Etiqueta Qué es
<table>La tabla completa.
<caption>El título de la tabla. Va primero y describe qué muestra.
<thead>El bloque de encabezados.
<tbody>El bloque de datos.
<tr>Una fila.
<th>Una celda de encabezado: nombra una columna o una fila.
<td>Una celda de dato.

La diferencia entre <th> y <td> no es que el primero se vea en negrita —eso es CSS— sino que uno encabeza y el otro contiene. El atributo scope="col" lo confirma: le dice al lector de pantalla que ese encabezado nombra a toda la columna. Gracias a eso, al recorrer la tabla se escucha «Socio: Ana Pérez» en lugar de un valor suelto sin contexto. Las tablas de verdad tienen encabezados en el <thead> con <th>, no filas en negrita con <td>.

Para unir celdas están colspan —cuántas columnas abarca— y rowspan —cuántas filas—. Conviene usarlos con moderación: una tabla llena de celdas unidas es imposible de leer desde un lector de pantalla, porque cada celda depende de contar bien cuántas se saltearon las anteriores. Y un último dato: que la base de datos tenga una tabla no obliga a que la página muestre una tabla HTML. Muchas veces los mismos datos se entienden mejor como una lista de fichas. La tabla HTML es una herramienta entre varias, no un reflejo automático de la base.

Formularios: etiquetas, campos, listas y botones

Esta sección es el inventario de las etiquetas que forman un formulario. Qué hace cada control y cuál conviene para cada dato se ve en Tipos de ingreso; acá interesa la estructura.

Etiqueta Qué aporta
<form>El envoltorio. Define qué se envía junto, a dónde y cómo.
<label>El rótulo de un campo. Se une al control con for = id.
<input>El control propiamente dicho. Su comportamiento lo decide el atributo type.
<select>Una lista desplegable.
<option>Cada una de las opciones de esa lista.
<optgroup>Un grupo de opciones dentro de la lista, con su propio rótulo.
<textarea>Un campo de varias líneas.
<button>Un botón. Con type="submit" envía el formulario.
<fieldset>Agrupa controles relacionados con un borde.
<legend>El título de ese grupo.

Hay dos controles que tienen su propia lógica interna. En <select>, la opción que aparece elegida por defecto se marca con selected; si no se marca ninguna, el navegador muestra la primera, que muchas veces es un error —porque el usuario cree que eligió algo que en realidad nunca tocó—. Y en <textarea> el valor inicial no va en un atributo value sino entre la etiqueta de apertura y la de cierre.

<fieldset> y <legend> son los más olvidados y los más útiles. Cuando varios controles forman una sola pregunta —el estado civil, el turno—, agruparlos hace que un lector de pantalla anuncie el título del grupo antes de cada opción: «Turno: mañana, opción 1 de 2». Sin el <fieldset>, se escuchan dos opciones sueltas sin saber a qué pregunta pertenecen.

<fieldset>
    <legend>Turno</legend>

    <input type="radio" id="manana" name="turno" value="manana">
    <label for="manana">Mañana</label>

    <input type="radio" id="tarde" name="turno" value="tarde">
    <label for="tarde">Tarde</label>
</fieldset>

Fijate en los dos botones de opción: tienen id distintos, pero el mismo name. Y eso no es un descuido: es lo que los convierte en un grupo donde solo se puede elegir uno. Al compartir el name, el navegador entiende que son respuestas de la misma pregunta y desmarca la anterior al marcar la siguiente. El value, en cambio, es distinto en cada uno: es el dato que efectivamente viaja. Si esa distinción se confunde, el resultado es un grupo donde se pueden marcar las dos opciones a la vez, o donde las dos mandan el mismo valor.

Validaciones básicas: campos obligatorios, tipos de entrada y límites

HTML puede revisar solo, sin una línea de programación, que lo que se escribió tenga cierto sentido. No hace falta un lenguaje de servidor ni JavaScript: son atributos.

Atributo Qué exige Ejemplo
requiredQue el campo no quede vacío.required
typeQue el contenido tenga la forma del tipo declarado.type="email"
min / maxUn rango permitido para números y fechas.min="1" max="99"
minlength / maxlengthLa cantidad de caracteres permitida.maxlength="8"
patternQue respete una expresión regular.pattern="[0-9]{8}"
stepLos saltos válidos de un número.step="0.01"
acceptQué tipos de archivo acepta un campo de archivo.accept="image/*"

Si algo no cumple, el navegador no envía el formulario y muestra un aviso junto al campo. Es una ayuda enorme: el usuario corrige en el momento y no descubre el error dos días después. Pero es imprescindible entender qué es y qué no es esta validación.