Obrazy i pliki statyczne
Plakat wydarzenia, logo szkoły, ikona — wszystko to są pliki, których Angular nie kompiluje, tylko podaje przeglądarce bez zmian. Trzeba wiedzieć, gdzie je położyć, jak zapisać adres i co zrobić, żeby strona nie skakała podczas wczytywania.
Czego się dziś nauczysz
- Umieścisz obrazek w folderze
publici zapiszesz poprawny adres zaczynający się od/. - Wyjaśnisz, dlaczego pliki z
publicnie przechodzą przez kompilator. - Podasz adres obrazka z pola klasy przez
[src], a opis przez[alt]. - Napiszesz
alt, który opisuje treść obrazu. - Podasz
widthiheight, żeby strona nie przeskakiwała przy wczytywaniu. - Znajdziesz błąd 404 w narzędziach przeglądarki, gdy obrazka brakuje.
- Wstawisz obrazek do karty Bootstrapa i dopasujesz go do szerokości kolumny.
Przygotowanie: lekcje 05 i 06 — umiesz pokazać wartość pola i przekazać ją do właściwości elementu. Przewidywany czas: 45 min z zadaniami.
Obrazki do przykładów to pliki turniej.svg, roboty.svg i druk3d.svg — dostaniesz je od nauczyciela. Możesz też zapisać pod tymi nazwami dowolne własne obrazki (.svg, .png albo .jpg — wtedy zmień rozszerzenie w adresie).
Dlaczego obrazki mają osobny folder
Pliki z folderu src przechodzą przez kompilator: TypeScript zamienia się w JavaScript, szablony w kod. Z obrazkiem nie ma czego kompilować — ma po prostu trafić do przeglądarki taki, jaki jest.
Dlatego istnieje folder public (obok src, nie w nim). Wszystko, co w nim położysz, serwer podaje bez zmian, a ng build kopiuje do gotowej aplikacji. Leży tam już favicon.ico — ikona karty przeglądarki. Ten sam mechanizm obsłuży plik PDF z regulaminem i plik JSON z danymi, który wczytamy w lekcji 36.
klub-gier/
public/
favicon.ico
img/
turniej.svg ← tutaj (folder img utwórz sam)
roboty.svg
druk3d.svg
src/
app/
| Plik w projekcie | Adres w src |
|---|---|
public/img/turniej.svg | /img/turniej.svg |
public/favicon.ico | /favicon.ico |
public/dokumenty/regulamin.pdf | /dokumenty/regulamin.pdf |
Słowa public nie ma w adresie
Folder public jest korzeniem serwera — adres zaczyna się od ukośnika i od razu od tego, co leży w środku. src="public/img/turniej.svg" to najczęstsza pomyłka tej lekcji.
Dwie zasady dobrego obrazka
alt opisuje treść
Tekst alternatywny czyta program dla osób niewidomych, pokazuje go przeglądarka, gdy obrazek się nie wczytał, i bierze pod uwagę wyszukiwarka. „Plakat turnieju retro” niesie informację. „obrazek” nie niesie żadnej. Obrazek czysto ozdobny dostaje pusty alt="" — czytnik go wtedy pominie.
width i height rezerwują miejsce
Przeglądarka, znając wymiary, zostawia puste pole, zanim plik dotrze. Bez tego reszta strony przeskakuje w chwili wczytania obrazka. Liczby w atrybutach to piksele, bez jednostki.
Obrazek dopasowany do kolumny
W siatce i w karcie szerokość wyznacza kolumna, a nie liczba w width. Bootstrap ma na to klasy: img-fluid (obrazek nigdy nie jest szerszy niż rodzic) i card-img-top (obrazek na całą szerokość karty, z zaokrąglonymi górnymi rogami). width i height zostawiasz — przeglądarka liczy z nich proporcje i nadal rezerwuje miejsce.
Gdzie wrzucić obrazek
Utwórz folder public/img i skopiuj do niego trzy obrazki. Adres w szablonie zaczyna się od ukośnika.
import { Component } from '@angular/core';
@Component({
selector: 'app-demo',
imports: [],
templateUrl: './demo.html'
})
export class Demo {
}
<div class="p-3">
<img src="/img/turniej.svg" alt="Plakat turnieju retro" width="220" height="140">
</div>
[ fioletowy plakat „Turniej retro, piątek, sala 12” — 220 × 140 ]
Klasa Demo jest pusta — obrazek ze stałym adresem nie potrzebuje żadnych danych.
Zatrzymaj się
Wpisz w pasku adresu przeglądarki localhost:4200/img/turniej.svg. Zobaczysz sam obrazek — dowód, że plik jest podawany niezależnie od aplikacji.
Adres obrazka z pola klasy
Skoro adres to zwykły tekst, może pochodzić z klasy — a wtedy przydają się nawiasy kwadratowe z lekcji 06.
import { Component } from '@angular/core';
@Component({
selector: 'app-demo',
imports: [],
templateUrl: './demo.html'
})
export class Demo {
readonly plakat = '/img/roboty.svg';
readonly opis = 'Plakat Nocy robotów';
}
<div class="card m-3" style="width: 16rem">
<img [src]="plakat" [alt]="opis" class="card-img-top" width="240" height="150">
<div class="card-body">
<h5 class="card-title">Noc robotów</h5>
</div>
</div>
┌────────────────────┐
│ [plakat robotów] │
│ Noc robotów │
└────────────────────┘
Obrazek jest w karcie, u góry, dzięki klasie card-img-top. Zmień wartość pola plakat na '/img/druk3d.svg' i zapisz.
Zatrzymaj się
Zapis src="{{ plakat }}" też by zadziałał — adres to przecież tekst. Dlaczego mimo to warto przyzwyczaić się do [src]? Przypomnij sobie przycisk z disabled z lekcji 06.
Obrazek, którego nie ma
Zły adres nie zatrzymuje aplikacji i nie daje błędu w terminalu. To dlatego tak łatwo go przeoczyć.
import { Component } from '@angular/core';
@Component({
selector: 'app-demo',
imports: [],
templateUrl: './demo.html'
})
export class Demo {
readonly zly = '/img/nie-ma-takiego.svg';
readonly dobry = '/img/druk3d.svg';
}
<div class="p-3">
<p>Poprawny adres:</p>
<img [src]="dobry" alt="Warsztat druku 3D" width="220" height="140">
<p class="mt-3">Błędny adres — zobacz konsolę (F12):</p>
<img [src]="zly" alt="Tego pliku nie ma" width="220" height="140">
</div>
GET http://localhost:4200/img/nie-ma-takiego.svg 404 (Not Found)
Drugi obrazek pokazuje ikonę uszkodzonego pliku i tekst z alt. W zakładce Network (z filtrem Img) ten plik jest zaznaczony na czerwono ze statusem 404.
Zatrzymaj się
Tekst z alt pojawił się, bo obrazka nie ma. Kto jeszcze korzysta z tego tekstu, gdy obrazek wczytał się poprawnie?
Szerokość, wysokość i przeskakująca strona
Dwa atrybuty, o których początkujący zapominają — a różnicę widać gołym okiem przy wolnym łączu.
import { Component } from '@angular/core';
@Component({
selector: 'app-demo',
imports: [],
templateUrl: './demo.html'
})
export class Demo {
}
<div class="p-3">
<p>Z podanymi wymiarami — miejsce jest zarezerwowane od początku:</p>
<img src="/img/turniej.svg" alt="Turniej retro" width="220" height="140">
<p class="mt-3">Bez wymiarów — tekst pod spodem podskoczy po wczytaniu:</p>
<img src="/img/roboty.svg" alt="Noc robotów">
<p>Ten akapit jest pod obrazkiem.</p>
</div>
1. obrazek: puste miejsce 220 × 140 od początku, potem plakat
2. obrazek: brak miejsca — po wczytaniu akapit pod nim „zjeżdża” w dół
W narzędziach przeglądarki (F12 → Network) zaznacz Disable cache, włącz Slow 4G i odśwież stronę. Pierwszy obrazek ma zarezerwowane miejsce, drugi je sobie „wywalcza” i przesuwa tekst. Na koniec przywróć No throttling.
Zatrzymaj się
Drugi obrazek po wczytaniu jest dwa razy większy niż pierwszy. Skąd przeglądarka wzięła jego rozmiar, skoro nie podałeś width i height?
Zestawienie elementów
| Element | Znaczenie | Uwagi |
|---|---|---|
folder public | pliki podawane bez zmian | Obok src; jest korzeniem adresów. |
src="/img/plik.svg" | stały adres obrazka | Od ukośnika, bez słowa public. |
[src]="pole" | adres z pola klasy | Można sklejać: [src]="'/img/' + nazwa". |
alt / [alt] | opis treści obrazu | Ozdobnik: alt="". |
width, height | wymiary w pikselach | Rezerwują miejsce przed wczytaniem. |
img-fluid | obrazek nie szerszy niż rodzic | Do obrazków w kolumnach siatki. |
card-img-top | obrazek na górze karty | Pierwszy element w card, przed card-body. |
rounded, rounded-circle | zaokrąglone rogi, koło | Bootstrap; np. zdjęcie profilowe. |
| F12 → Network → Img | lista pobranych obrazków | Status 404 = brak pliku. |
NgOptimizedImage | dyrektywa do obrazków w dużych projektach | Nie potrzebujemy jej w kursie; warto znać nazwę. |
Zanim utkniesz
| Zapis | Problem |
|---|---|
src="public/img/a.svg" | 404. Słowa public nie ma w adresie — ten folder jest korzeniem. |
Obrazek w src/img albo src/assets | 404. Pliki z src nie są podawane przeglądarce. Do Angulara 17 domyślny był folder src/assets; od wersji 18 jest public. |
Plik skopiowany do public, a nadal 404 | Sprawdź dokładnie nazwę i rozszerzenie (.svg czy .png). Na serwerze szkolnym wielkość liter ma znaczenie: Turniej.svg to inny plik niż turniej.svg. |
Brak atrybutu alt | Kompilator nie protestuje, ale czytnik ekranu nie ma czego przeczytać, a przy 404 nie widać, co miało tam być. |
alt="obrazek" | Tekst bez treści. alt opisuje, co przedstawia obraz. |
[src]="/img/a.svg" | Błąd składni: w nawiasach kwadratowych stoi kod. Stały adres bez nawiasów: src="/img/a.svg". |
width="220px" | Atrybut przyjmuje samą liczbę pikseli, bez jednostki. |
Zadania
Pokaż trzy plakaty obok siebie w siatce Bootstrapa (na wąskim ekranie jeden pod drugim). Każdy obrazek ma mieć sensowny alt, wymiary i klasę img-fluid.
Kryterium sukcesu: trzy obrazki stoją w rzędzie, mieszczą się w kolumnach, a po zwężeniu okna układają się jeden pod drugim.
Podpowiedź
Siatkę masz w lekcji 03: container → row g-3 → trzy razy col-12 col-md-4.
Dodaj do public/img logo szkoły (dowolny obrazek) i wstaw je do komponentu naglowek z lekcji 04, przed nazwą klubu, w wysokości 40 pikseli. Zmień też ikonę karty przeglądarki, podmieniając plik public/favicon.ico.
Kryterium sukcesu: logo stoi w ciemnym pasku obok nazwy, a karta przeglądarki pokazuje nową ikonę (czasem trzeba odświeżyć z Ctrl+F5).
Podpowiedź
<img src="/img/logo.png" alt="Logo ZSMI" height="40" class="me-2">. Ikona musi być w formacie .ico albo zmień wpis w index.html.
Zrób komponent karta-plakat z obrazkiem u góry karty, tytułem i przyciskiem „Szczegóły”. Adres obrazka, opis do alt i tytuł trzymaj w trzech polach klasy.
Kryterium sukcesu: zmiana pola z adresem w pliku .ts zmienia obrazek, a zmiana tytułu — napis; alt w narzędziach przeglądarki (Elements) ma wartość z pola.
Podpowiedź
[src], [alt] i {{ }} w tytule; obrazek z klasą card-img-top stoi przed card-body.
Zrób galerię z trzech zdjęć z podpisami. Każde zdjęcie umieść w znaczniku <figure> z podpisem <figcaption>. Podpisy i opisy alt mają się różnić: podpis jest dla wszystkich („Finał turnieju 2026”), alt opisuje, co widać na obrazku („Dwie osoby przy automacie do gier”).
Kryterium sukcesu: pod każdym zdjęciem jest podpis, zdjęcia mają zaokrąglone rogi, a każde alt opisuje treść obrazu.
Podpowiedź
Klasy Bootstrapa: figure, figure-img img-fluid rounded, figure-caption.
Wstaw na stronę pięć obrazków z adresami: /img/turniej.svg, img/turniej.svg, public/img/turniej.svg, /images/turniej.svg, /img/turniej. Zanim zapiszesz, przewidź w zeszycie, które się wczytają. Potem sprawdź w zakładce Network (filtr Img) status każdego z nich i zapisz tabelkę: adres → przewidywanie → status → wyjaśnienie.
Kryterium sukcesu: tabelka ma pięć wierszy z prawdziwymi statusami, a dla każdego obrazka, który się nie wczytał, umiesz wskazać przyczynę.
Podpowiedź
Adres bez ukośnika na początku liczony jest od <base href="/"> z index.html — sprawdź, co z tego wynika. Uwaga na adres bez rozszerzenia: serwer może odpowiedzieć statusem 200, ale zamiast obrazka odeśle stronę aplikacji — sprawdź kolumnę Type (document zamiast svg+xml).
Zrób kartę wydarzenia z polem kategoria, które przyjmuje jedną z wartości: 'turniej', 'roboty', 'druk3d'. Adres plakatu ma powstać z kategorii (/img/ + kategoria + .svg), a opis alt i tytuł — z metody tytul(), która dla każdej kategorii zwraca pełną nazwę wydarzenia. Dodatkowo dla kategorii 'roboty' karta ma mieć ciemne tło i biały tekst.
Kryterium sukcesu: zmiana jednego pola kategoria zmienia plakat, tytuł, alt i — dla robotów — kolory karty.
Podpowiedź
[src]="'/img/' + kategoria + '.svg'". Kolory: [class.text-bg-dark]="kategoria === 'roboty'" na elemencie card.
Co trzeba zapamiętać
- Pliki statyczne leżą w
public, oboksrc; serwer podaje je bez kompilowania. - Adres zaczyna się od
/i nie zawiera słowapublic. - Adres z pola klasy przekazujesz przez
[src]; da się go też skleić z kilku części. - Błędny adres nie zatrzymuje aplikacji — 404 widać tylko w narzędziach przeglądarki.
altopisuje treść obrazu; ozdobnik dostajealt="".widthiheightrezerwują miejsce;img-fluiddopasowuje obrazek do kolumny.- W karcie obrazek z
card-img-topstoi przedcard-body.
Sprawdź się: plik leży w public/img/logo.png. Jaki adres wpiszesz w src i dlaczego nie ten z folderem public?
Dokumentacja: angular.dev — struktura projektu (folder public).