Acerca de este problema HTML
Los atributos booleanos defer y async controlan cómo y cuándo se obtiene y ejecuta un script externo en relación con el parseo de HTML. Estos atributos existen específicamente para optimizar la carga de recursos externos. Un bloque <script> inline (uno sin atributo src) no necesita ser “descargado” — su contenido ya está incrustado en el documento HTML. Debido a esto, el atributo defer no tiene ningún efecto significativo en scripts inline, y la especificación HTML prohíbe explícitamente esta combinación.
Según el estándar vivo HTML de WHATWG, el atributo defer “no debe especificarse si el atributo src no está presente.” Los navegadores simplemente ignorarán el atributo defer en scripts inline, lo que significa que el script se ejecutará sincrónicamente como si defer nunca hubiera sido añadido. Esto puede confundir a los desarrolladores haciéndoles pensar que la ejecución de su script inline se está aplazando cuando no es así, causando potencialmente errores sutiles de sincronización que son difíciles de diagnosticar.
La misma regla se aplica al atributo async — también requiere la presencia de un atributo src para ser válido.
Cómo solucionarlo
Tienes dos opciones dependiendo de tu situación:
-
Si el script debe ser aplazado, mueve el código inline a un archivo
.jsexterno y refiérelo con el atributosrcjunto condefer. -
Si el script debe permanecer inline, elimina el atributo
defercompletamente. Si necesitas ejecución aplazada para código inline, considera colocar el elemento<script>al final del<body>, o usaDOMContentLoadedpara esperar a que el documento termine de parsearse.
Ejemplos
❌ Inválido: defer en un script inline
<script defer>
console.log("hello");
</script>
Esto activa el error de validación porque defer está presente sin un atributo src correspondiente.
✅ Opción de solución 1: Añadir un atributo src
Mueve el JavaScript a un archivo externo (ej., app.js) y refiérelo:
<script defer src="app.js"></script>
El navegador descargará app.js en paralelo con el parseo de HTML y lo ejecutará solo después de que el documento esté completamente parseado.
✅ Opción de solución 2: Eliminar defer del script inline
Si el script debe permanecer inline, simplemente elimina el atributo defer:
<script>
console.log("hello");
</script>
✅ Opción de solución 3: Usar DOMContentLoaded para ejecución inline aplazada
Si necesitas que tu script inline espere hasta que el DOM esté listo, envuelve el código en un event listener de DOMContentLoaded:
<script>
document.addEventListener("DOMContentLoaded", function() {
console.log("DOM is fully parsed");
});
</script>
Esto logra un efecto similar a defer pero es válido para scripts inline.
❌ Inválido: async en un script inline
La misma regla se aplica a async:
<script async>
document.title = "Updated";
</script>
✅ Solucionado
<script async src="update-title.js"></script>
O simplemente elimina async si el script es inline:
<script>
document.title = "Updated";
</script>
Encuentra problemas como este automáticamente
Rocket Validator escanea miles de páginas en segundos, detectando problemas de HTML en todo tu sitio web.
Más información: