Ves al contingut principal

<script> dins html, on?

L'etiqueta <script> per incloure codi JavaScript es pot col·locar principalment en tres llocs dins d'un document HTML: al <head>, just abans de tancar el </body>, o utilitzant els atributs async o defer en una ubicació externa (que canvia el seu comportament de càrrega).

A continuació, s'expliquen les opcions, els seus avantatges i els inconvenients:

1. Dins de l'etiqueta <head>

Col·locar el codi JavaScript dins de la secció <head>...</head> de l'HTML.

Opció Codi Comportament
Estàndard <head><script src="script.js"></script></head> El navegador atura l'anàlisi del HTML per carregar i executar el script abans de carregar qualsevol contingut del <body>.
Amb defer <head><script src="script.js" defer></script></head> El navegador no s'atura, descarrega el script en paral·lel, i l'executa just abans de l'esdeveniment DOMContentLoaded.
Amb async <head><script src="script.js" async></script></head> El navegador no s'atura, descarrega el script en paral·lel, i l'executa immediatament quan acaba la descàrrega, interrompent l'anàlisi del DOM si cal.

Avantatges i Inconvenients (al <head>)

Avantatges Inconvenients
Rendiment amb defer o async: Es comença a descarregar el JS abans, però sense bloquejar la renderització del <body>. Bloqueig de la pàgina (sense defer/async): La pàgina es mostra en blanc fins que el JS ha estat completament carregat i executat.
Ideal per a utilitats: Perfecte per a carregar llibreries que no interactuen amb el DOM. Error d'accés al DOM (sense defer/async): Si el script intenta manipular elements del <body>, fallarà perquè encara no existeixen.
Claritat: Fa evident que el script és necessari per a la càrrega inicial.  

2. Just abans de tancar el </body>

Aquesta és la ubicació més habitual i tradicionalment recomanada per als scripts que interactuen amb el DOM.

Opció Codi Comportament
Estàndard <body>... Contenido ... <script src="script.js"></script></body> El navegador analitza i renderitza tot el HTML del <body>. Quan troba l'etiqueta <script>, l'executa.

Avantatges i Inconvenients (al </body>)

Avantatges Inconvenients
Rendiment (Percebut): El contingut HTML es mostra a l'usuari abans que s'executi el JS, millorant la velocitat percebuda. Retard en la interactivitat: El JS no comença a descarregar-se ni a executar-se fins que el navegador no arriba al final del document.
Accés segur al DOM: Quan s'executa el script, tots els elements HTML ja estan carregats i disponibles. Opció menys neta: Trenca la separació de preocupacions (la part lògica/recursos al <head>) del contingut (<body>).
No cal defer: Simula el comportament de defer de forma nativa per a la interacció amb el DOM.  

3. En mig de <body>

Es pot posar l'etiqueta <script> al mig del <body> d'un document HTML. De fet, tradicionalment, era una pràctica comuna, tot i que té implicacions importants per al rendiment i el comportament de la pàgina.

Comportament i Implicacions

Quan el navegador processa un document HTML, va llegint el codi de dalt a baix. Quan es troba un <script> (sense els atributs async o defer):

  1. S'atura l'anàlisi (Parsing) del HTML: El navegador atura la construcció de l'arbre DOM (Document Object Model) i la renderització del contingut restant del <body>.

  2. Descàrrega i execució: Descarrega el fitxer JavaScript (si és extern) i l'executa completament.

  3. Represa: Un cop finalitzada l'execució del script, el navegador reprèn l'anàlisi del HTML que ve a continuació.

Exemple de Codi

En el següent exemple, el JS s'executarà després que s'hagi carregat el <h1> però abans que el navegador llegeixi i mostri el <p>.

<body>
    <h1>Títol de la Pàgina</h1>  <script>
        console.log("El codi JS s'executa ara mateix.");
        // Aquest script bloqueja la càrrega del <p> següent.
    </script>
    
    <p>Aquest paràgraf es retarda fins que el script anterior s'ha executat.</p> 
</body>

Avantatges

  • Accés a elements carregats: El script pot manipular de manera segura qualsevol element HTML que hagi estat definit abans de la seva ubicació. Això elimina la necessitat d'utilitzar escoltadors d'esdeveniments com DOMContentLoaded per a aquests elements previs.

Inconvenients (Per què s'ha d'evitar)

  • Bloqueig de Renderització: El principal inconvenient és el bloqueig. Si el script és gran o requereix temps per descarregar-se, l'usuari veurà la pàgina "congelada" en el punt on es troba el <script>, retardant la visualització de la resta del contingut. Això és desastrós per al rendiment i l'experiència d'usuari (UX).

  • Accessibilitat Incompleta al DOM: El script només pot accedir als elements que s'han carregat abans d'ell. Si necessita interactuar amb elements que es troben després del seu punt d'inserció, fallarà.

Millors pràctiques

En JavaScript modern, per evitar bloquejos i garantir el millor rendiment, s'han d'utilitzar els següents mètodes:

  1. Al final del <body>: Aquesta és la solució clàssica per assegurar que tot el DOM es carrega abans que s'executi el JS.

  2. Al <head> amb defer: Aquesta és la millor pràctica moderna. Permet la descàrrega asíncrona (sense bloquejar el HTML) i garanteix que l'execució del script es realitza un cop el DOM està completament carregat.

Opció Ubicació Càrrega Execució
Recomanada <head> Paral·lela Després del DOM (en ordre)
Tradicional Final del <body> Bloquejant Després del DOM (en ordre)

En resum, tot i que tècnicament es pot posar un script al mig del <body>, no és aconsellable a menys que tinguis una raó molt específica (i normalment d'herència) per fer-ho. Utilitza defer al <head> o posa el script just abans de </body> per al millor rendiment.

La decisió depèn de la funcionalitat del script:

Tipus de Script Ubicació i Atribut Recomanat
Scripts que manipulen el DOM (p. ex., un carrusel, un botó interactiu) Abans de </body> (sense atributs), o Al <head> amb l'atribut defer. (La millor pràctica moderna és defer).
Scripts d'analítiques o publicitat (que no depenen del DOM i han de carregar-se ràpidament) Al <head> amb l'atribut async.
Scripts que es carrega com a mòdul (ES Modules) Al <head> o al </body> amb type="module". Per defecte, aquests mòduls es comporten com si tinguessin l'atribut defer.