JavaScript en el Head vs Footer: cómo afecta a los Core Web Vitals

Por qué defer en el head es la mejor práctica moderna, y cuándo la ubicación en el footer todavía tiene sentido

Arjen Karel Core Web Vitals Consultant
Arjen Karel - linkedin
Last update: 2026-03-03

La respuesta corta: defer en el head

Última revisión por Arjen Karel en marzo 2026

El consejo clásico era poner JavaScript en el footer. Ese consejo está obsoleto. Con async y defer soportados en todos los navegadores, el mejor lugar para la mayoría de los scripts es en el <head> con un atributo defer.

La razón se reduce al preload scanner: tu navegador descubre los scripts del head inmediatamente y comienza a descargarlos en paralelo con el análisis del HTML. Los scripts del footer se descubren más tarde, lo que significa un inicio de descarga posterior. El resultado es el mismo comportamiento no bloqueante, pero con un descubrimiento de recursos más rápido.

Según el Web Almanac 2025, el 85% de las páginas aún no pasan la auditoría de recursos que bloquean el renderizado. Es un número enorme. Mientras tanto, el Total Blocking Time en móvil aumentó un 58% interanual hasta una mediana de 1.916 ms. JavaScript se está volviendo más pesado, no más ligero. Optimizar la ubicación de tus scripts es una de las cosas más fáciles que puedes hacer para mejorar tu First Contentful Paint y tu Largest Contentful Paint.

Cómo funciona el preload scanner

El preload scanner es un segundo analizador HTML que se ejecuta por delante del analizador principal. Escanea rápidamente el HTML sin procesar y comienza a obtener recursos críticos (imágenes, CSS, JavaScript) antes de que el analizador principal los alcance. El preload scanner obtiene los recursos aproximadamente en el orden en que los descubre.

Aquí es donde la ubicación de los scripts importa. Un script en el <head> se descubre casi inmediatamente. Un script al final del <body> se descubre más tarde, especialmente en documentos HTML grandes. Ese retraso puede costarte cientos de milisegundos en una conexión móvil.

Los scripts inyectados dinámicamente (creados mediante JavaScript) son completamente invisibles para el preload scanner. El scanner solo descubre recursos que existen en el marcado HTML devuelto por el servidor. Por eso diferir JavaScript mediante atributos HTML es casi siempre mejor que inyectar scripts con código.

JavaScript en el head

Colocar JavaScript en el <head> de la página le da el descubrimiento más temprano posible por parte del preload scanner.

Ventajas

  1. Descubrimiento temprano: El preload scanner encuentra los scripts del head antes de cualquier contenido del body. La descarga comienza lo antes posible.
  2. Ejecución más temprana: Los scripts en el head (con defer) se ejecutan antes que los scripts descubiertos más tarde en el documento. Para una comparación detallada, consulta defer vs async JavaScript y los Core Web Vitals.
  3. Separación del código: Mantener las referencias de scripts en el <head> las separa del marcado de contenido, haciendo el HTML más fácil de mantener.

Desventajas

  1. Bloqueo del renderizado (sin defer o async): Un simple <script> en el head bloquea el análisis del HTML hasta que el script se descarga y ejecuta. Esto destruye tu First Contentful Paint. Usa siempre defer o async en scripts externos en el head para evitar esto.
  2. Competencia por el ancho de banda: Los scripts del head de alta prioridad compiten por el ancho de banda con tu CSS, fuentes e imagen LCP. En conexiones lentas, esto puede hacer que tu Largest Contentful Paint supere el umbral de 2,5 segundos.

Cuándo usar la ubicación en el head

Usa el <head> para scripts que son críticos para la experiencia de la página: tu menú, aviso de cookies, slider o cualquier script que afecte lo que el visitante ve por encima de la línea de flotación. Añade defer (o async si el orden de ejecución no importa) para prevenir el bloqueo del renderizado. Las bibliotecas de detección de funcionalidades también pertenecen al head, ya que necesitan ejecutarse antes de que el body sea analizado.

JavaScript en el footer

Colocar JavaScript justo antes de la etiqueta de cierre </body> fue el consejo estándar de rendimiento durante años. La idea: dejar que el HTML se renderice primero, descargar los scripts después.

Ventajas

  1. No bloqueante por defecto: Los scripts del footer no bloquean el renderizado inicial porque el HTML por encima de ellos ya ha sido analizado.
  2. Menor competencia por el ancho de banda: Para cuando el navegador alcanza los scripts del footer, tu CSS, fuentes e imagen LCP ya han comenzado a descargarse.

Desventajas

  1. Descubrimiento tardío: El preload scanner encuentra los scripts del footer más tarde que los scripts del head. En una página grande, esto significa un inicio de descarga y una ejecución más tardíos.
  2. Patrón obsoleto: <script defer> en el <head> logra el mismo comportamiento no bloqueante con un descubrimiento más temprano. La ubicación en el footer era la solución alternativa antes de que defer tuviera soporte universal en los navegadores. Esa era terminó.

Cuándo la ubicación en el footer todavía tiene sentido

La ubicación en el footer puede tener sentido para scripts que realmente no quieres que compitan por el ancho de banda durante la carga inicial de la página: analytics, herramientas de tests A/B o widgets sociales. Pero incluso para estos, defer en el head suele ser la mejor opción debido al descubrimiento más temprano por parte del preload scanner.

Atributos modernos de script

Más allá de async y defer, hay dos atributos más que vale la pena conocer:

type="module": Los scripts de tipo module son diferidos por defecto. No necesitas añadir defer a un script module porque ya se comporta así. Añadir async a un script module anula el comportamiento defer por defecto y hace que se ejecute tan pronto como termine de descargarse.

fetchpriority: Por defecto, los scripts async y defer obtienen prioridad de red baja. Añadir fetchpriority="high" a un script async te da una descarga no bloqueante con prioridad alta. Esta es la combinación ideal para scripts que son críticos para la experiencia del usuario pero que no deben bloquear el renderizado. Para el panorama completo, consulta la guía de priorización de recursos y los niveles de prioridad de JavaScript.

Una estrategia práctica de ubicación de scripts

No todos los scripts merecen el mismo tratamiento. Utilizo un enfoque de cuatro niveles:

  1. Scripts críticos para el renderizado: Scripts que afectan el diseño visible de la página (menú, slider, interfaz por encima de la línea de flotación). Colócalos en el <head> sin defer si deben ejecutarse antes del primer pintado. Mantenlos lo más pequeños posible porque bloquean el renderizado y perjudicarán tus Core Web Vitals.
  2. Scripts importantes: Scripts críticos para la conversión o la interacción (formularios, navegación, consentimiento de cookies). Colócalos en el <head> con defer o async.
  3. Scripts normales: Scripts que no afectan el primer renderizado de la página (carruseles, modales, pestañas). Colócalos en el <head> con defer.
  4. Scripts prescindibles: Scripts de los que podrías prescindir si fuera absolutamente necesario (analytics, widgets de chat, botones de compartir en redes sociales). Cárgalos después de que la página haya terminado de renderizarse, usando el evento load o requestIdleCallback. Consulta 16 métodos para diferir JavaScript para las técnicas. Si tienes mucho JavaScript no utilizado en esta categoría, consulta cómo reducir el JavaScript no utilizado.

Los eventos DOMContentLoaded y load te permiten controlar el momento de ejecución independientemente de dónde esté ubicado el script en el HTML. Esto es útil para asegurar que tu código se ejecute en el momento adecuado.

Ejemplos de código

Ejemplo 1: JavaScript en el head (bloqueante del renderizado)

<!DOCTYPE html>
<html>
<head>
    <title>JavaScript in the Head Example</title>
    <script>
        function showMessage() {
            alert("Hello from JavaScript in the head!");
        }
    </script>
    <!-- This script blocks rendering -->
    <script src="script.js"></script>
</head>
<body>
    <button onclick="showMessage()">Click Me</button>
</body>
</html>

En este ejemplo, script.js en el <head> bloquea el renderizado. El navegador no mostrará el botón hasta que el script se haya descargado y ejecutado. Añade defer a la etiqueta script para solucionar esto.

Ejemplo 2: JavaScript en el footer

<!DOCTYPE html>
<html>
<head>
    <title>JavaScript in the Footer Example</title>
</head>
<body>
    <button onclick="showMessage()">Click Me</button>
    <!-- Script at the end of the body -->
    <script src="script.js"></script>
    <script>
        function showMessage() {
            alert("Hello from JavaScript in the footer!");
        }
    </script>
</body>
</html>

Aquí, script.js se carga después del contenido HTML, por lo que no bloquea el renderizado. Pero el preload scanner lo descubre más tarde que si estuviera en el head. Usar <script defer src="script.js"></script> en el <head> te da el mismo comportamiento no bloqueante con un descubrimiento de descarga más temprano.

Ejemplo 3: Uso de escuchadores de eventos

<!DOCTYPE html>
<html>
<head>
    <title>Event Listener Example</title>
    <script>
        window.addEventListener('load', function() {
            console.log("Page is fully loaded.");
        });
    </script>
</head>
<body>
    <!-- Page content -->
</body>
</html>

El escuchador de eventos load asegura que el código dentro del callback solo se ejecute después de que la página se haya cargado completamente, independientemente de dónde esté ubicado el script. Esto es útil para la inicialización no crítica que debe esperar hasta que todo lo demás esté listo.

Verifica tus cambios

Después de mover los scripts del footer a defer en el <head>, verifica el impacto con Real User Monitoring. Tu FCP y tu LCP deberían mejorar. En los sitios monitorizados por CoreDash, los orígenes que usan defer para la mayoría de sus scripts tienen un FCP mediano un 18% más rápido que los orígenes que aún dependen de la ubicación en el footer.

About the author

Arjen Karel is a web performance consultant and the creator of CoreDash, a Real User Monitoring platform that tracks Core Web Vitals data across hundreds of sites. He also built the Core Web Vitals Visualizer Chrome extension. He has helped clients achieve passing Core Web Vitals scores on over 925,000 mobile URLs.

Performance degrades unless you guard it.

I do not just fix the metrics. I set up the monitoring, the budgets, and the processes so your team keeps them green after I leave.

Start the Engagement
JavaScript en el Head vs Footer: cómo afecta a los Core Web VitalsCore Web Vitals JavaScript en el Head vs Footer: cómo afecta a los Core Web Vitals