Sobre este problema HTML
Os atributos booleanos defer e async controlam como e quando um script externo é descarregado e executado em relação à análise HTML. Estes atributos existem especificamente para otimizar o carregamento de recursos externos. Um bloco <script> inline (um sem atributo src) não precisa de ser “descarregado” — o seu conteúdo já está incorporado no documento HTML. Por isso, o atributo defer não tem qualquer efeito significativo em scripts inline, e a especificação HTML proíbe explicitamente esta combinação.
De acordo com o padrão HTML living da WHATWG, o atributo defer “não deve ser especificado se o atributo src não estiver presente.” Os navegadores simplesmente ignoram o atributo defer em scripts inline, o que significa que o script irá executar sincronamente como se defer nunca tivesse sido adicionado. Isto pode induzir os programadores em erro, fazendo-os pensar que a execução do script inline está a ser diferida quando não está, causando potencialmente bugs de temporização subtis que são difíceis de diagnosticar.
A mesma regra aplica-se ao atributo async — também requer a presença de um atributo src para ser válido.
Como corrigir
Tem duas opções dependendo da sua situação:
-
Se o script deve ser diferido, mova o código inline para um ficheiro
.jsexterno e faça referência ao mesmo com o atributosrcjuntamente comdefer. -
Se o script deve permanecer inline, remova completamente o atributo
defer. Se precisar de execução diferida para código inline, considere colocar o elemento<script>no final do<body>, ou useDOMContentLoadedpara esperar que o documento termine de ser analisado.
Exemplos
❌ Inválido: defer num script inline
<script defer>
console.log("hello");
</script>
Isto gera o erro de validação porque defer está presente sem um atributo src correspondente.
✅ Opção de correção 1: adicionar um atributo src
Mova o JavaScript para um ficheiro externo (por exemplo, app.js) e faça referência ao mesmo:
<script defer src="app.js"></script>
O navegador irá descarregar app.js em paralelo com a análise HTML e executá-lo apenas depois de o documento ser completamente analisado.
✅ Opção de correção 2: remover defer do script inline
Se o script deve permanecer inline, simplesmente remova o atributo defer:
<script>
console.log("hello");
</script>
✅ Opção de correção 3: usar DOMContentLoaded para execução inline diferida
Se precisar que o seu script inline espere até que o DOM esteja pronto, envolva o código num event listener DOMContentLoaded:
<script>
document.addEventListener("DOMContentLoaded", function() {
console.log("DOM is fully parsed");
});
</script>
Isto consegue um efeito semelhante ao defer mas é válido para scripts inline.
❌ Inválido: async num script inline
A mesma regra aplica-se ao async:
<script async>
document.title = "Updated";
</script>
✅ Corrigido
<script async src="update-title.js"></script>
Ou simplesmente remova async se o script for inline:
<script>
document.title = "Updated";
</script>
Encontre problemas como este automaticamente
O Rocket Validator analisa milhares de páginas em segundos, detetando problemas HTML em todo o seu site.
Saiba mais: