← Ruta MERN: todos los módulos
Ruta MERN · Módulo 1 de 7

HTML, CSS y JavaScript

Fundamentos de la web: HTML semántico y formularios, CSS con Flexbox, Grid y diseño adaptable, y JavaScript moderno (ES6+): funciones, DOM, asincronía con promesas y async/await, y la Fetch API.

Definición

Toda página web se arma con tres lenguajes que el navegador entiende sin instalar nada. Cada uno tiene un trabajo distinto:

LenguajeQué esSu trabajoEn el restaurante
HTMLLenguaje de marcado (HyperText Markup Language)La estructura: qué hay en la página y qué es cada cosaLa carta: qué platillos hay, sus nombres y precios
CSSHojas de estilo en cascada (Cascading Style Sheets)La presentación: colores, letras, tamaños y acomodoEl diseño de la carta: tipografía, colores y orden
JavaScriptLenguaje de programaciónEl comportamiento: reaccionar a clics, pedir datos y cambiar la páginaLo que pasa cuando tocas «Agregar»: el pedido se arma y el total se suma

En este módulo construimos la página del menú del Restaurante en línea con los tres. Es el mismo menú que en el módulo 3 pasará a React; lo que aprendas aquí es exactamente lo que React usa por dentro.

HTML: la estructura

HTML describe el contenido con etiquetas. Una etiqueta abre y cierra un elemento (<h1>…</h1>) y puede llevar atributos (<img src="pozole.jpg" alt="Plato de pozole rojo">).

Lo importante es usar la etiqueta que dice qué es cada cosa (HTML semántico), no la que «se ve» como uno quiere:

EtiquetaPara quéEn el menú
<header>Encabezado de la página o de una secciónNombre del restaurante
<main>El contenido principal (uno por página)Menú y pedido
<section>Una parte con su propio títuloEl menú
<nav>Un grupo de enlaces o controles de navegaciónFiltros por categoría
<aside>Contenido complementarioEl resumen del pedido
<ul> / <li>Lista y sus elementosLos platillos
<button>Una acción«Agregar», «Hacer pedido»
<form>, <label>, <input>Un formulario y sus camposLa propina
<template>Un molde que no se muestra; JavaScript lo copiaLa tarjeta de un platillo

Por qué importa la semántica:

  • Accesibilidad. Un lector de pantalla anuncia «botón, Agregar» o «región principal». Un <div> con un clic no dice nada.
  • Buscadores. Google entiende mejor la página cuando las etiquetas dicen qué es cada cosa.
  • Mantenimiento. Seis meses después, <aside class="pedido"> se entiende solo.

Cada <input> necesita su <label for="…">: al tocar la etiqueta se activa el campo, y el lector de pantalla sabe qué se pide.

CSS: la presentación

CSS aplica reglas a los elementos que elige un selector:

.platillo .precio {      /* selector: el precio dentro de cada platillo */
  font-weight: 700;      /* propiedad: valor */
}
SelectorEligeEjemplo
EtiquetaTodos los elementos de ese tipobody, h1
ClaseLos que tienen class="…" (el más usado).platillo
IdUno solo con id="…"#total
AtributoLos que tienen un atributo o valor[aria-pressed="true"]
DescendienteElementos dentro de otros.pedido form

La cascada. Si dos reglas chocan, gana la más específica (un id pesa más que una clase, y una clase más que una etiqueta) y, a igual peso, la que aparece después. Por eso conviene estilizar casi todo con clases.

El modelo de caja. Todo elemento es una caja: contenido, padding (relleno), border (borde) y margin (separación). Con box-sizing: border-box el ancho que declaras incluye el relleno y el borde, y las cuentas salen como esperas.

Variables. --acento: #1f7a4a; en :root define un color que se reutiliza con var(--acento). Cambiarlo en un lugar cambia toda la página.

Flexbox y Grid

Son las dos herramientas modernas para acomodar elementos:

FlexboxGrid
DimensiónUna (fila o columna)Dos (filas y columnas)
Úsalo paraUna fila de botones, alinear cosas dentro de una tarjetaEl acomodo de la página, una cuadrícula de tarjetas
En el menú.filtros y el interior de cada .platillo.contenido (menú y pedido) y .platillos

La cuadrícula de platillos se adapta sola, sin media queries:

.platillos {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: 16px;
}

«Tantas columnas como quepan, cada una de al menos 180 px». En el celular sale una; en la computadora, tres o cuatro.

Diseño adaptable (responsive)

Más de la mitad de los pedidos llegan desde un celular. Tres piezas lo resuelven:

  1. La etiqueta <meta name="viewport" content="width=device-width, initial-scale=1"> en el <head>. Sin ella, el celular muestra la versión de computadora en miniatura.
  2. Unidades relativas y clamp(): font-size: clamp(1.6rem, 5vw, 2.4rem) crece con la pantalla, sin pasarse.
  3. Media queries para los cambios grandes:
@media (max-width: 760px) {
  .contenido { grid-template-columns: 1fr; }  /* el pedido baja debajo del menú */
}

JavaScript: el comportamiento

JavaScript corre en el navegador y puede leer y cambiar la página mientras está abierta. Lo moderno (ES6 en adelante) que usamos:

HerramientaPara quéEjemplo
const / letDeclarar variables (const si no cambia)const pedido = new Map();
Funciones flechaFunciones cortas(p) => p.categoria === "bebidas"
Plantillas de textoTexto con valores` ${cantidad} × ${platillo.nombre} `
filter, find, mapRecorrer arreglos sin for manualmenu.filter(...)
MapPares llave → valor (id → cantidad)pedido.set(id, 3)
??Valor por defecto si es null o undefinedpedido.get(id) ?? 0
Intl.NumberFormatFormato de moneda local$1,250.00

El DOM

El navegador convierte el HTML en un árbol de objetos: el DOM (Document Object Model). JavaScript lo recorre y lo cambia:

const total = document.querySelector("#total");  // buscar un elemento
total.textContent = "$45.00";                     // cambiar su texto

const li = document.createElement("li");          // crear uno nuevo
li.textContent = "3 × Enchilada verde";
document.querySelector("#lineas").append(li);      // ponerlo en la página

Usa textContent para poner texto. innerHTML interpreta etiquetas, y con datos que escribió alguien más abre la puerta a inyectar código en tu página (XSS).

Eventos

La página reacciona con escuchadores de eventos:

boton.addEventListener("click", () => agregar(platillo.id));
document.querySelector("#propina").addEventListener("input", dibujarPedido);
formulario.addEventListener("submit", (evento) => {
  evento.preventDefault();  // no recargar la página
  // ...armar y enviar el pedido
});

En los filtros usamos delegación: un solo escuchador en el contenedor .filtros que revisa qué botón se tocó con evento.target.closest("button"). Sirve aunque los botones cambien.

Asincronía: promesas, async/await y fetch

Pedir datos a otra computadora tarda. Si JavaScript esperara sin hacer nada, la página se congelaría. Por eso fetch devuelve una promesa: «te aviso cuando llegue». Con async/await el código se lee de arriba abajo:

async function cargarMenu() {
  try {
    const respuesta = await fetch("platillos.json");
    if (!respuesta.ok) throw new Error(`HTTP ${respuesta.status}`);
    menu = await respuesta.json();   // texto JSON → arreglo de objetos
    dibujarMenu("todas");
  } catch (error) {
    estado.textContent = "No se pudo cargar el menú.";
  }
}

Dos detalles que confunden al empezar:

  • fetch no falla con un 404 o un 500: la promesa se cumple igual. Por eso revisamos respuesta.ok.
  • fetch no funciona con archivos abiertos con doble clic (file://). Hay que servir la carpeta: para eso es servir.mjs.

En el módulo 4 cambiamos "platillos.json" por "/api/platillos", la ruta de Express, y el resto del código queda igual.

Práctica: el menú del restaurante

El código completo está en el repositorio, carpeta modulos/01-html-css-javascript:

ArchivoQué hace
index.htmlEstructura: encabezado, menú con filtros, pedido con propina y el molde de tarjeta
estilos.cssVariables de color, Flexbox, Grid automático y la media query del celular
platillos.jsonLos 6 platillos con id, nombre, descripción, precio y categoría
menu.jsCarga el menú con fetch, lo dibuja, filtra, arma el pedido y suma el total
servir.mjsServidor estático solo con Node para abrir la página en localhost:5500
  1. Descarga el repositorio (o copia los cinco archivos en una carpeta).
  2. Abre una terminal en esa carpeta y ejecuta:
node modulos/01-html-css-javascript/servir.mjs
  1. Abre http://localhost:5500. Prueba:
    • Toca «Agregar» tres veces en la enchilada verde: el pedido dice 3 × Enchilada verde y el total $45.00.
    • Escribe 10 en la propina: el total pasa a $55.00.
    • Toca «Bebidas»: solo quedan el agua de jamaica y el café de olla.
    • Achica la ventana: debajo de 760 px el pedido baja debajo del menú.
  2. Abre las herramientas del navegador (F12), pestaña Consola, y toca «Hacer pedido». Verás el JSON que en el módulo 4 viajará a la cocina.

Este módulo se probó con Node v24.14.1 y Chrome, en 375 px y en pantalla de computadora.

Errores comunes

SíntomaCausaArreglo
«No se pudo cargar el menú» al abrir con doble clicfetch no lee archivos file://Abre con node servir.mjs
Cannot read properties of nullEl script corre antes de que exista el HTML<script src="menu.js" defer>
El total sale 4510 en lugar de 55El valor de un <input> siempre es textoNumber(input.value) (ver el quiz)
En el celular todo se ve diminutoFalta la etiqueta viewportAgrégala en el <head>
Un estilo no se aplicaOtra regla es más específica o va despuésRevisa la pestaña Elementos → Estilos

Quiz del módulo

¿Qué imprime este código?

const total = 45;       // 3 enchiladas
const propina = "10";   // lo que escribió el cliente en un <input>
console.log(total + propina);
  1. 55
  2. "4510" (el texto 4510)
  3. NaN
  4. Un error

Respuesta: 2. El valor de un <input> siempre llega como texto, aunque el campo sea type="number". Cuando sumas un número con un texto, JavaScript no suma: convierte el número en texto y los pega (concatena). Resultado: "4510". En un restaurante real, ese pedido de 45 pesos se cobraría como 4,510. El arreglo es convertir antes: total + Number(propina) da 55. Con -, o / JavaScript sí convierte a número ("10" 1 es 10); el + es el único que pega texto. Pruébalo tú: node -e 'console.log(45 + "10", 45 + Number("10"))'.

Referencias

En el reel lo explicamos así

La carta del restaurante. HTML es lo que dice la carta (qué platillos hay y sus precios), CSS es cómo se ve (letras, colores y orden) y JavaScript es lo que pasa cuando tocas «Agregar»: el pedido se arma y el total se suma.

Glosario: del inglés al español

Semantic HTMLHTML semántico: etiquetas que dicen qué es cada cosa
Responsive designdiseño adaptable a cualquier pantalla
DOMmodelo de objetos del documento: la página como objetos que JS puede cambiar
Event listenerescuchador de eventos: función que corre cuando pasa algo, como un clic
Async / awaitesperar una respuesta sin congelar la página
Fetchfunción del navegador para pedir datos a un servidor