Tablas de datos

Una tabla muestra datos en filas y columnas.

<table>
  <tr>
    <th>Alumno</th>
    <th>Nota</th>
  </tr>
  <tr>
    <td>Ana</td>
    <td>6,5</td>
  </tr>
</table>
EtiquetaQué es
<table>Envuelve toda la tabla
<tr>Table row: una fila
<th>Table header: una celda de encabezado. Se ve en negrita y centrada
<td>Table data: una celda normal de datos

Celdas que ocupan varias columnas o filas

<table>
  <caption>Notas del primer semestre</caption>
  <tr>
    <th>Alumno</th>
    <th colspan="2">Notas</th>
  </tr>
  <tr>
    <td>Ana</td>
    <td>6,5</td>
    <td>5,9</td>
  </tr>
</table>
AtributoQué hace
<caption>El título de la tabla. Va justo después de <table> y se lee antes que nada en un lector de pantalla
colspan="2"Esa celda ocupa 2 columnas
rowspan="2"Esa celda ocupa 2 filas

Cuenta las celdas cuando uses colspan

Si una fila declara colspan="2" y las demás tienen tres celdas sueltas, la tabla queda descuadrada y el navegador no avisa. La suma de columnas de cada fila, contando los colspan, tiene que dar siempre el mismo número.

Las tablas son para datos, no para maquetar

Un horario, una lista de notas, un catálogo de precios: eso es una tabla. La disposición de la página (columnas, barras laterales, cuadrículas) se hace con CSS.

Maquetar con tablas fue normal hace veinte años y hoy es un error: rompe la lectura en lectores de pantalla y se desarma en pantallas chicas.

¿Por qué los formularios?

La tabla muestra datos que ya existen. El formulario es el que los captura.

QuiénQué hace
El usuarioEscribe datos: nombre, correo, una búsqueda, un pedido
El formularioLa puerta de entrada: recoge lo escrito y lo envía
El servidorRecibe y procesa. Lo veremos con PHP, más adelante

Todo sistema necesita recibir datos: un registro, un login, un pedido, una búsqueda. Hoy construimos la puerta con HTML; procesar lo que entra por ella viene después.

Anatomía de un formulario

<form action="" method="GET">
  <label for="correo">Correo</label>
  <input id="correo" name="correo" type="email"
         placeholder="tu@correo.cl" required>
 
  <button type="submit">Enviar</button>
</form>
Elemento / atributoQué hace
<form>Envuelve los campos
actionA dónde se envían: el archivo del servidor que los recibirá. Ese archivo lo escribiremos con PHP; por ahora va vacío
methodCómo se envían: GET los pone en la URL; POST los manda dentro de la solicitud, sin mostrarlos
<label>Describe el campo; se asocia con for / id
<input>El campo donde se escribe. Su type define qué acepta
nameEl nombre con el que llega el dato al servidor
requiredEl navegador no deja enviar si el campo está vacío
placeholderTexto gris de ejemplo dentro del campo

Sin name el dato se pierde

Un campo sin name simplemente no se envía, y nadie te avisa: el formulario se manda, el navegador no protesta, y ese dato nunca llega. Es el error más común de todos.

id frente a name

Se confunden todo el tiempo porque suelen valer lo mismo:

  • id enlaza el <label> con el campo, dentro del HTML. Hace que al hacer clic en la etiqueta se enfoque el campo, y es lo que anuncia el lector de pantalla.
  • name es el nombre con el que el dato viaja hacia el servidor.

Lo normal es poner el mismo valor en los dos.

El placeholder no reemplaza al label

El texto gris desaparece en cuanto el usuario empieza a escribir. Si era la única indicación de qué iba ahí, el usuario se queda sin referencia a mitad de camino. El label se queda siempre.

Al enviar, mira la barra de direcciones

Solo con HTML nadie procesa los datos: la página se vuelve a cargar y el formulario queda vacío. Pero con method="GET" los datos viajan en la URL, y ahí los puedes ver: contacto.html?correo=ana%40correo.cl. Son los mismos parámetros de la anatomía de una URL.

En esta unidad usamos GET justamente para verlos. En la Unidad 2, cuando PHP reciba el envío, pasaremos a POST, que es lo correcto para datos como una contraseña: con GET quedaría escrita en la URL y en el historial.

Con Live Server, method="POST" muestra «Cannot POST»

Live Server solo sabe entregar archivos, no recibir envíos. Un formulario con POST le pide algo que no sabe hacer y responde con esa página de error. No es un problema de tu HTML: cámbialo a GET por ahora.

Agrupar campos relacionados

<form action="" method="GET">
  <fieldset>
    <legend>Datos personales</legend>
 
    <label for="nombre">Nombre</label>
    <input id="nombre" name="nombre" type="text" required>
  </fieldset>
 
  <fieldset>
    <legend>Tu consulta</legend>
    …
  </fieldset>
</form>
ElementoQué hace
<fieldset>Agrupa campos que van juntos y dibuja un marco alrededor
<legend>El título de ese grupo. Va como primer hijo del fieldset

Úsalo cuando el formulario tenga más de cinco campos

Un formulario largo sin agrupar se lee como una lista interminable. Con dos o tres fieldset el usuario ve de entrada cuánto le falta, y el lector de pantalla anuncia el legend al entrar en cada grupo.

Tipos de campo

El type del <input> define qué acepta el campo, y de paso da validación gratis: el navegador se encarga.

1 · Texto, correo y contraseña

typeQué aceptaDetalle
textTexto libre de una líneaEl más común
emailFormato de correoExige arroba y dominio. En el celular aparece el teclado con arroba
passwordTexto ocultoLo escrito se ve como puntos

password no cifra nada

Solo tapa la pantalla para que nadie lea por encima del hombro. El dato viaja tal cual. Lo que protege el envío es HTTPS, que viste en cómo funciona la web.

2 · Números, fechas y texto largo

ElementoQué aceptaDetalle
type="number"Solo númerosAdmite min y max. Trae flechas para subir y bajar
type="date"Una fechaAbre el calendario del navegador, así la fecha llega siempre con el mismo formato
<textarea>Texto largo, de varias líneasNo es un input: es un elemento aparte y sí se cierra

3 · Elegir entre opciones

Cuando el dato no se escribe, se elige.

ElementoCuántas se eligenDetalle
type="checkbox"Ninguna, una o variasCada casilla es independiente
type="radio"Solo una del grupoLo que las agrupa es compartir el mismo name
<select>Una de la listaLista desplegable, con un <option> por alternativa. Se cierra

El value es lo que realmente se envía

En los campos donde se escribe, el dato que viaja es lo que el usuario escribió. En los que se eligen, viaja el value (y el texto que se ve al lado es solo la etiqueta).

<input type="radio" id="diurna" name="jornada" value="diurna" checked>
<label for="diurna">Diurna</label>
 
<select name="asunto">
  <option value="consulta" selected>Consulta</option>
  <option value="reclamo">Reclamo</option>
</select>
AtributoEn qué campoQué hace
valueradio, checkbox, optionEl dato que se envía al servidor
checkedradio, checkboxDeja la opción marcada de entrada
selectedoptionDeja esa opción elegida de entrada

Un option sin value envía su texto visible

<option>Consulta</option> manda literalmente Consulta, con mayúscula y tildes. Si mañana cambias el texto a “Hacer una consulta”, cambia también el dato que llega al servidor y lo que ya estaba guardado deja de coincidir. Pon siempre un value corto y estable.

Poner límites al dato

AtributoEn qué campoQué hace
maxlengthtext, textareaMáximo de caracteres que deja escribir
min / maxnumber, dateValor mínimo y máximo aceptado
stepnumberDe cuánto en cuánto sube: step="0.1" permite decimales
patterntextUna expresión regular que el valor debe cumplir
<input type="number" name="edad" min="18" max="120" required>
<input type="text" name="rut" pattern="[0-9]{7,8}-[0-9kK]" placeholder="12345678-9">
<textarea name="mensaje" maxlength="500"></textarea>

La validación del navegador no reemplaza a la del servidor

Todo esto se puede saltar: basta con abrir el inspector (F12), borrar el required del campo y enviar, o mandar la petición por fuera del formulario. Sirve para ayudar al usuario a no equivocarse, no para proteger el sistema.

El dato se valida otra vez en el servidor, siempre. Eso lo veremos con PHP.

Los radio se agrupan por el name

Si dos botones de radio tienen name distinto, el navegador los trata como grupos separados y se pueden marcar los dos a la vez. Comparten name y se distinguen por value.

Un formulario con todos los tipos

<form action="" method="GET">
  <input type="text"     name="nombre"     required>
  <input type="email"    name="correo">
  <input type="password" name="clave">
  <input type="number"   name="edad" min="18">
  <input type="date"     name="nacimiento">
 
  <textarea name="mensaje"></textarea>
 
  <input type="checkbox" name="foto">
 
  <input type="radio" name="jornada" value="diurna">
  <input type="radio" name="jornada" value="vespertina">
 
  <select name="asunto">
    <option value="consulta">Consulta</option>
    <option value="reclamo">Reclamo</option>
  </select>
 
  <button type="submit">Enviar</button>
</form>

Tres cosas que revisar en ese bloque:

  • Todos los campos llevan name.
  • Los dos radio comparten el mismo name (son el mismo grupo) y se distinguen por value.
  • textarea y select se cierran; input no.

Falta un <label> por campo

El ejemplo está comprimido para que quepan todos los tipos juntos. En tu código, cada campo lleva su <label for="…"> delante.

La tabla donde irán los datos

El formulario decide las columnas: una por cada name. Las filas, por ahora, las escribimos a mano con datos de ejemplo.

<table>
  <thead>
    <tr>
      <th>Nombre</th>
      <th>Correo</th>
      <th>Asunto</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Ana Soto</td>
      <td>ana@correo.cl</td>
      <td>Consulta</td>
    </tr>
    <tr>
      <td>Beto Díaz</td>
      <td>beto@correo.cl</td>
      <td>Reclamo</td>
    </tr>
  </tbody>
</table>
EtiquetaQué agrupa
<thead>La fila de títulos, una sola vez
<tbody>Las filas de datos

El orden de los <th> y el de los <td> debe coincidir

Si mueves una columna en el encabezado, mueve también sus celdas. Nada te avisa si quedan cruzadas: la tabla se dibuja igual, con los datos en la columna equivocada.

Con HTML solo no se pueden mostrar los datos enviados

Al apretar enviar, los datos aparecen en la URL pero no en la tabla. HTML no recuerda nada y no hay quién procese el envío.

Leerlos y mostrarlos lo hará PHP con la base de datos, en las unidades 2 y 3. Lo que hacemos hoy es dejar preparada la tabla donde después irán esos datos.

Incrustar contenido de otro sitio

Un <iframe> mete otra página completa dentro de un hueco de la tuya. Es lo que usan los mapas de Google y los videos de YouTube.

<!-- Un video de YouTube -->
<iframe width="560" height="315"
        src="https://www.youtube.com/embed/CODIGO_DEL_VIDEO"
        title="Descripción del video"
        allowfullscreen></iframe>
 
<!-- Un mapa de Google -->
<iframe src="https://www.google.com/maps/embed?pb=..."
        width="600" height="450"
        title="Ubicación de la UMAG"
        loading="lazy"></iframe>
AtributoPara qué
srcLa dirección de la página que se incrusta
width / heightEl tamaño del hueco
titleDescribe qué hay dentro. Es el alt de los iframes: obligatorio por accesibilidad
loading="lazy"No lo carga hasta que el usuario se acerca a él. Acelera la página

Copia el código que te da el propio sitio

En YouTube: Compartir → Insertar. En Google Maps: Compartir → Incorporar un mapa. Ambos entregan el <iframe> completo y ya armado.

La URL de la barra de direcciones no sirve

youtube.com/watch?v=abc123 no funciona dentro de un iframe: YouTube lo bloquea. La que sirve es la de incrustar, youtube.com/embed/abc123, que es la que da el botón Insertar.

No todos los sitios se dejan incrustar

Un sitio puede prohibir que lo metan en un iframe ajeno, y entonces el hueco aparece en blanco o con un mensaje de error. Es una medida de seguridad del sitio incrustado, no un fallo de tu código.

Checkpoint

Intenta responder antes de desplegar cada pregunta.