Kurs HTML

Lekcja 11.6: Elementy <script> i <noscript>

Strona główna > Rozdział 11: Zaawansowane funkcje HTML > Elementy <script> i <noscript>

Dodawanie dynamicznego zachowania: JavaScript

Sam HTML definiuje strukturę i treść strony, a CSS odpowiada za jej wygląd. Aby dodać interaktywność, dynamiczne aktualizacje treści, walidację formularzy po stronie klienta i wiele innych zaawansowanych funkcji, potrzebujemy języka skryptowego. Najpopularniejszym i standardowym językiem skryptowym dla stron internetowych jest JavaScript.

Element <script> służy do osadzania lub linkowania kodu JavaScript w dokumencie HTML.

Osadzanie skryptów bezpośrednio w HTML

Kod JavaScript można umieścić bezpośrednio pomiędzy znacznikami <script> i </script>. Taki skrypt nazywamy skryptem wbudowanym (inline script).

<script>
  // Prosty kod JavaScript
  console.log("Witaj, świecie z wbudowanego skryptu!");
  alert("To jest alert z JavaScript!");
</script>

Skrypty wbudowane są przydatne do małych fragmentów kodu specyficznych dla danej strony, ale dla większych aplikacji preferuje się oddzielne pliki.

Linkowanie zewnętrznych plików JavaScript

Najczęstszą i zalecaną praktyką jest umieszczanie kodu JavaScript w osobnych plikach z rozszerzeniem .js i linkowanie ich do dokumentu HTML za pomocą atrybutu src w znaczniku <script>.

<!-- Linkowanie do pliku script.js w tym samym katalogu -->
<script src="script.js"></script>

<!-- Linkowanie do pliku w podkatalogu js -->
<script src="js/main.js"></script>

<!-- Linkowanie do skryptu na innym serwerze (np. CDN) -->
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>

Ważne: Jeśli znacznik <script> ma atrybut src, jego zawartość (pomiędzy <script> a </script>) jest ignorowana. Nie można jednocześnie linkować zewnętrznego pliku i umieszczać kodu wewnątrz tego samego znacznika.

Zalety zewnętrznych plików .js:

Gdzie umieszczać znacznik <script>?

Znacznik <script> można umieścić:

  1. W sekcji <head>: Skrypty umieszczone w <head> są zazwyczaj pobierane i wykonywane przed rozpoczęciem renderowania treści <body>. Może to spowolnić początkowe wyświetlanie strony, ponieważ przeglądarka musi poczekać na zakończenie skryptu. Jest to jednak czasem konieczne, jeśli skrypt musi być dostępny od samego początku lub modyfikuje sposób renderowania strony.
  2. W sekcji <body>: Najczęściej znaczniki <script> (szczególnie te linkujące do zewnętrznych plików) umieszcza się tuż przed zamykającym znacznikiem </body>. Dzięki temu strona HTML jest najpierw parsowana i renderowana, a dopiero potem pobierane i wykonywane są skrypty. Zapewnia to szybsze wyświetlenie treści użytkownikowi i gwarantuje, że skrypt będzie miał dostęp do wszystkich elementów DOM strony, gdy zacznie działać.
<!DOCTYPE html>
<html>
<head>
  <title>Pozycja skryptu</title>
  <!-- Skrypty w head (mogą blokować renderowanie) -->
  <script src="library.js"></script>
</head>
<body>
  <h1>Treść strony</h1>
  <p>...

<!-- Skrypty na końcu body (zalecane) --> <script src="main.js"></script> </body> </html>

Atrybuty `async` i `defer`

Dla zewnętrznych skryptów (tych z atrybutem src) istnieją dwa atrybuty logiczne, które modyfikują sposób ich pobierania i wykonywania, szczególnie gdy są umieszczone w <head>:

Jeśli skrypt nie ma ani async, ani defer, jest pobierany i wykonywany synchronicznie, blokując parsowanie HTML.

Zarówno async, jak i defer działają tylko dla skryptów zewnętrznych (z atrybutem src).

Atrybut `type`

Atrybut type określa typ MIME skryptu. Dla klasycznego JavaScriptu wartością domyślną i standardową jest text/javascript. W HTML5 można ten atrybut pominąć, jeśli skrypt jest standardowym JavaScriptem.

<!-- Te dwa zapisy są równoważne -->
<script type="text/javascript" src="script.js"></script>
<script src="script.js"></script>

Inną ważną wartością dla type jest module, która wskazuje, że skrypt jest modułem JavaScript (ES Module). Moduły mają inne zasady dotyczące zasięgu zmiennych i importowania/eksportowania funkcjonalności. Skrypty typu module domyślnie zachowują się jak te z atrybutem defer.

<script type="module" src="app.js"></script>

Element <noscript>

Element <noscript> służy do dostarczenia alternatywnej treści dla użytkowników, których przeglądarki nie obsługują JavaScriptu lub mają wyłączoną jego obsługę.

Zawartość elementu <noscript> jest wyświetlana tylko wtedy, gdy skrypty są niedostępne. Jeśli JavaScript jest włączony, przeglądarka ignoruje zawartość <noscript>.

<body>
  <div id="dynamic-content">
    <!-- Treść ładowana przez JavaScript -->
  </div>
  
  <noscript>
    <p style="color: red; font-weight: bold;">
      Twoja przeglądarka nie obsługuje JavaScriptu lub ma go wyłączonego. 
      Niektóre funkcje tej strony mogą nie działać poprawnie.
      <a href="/wersja-bez-js">Przejdź do wersji strony bez JavaScriptu.</a>
    </p>
  </noscript>
  
  <script src="app.js"></script>
</body>

<noscript> może zawierać dowolne elementy HTML, które są dozwolone w miejscu jego użycia (w <head> można umieszczać tylko <link>, <style>, <meta> wewnątrz <noscript>).

Zadanie praktyczne (z rozwiązaniem)

Zadanie: Utwórz plik HTML. W sekcji <body> umieść przycisk z id="test-btn". Utwórz zewnętrzny plik alert.js, który zawiera kod dodający nasłuchiwanie na kliknięcie tego przycisku i wyświetlający alert "Kliknięto przycisk!". Połącz plik alert.js z HTML za pomocą znacznika <script> umieszczonego przed końcem <body>. Dodaj również element <noscript> z informacją dla użytkowników bez JavaScript.

Krok 1: Utwórz plik `alert.js`

document.addEventListener('DOMContentLoaded', function() {
  const przycisk = document.getElementById('test-btn');
  
  if (przycisk) {
    przycisk.addEventListener('click', function() {
      alert('Kliknięto przycisk!');
    });
  } else {
    console.error('Nie znaleziono przycisku o ID: test-btn');
  }
});

Używamy DOMContentLoaded, aby upewnić się, że DOM jest gotowy, zanim spróbujemy znaleźć przycisk. Jest to dobra praktyka, chociaż przy umieszczeniu skryptu na końcu body, DOM zazwyczaj jest już gotowy.

Krok 2: Utwórz plik HTML (`index.html`)

<!DOCTYPE html>
<html lang="pl">
<head>
  <meta charset="UTF-8">
  <title>Test Skryptu</title>
</head>
<body>

<h1>Testowanie JavaScript</h1>

<button id="test-btn">Kliknij mnie</button>

<noscript>
  <p style="color: red;">JavaScript jest wyłączony. Przycisk nie będzie działał interaktywnie.</p>
</noscript>

<!-- Linkowanie skryptu na końcu body -->
<script src="alert.js"></script>

</body>
</html>

Po otwarciu index.html w przeglądarce z włączonym JavaScriptem, kliknięcie przycisku powinno wywołać alert. Jeśli JavaScript jest wyłączony, zamiast tego pojawi się komunikat z elementu <noscript>.

Dodatkowe zadania do samodzielnego wykonania:

  1. Przenieś znacznik <script src="alert.js"></script> do sekcji <head>. Czy skrypt nadal działa poprawnie? Dlaczego (lub dlaczego nie)? Spróbuj dodać atrybut defer. Czy to pomoże?
  2. Utwórz drugi plik JavaScript (np. log.js) z prostym console.log("Drugi skrypt załadowany");. Dodaj oba skrypty (alert.js i log.js) do <head> z atrybutem async. Sprawdź w konsoli, w jakiej kolejności się wykonują (może być różna przy każdym odświeżeniu).
  3. Zmodyfikuj treść w elemencie <noscript>, aby zawierała link do strony wyjaśniającej, jak włączyć JavaScript w popularnych przeglądarkach.

Najczęściej zadawane pytania

Do czego służy znacznik <script>?

Do osadzania kodu JavaScript bezpośrednio w dokumencie HTML lub do linkowania zewnętrznych plików JavaScript (.js) za pomocą atrybutu `src`.

Gdzie najlepiej umieszczać znaczniki <script>?

Zazwyczaj zaleca się umieszczanie ich tuż przed zamykającym znacznikiem </body>, aby nie blokować renderowania strony. Alternatywnie, można je umieścić w <head> z atrybutem `defer`.

Czym różnią się `async` i `defer`?

Oba pobierają skrypt asynchronicznie. `async` wykonuje skrypt natychmiast po pobraniu (kolejność niegwarantowana), potencjalnie blokując parser. `defer` wykonuje skrypt po sparsowaniu HTML, zachowując kolejność deklaracji.

Czy muszę używać `type="text/javascript"`?

W HTML5 dla standardowego JavaScriptu ten atrybut jest domyślny i można go pominąć. Należy go użyć, jeśli skrypt jest innego typu, np. modułem (`type="module"`).

Co robi element <noscript>?

Dostarcza alternatywną treść HTML, która jest wyświetlana tylko wtedy, gdy przeglądarka użytkownika nie obsługuje JavaScriptu lub ma go wyłączonego.