Atributos HTML que deberías conocer
HTML tiene atributos que van mucho más allá de class, id o href. Algunos afectan al rendimiento, otros a la accesibilidad y otros al comportamiento del navegador. Esta lección recorre los más útiles y desconocidos.
Scripts: defer y async
Cuando el navegador encuentra un <script> en el HTML, detiene el análisis del documento para descargarlo y ejecutarlo. Eso puede hacer que la página tarde más en mostrarse. defer y async evitan ese bloqueo.
<!-- Bloquea el análisis del HTML (comportamiento por defecto) -->
<script src="app.js"></script>
<!-- Se descarga en paralelo y se ejecuta al terminar el HTML -->
<script src="app.js" defer></script>
<!-- Se descarga en paralelo y se ejecuta en cuanto esté listo -->
<script src="app.js" async></script>
¿Cuándo usar cada uno?
| Atributo | Descarga | Ejecución | Uso recomendado |
|---|---|---|---|
| Ninguno | Bloquea HTML | Inmediata | Evitar siempre que sea posible |
defer | En paralelo | Al terminar el HTML, en orden | Scripts que necesitan el DOM completo |
async | En paralelo | En cuanto termina la descarga | Scripts independientes (analytics, ads) |
Regla práctica: usa defer para tus scripts de aplicación. Usa async solo para scripts de terceros que no dependen del DOM ni de otros scripts.
rel en enlaces y recursos
El atributo rel (relationship) describe la relación entre la página actual y el recurso enlazado. Es esencial para <link> y <a>.
En <link>
<!-- Hoja de estilos -->
<link rel="stylesheet" href="estilos.css" />
<!-- Icono de la pestaña -->
<link rel="icon" href="/favicon.ico" />
<!-- Precargar un recurso crítico antes de que se necesite -->
<link rel="preload" href="fuente.woff2" as="font" crossorigin />
<!-- Preconectar al dominio de una API o CDN -->
<link rel="preconnect" href="https://fonts.googleapis.com" />
<!-- DNS prefetch: resolver el dominio antes de necesitarlo -->
<link rel="dns-prefetch" href="https://api.ejemplo.com" />
<!-- Feed RSS -->
<link rel="alternate" type="application/rss+xml" href="/rss.xml" />
En <a>
<!-- Enlace externo: no transmite autoridad SEO -->
<a href="https://externo.com" rel="nofollow">Enlace externo</a>
<!-- Abre enlace externo sin dar acceso a window.opener -->
<a href="https://externo.com" target="_blank" rel="noopener noreferrer">
Enlace seguro
</a>
<!-- Patrocinado -->
<a href="https://sponsor.com" rel="sponsored">Patrocinador</a>
Seguridad: siempre usa
rel="noopener noreferrer"en enlaces contarget="_blank". Sin él, la página destino puede acceder al objetowindowde tu página.
hidden: ocultar sin CSS
El atributo booleano hidden oculta un elemento completamente (equivalente a display: none):
<div id="mensaje" hidden>
Este mensaje está oculto inicialmente.
</div>
<button onclick="document.getElementById('mensaje').hidden = false">
Mostrar mensaje
</button>
A diferencia de una clase CSS, hidden es semántico: comunica que el contenido no es relevante en este momento, no solo que no es visible. Los lectores de pantalla lo respetan.
hidden="until-found"
Una variante especial: el elemento está oculto pero los motores de búsqueda y la búsqueda en página (Ctrl+F) pueden encontrarlo. Se revela automáticamente si el usuario busca texto en su interior:
<details>
<summary>Información adicional</summary>
<div hidden="until-found" id="extra">
Este contenido aparecerá si el usuario lo busca con Ctrl+F.
</div>
</details>
inert: bloquear toda interacción
inert desactiva completamente un elemento y todo su contenido: no recibe clics, no es navegable con teclado y los lectores de pantalla lo ignoran.
<div id="formulario" inert>
<input type="text" placeholder="No se puede editar" />
<button>Tampoco funciona</button>
</div>
Es ideal para:
- Deshabilitar una sección mientras se carga contenido.
- Garantizar que un modal bloquea el fondo de forma accesible.
- Deshabilitar formularios temporalmente.
// Activar/desactivar con JavaScript
const formulario = document.getElementById('formulario');
formulario.inert = true; // bloquear
formulario.inert = false; // desbloquear
contenteditable: editar contenido en el navegador
Hace que el contenido de un elemento sea editable directamente en el navegador:
<p contenteditable="true">
Haz clic aquí para editar este texto directamente.
</p>
<!-- Edición de código con resaltado correcto -->
<pre contenteditable="true" spellcheck="false">
const saludo = "Hola mundo";
</pre>
Valores:
contenteditable="true"o simplementecontenteditable→ editable.contenteditable="false"→ no editable (por defecto).contenteditable="plaintext-only"→ editable pero solo acepta texto plano (sin HTML).
spellcheck: control del corrector ortográfico
<!-- Activo (por defecto en inputs y contenteditable) -->
<textarea spellcheck="true"></textarea>
<!-- Desactivado: ideal para código, contraseñas, campos técnicos -->
<input type="text" name="codigo" spellcheck="false" />
<pre contenteditable spellcheck="false">código aquí</pre>
tabindex: control del orden de foco
Controla si un elemento es focusable y en qué orden con la tecla Tab:
<!-- Excluir del orden de tabulación -->
<button tabindex="-1">No se puede enfocar con Tab</button>
<!-- Incluir en el orden natural del DOM (valor recomendado para elementos no interactivos) -->
<div role="button" tabindex="0">Div clickable accesible</div>
<!-- Orden explícito (desaconsejado, difícil de mantener) -->
<input tabindex="3" />
<input tabindex="1" />
<input tabindex="2" />
Regla práctica: usa tabindex="0" para hacer focusable un elemento no interactivo (div, span). Evita valores positivos porque rompen el orden natural de navegación.
translate: control de traducción automática
Indica a los traductores automáticos (como Google Translate) si deben traducir el contenido:
<!-- No traducir: código, nombres de marca, comandos -->
<code translate="no">npm install</code>
<span translate="no">GitHub Copilot</span>
<!-- Traducir (comportamiento por defecto) -->
<p translate="yes">Este texto sí se traducirá.</p>
autocomplete: control del autocompletado de formularios
<!-- Autocompletado estándar del navegador -->
<input type="email" autocomplete="email" />
<input type="tel" autocomplete="tel" />
<input type="text" autocomplete="name" />
<!-- Desactivar el autocompletado (para campos sensibles) -->
<input type="text" name="codigo_acceso" autocomplete="off" />
<!-- Contraseña nueva: evita que el navegador sugiera la actual -->
<input type="password" autocomplete="new-password" />
<!-- Contraseña actual -->
<input type="password" autocomplete="current-password" />
Los valores estándares de autocomplete permiten al navegador rellenar los formularios correctamente y mejoran la experiencia en móvil.
inputmode: teclado en móvil
Indica qué teclado mostrar en dispositivos móviles sin cambiar el tipo del input:
<!-- Teclado numérico para un campo de texto libre -->
<input type="text" inputmode="numeric" pattern="[0-9]*" />
<!-- Teclado con punto decimal para precios -->
<input type="text" inputmode="decimal" />
<!-- Teclado de teléfono (con +, * y #) -->
<input type="text" inputmode="tel" />
<!-- Teclado con @ y .com para emails -->
<input type="text" inputmode="email" />
<!-- Teclado optimizado para URLs -->
<input type="text" inputmode="url" />
loading en iframes
Igual que en imágenes, loading="lazy" también funciona en <iframe>:
<!-- El iframe no se carga hasta que esté cerca del viewport -->
<iframe
src="https://www.youtube.com/embed/dQw4w9WgXcQ"
loading="lazy"
title="Vídeo incrustado"
allow="accelerometer; autoplay; clipboard-write; encrypted-media"
>
</iframe>
Resumen rápido
| Atributo | Para qué sirve |
|---|---|
defer | Script no bloqueante, ejecuta tras el HTML |
async | Script no bloqueante, ejecuta al descargar |
rel="noopener noreferrer" | Seguridad en enlaces con target="_blank" |
rel="preload" | Precarga un recurso crítico |
rel="preconnect" | Preconecta a un dominio externo |
hidden | Oculta semánticamente un elemento |
hidden="until-found" | Oculto pero indexable y buscable con Ctrl+F |
inert | Bloquea toda interacción en el elemento y sus hijos |
contenteditable | Hace editable el contenido en el navegador |
spellcheck="false" | Desactiva el corrector (ideal en campos de código) |
tabindex="0" | Hace focusable un elemento no interactivo |
tabindex="-1" | Excluye del orden de tabulación |
translate="no" | Impide la traducción automática del contenido |
autocomplete | Controla el autocompletado del navegador |
inputmode | Define el teclado en móvil |
¿Qué hemos aprendido?
deferes el comportamiento correcto para la mayoría de scripts.rel="noopener noreferrer"es obligatorio en enlaces externos contarget="_blank".inertes la forma correcta de bloquear una sección completa (más potente quedisabled).inputmodemejora la experiencia en móvil sin cambiar la validación del campo.translate="no"protege nombres de marca y código de los traductores automáticos.
Siguiente paso
En la última lección veremos SEO on-page con HTML: cómo escribir el <head> correcto, la importancia del H1 único, el canonical, las Open Graph tags y el structured data.