Strona z gotowych klocków
Bootstrap to gotowy arkusz stylów i trochę JavaScriptu. Zamiast pisać CSS, dopisujesz do znaczników HTML klasy o znanych nazwach: container, row, col-md-4, btn btn-primary. Bootstrap ma już dla nich reguły, więc strona od razu dostaje siatkę kolumn, odstępy, kolory i komponenty takie jak menu, karty czy formularze.
Stronę powyżej zbudowano bez ani jednej linijki własnego CSS. Przełącz szerokość okna: przy wąskim ekranie kolumny same układają się jedna pod drugą, a menu chowa się pod przyciskiem. To nazywa się układem responsywnym i jest główną siłą Bootstrapa.
Jak korzystać z kursu
- Lekcje idą po kolei: najpierw podłączenie i siatka, potem klasy pomocnicze (odstępy, kolory, flex), komponenty i projekt całej strony. Lekcja „Bootstrap w React” pokazuje, jak użyć tego wszystkiego w aplikacji React na INF.04.
- W lekcjach są dema z przełącznikami. Wybierz klasę z listy i zobacz, co zmienia na stronie. Przyciski nad podglądem zmieniają szerokość okna.
- Każda lekcja ma ćwiczenie. Piszesz HTML z klasami Bootstrapa, podgląd odświeża się w trakcie pisania, a „Sprawdź” mierzy stronę przy kilku szerokościach okna.
- Postęp i twoje szkice zapisują się w tej przeglądarce.
Podłączenie i pierwsze klasy
Bootstrap to dwa pliki: arkusz stylów bootstrap.min.css i skrypt bootstrap.bundle.min.js. Arkusz wystarcza do siatki, kolorów, odstępów i wyglądu komponentów. Skrypt jest potrzebny tylko elementom, które reagują na kliknięcie: rozwijanemu menu, oknom modalnym, karuzeli.
Najprościej podłączyć oba pliki z serwera CDN, czyli z sieci, bez pobierania czegokolwiek:
<!doctype html> <html lang="pl"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Moja strona</title> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css"> </head> <body> <h1 class="text-primary">Witaj</h1> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script> </body> </html>
- Arkusz w
head, żeby strona od razu wyświetliła się ze stylami. - Skrypt na końcu
body, gdy elementy strony już istnieją. - Znacznik
meta name="viewport"jest obowiązkowy. Bez niego telefon udaje szeroki ekran komputera, pomniejsza całą stronę i układ responsywny nie działa. - Bez internetu (np. na egzaminie) pobierz oba pliki i podłącz je ścieżką lokalną:
href="css/bootstrap.min.css".
Klasy zamiast reguł CSS
W Bootstrapie prawie nie piszesz CSS. Wygląd elementu wybierasz klasą. Element może mieć wiele klas naraz, oddzielonych spacjami, a ich kolejność w atrybucie nie ma znaczenia.
button {
background: #0d6efd;
color: white;
border: 0;
padding: 6px 12px;
border-radius: 6px;
}<button class="btn btn-primary"> Zapisz </button>
Bootstrap od razu zmienia też wygląd zwykłych znaczników: czcionkę, marginesy nagłówków i akapitów, odnośniki. Ten zestaw domyślnych stylów nazywa się Reboot.
class="btn-primary" bez btn nie zrobi przycisku, a literówka btn-primay po prostu nic nie zmieni. Przeglądarka nie zgłasza błędu przy nieznanej klasie.Kontenery i punkty przerwania
Treść strony w Bootstrapie leży w kontenerze. Kontener wyśrodkowuje zawartość, dodaje odstępy po bokach i ogranicza szerokość tak, żeby na szerokim monitorze tekst nie rozlewał się na całe okno.
| Klasa | Szerokość |
|---|---|
container | Stała szerokość, zmieniana skokowo w punktach przerwania. Na środku okna. |
container-fluid | Zawsze 100% szerokości okna. |
container-md | 100% na małych ekranach, a od punktu md jak container. |
Punkty przerwania
Punkt przerwania (ang. breakpoint) to szerokość okna, od której zmienia się układ. Bootstrap ma ich sześć i każdy ma skrót. Te skróty zobaczysz w dziesiątkach klas: col-md-6, d-lg-none, navbar-expand-md.
| Skrót | Szerokość okna | Szerokość .container | Typowe urządzenie |
|---|---|---|---|
| (brak) | poniżej 576px | 100% | telefon pionowo |
sm | od 576px | 540px | telefon poziomo |
md | od 768px | 720px | tablet |
lg | od 992px | 960px | laptop |
xl | od 1200px | 1140px | monitor |
xxl | od 1400px | 1320px | duży monitor |
Zasada, którą trzeba zapamiętać: klasa z punktem przerwania działa od tej szerokości w górę. col-md-6 znaczy „pół szerokości od 768px wzwyż”, a poniżej element zachowuje się tak, jak mówią klasy bez skrótu. Bootstrap projektuje się więc od telefonu (ang. mobile first): najpierw układ na wąski ekran, potem zmiany dla szerszych.
div.container.<header class="bg-primary text-white py-4">
<div class="container">
<h1>Sklep rowerowy</h1>
</div>
</header>
Wiersze i kolumny
Siatka Bootstrapa dzieli szerokość wiersza na 12 równych części. Kolumna mówi, ile z tych 12 części zajmuje. Struktura jest zawsze ta sama: kontener → wiersz → kolumny.
<div class="container">
<div class="row">
<div class="col-8">Treść (8 z 12)</div>
<div class="col-4">Panel (4 z 12)</div>
</div>
</div>
| Klasa | Co robi |
|---|---|
row | Wiersz siatki. Pod spodem to display: flex z zawijaniem. Kolumny muszą być jego bezpośrednimi dziećmi. |
col | Kolumna bez liczby: wszystkie takie kolumny w wierszu dzielą miejsce po równo, ile by ich nie było. |
col-4 | Kolumna na 4 z 12 części, czyli jedną trzecią wiersza. |
col-auto | Kolumna tak szeroka jak jej zawartość. |
Gdy suma liczb w wierszu przekracza 12, nadmiarowa kolumna przechodzi do następnej linii. To nie błąd, tylko zamierzone zachowanie: tak powstają galerie, w których kafelki same zawijają się do nowych rzędów.
col-6 bez rodzica row nie stanie obok sąsiada, bo to row jest kontenerem flex. Do kolumny wkładaj treść, a jeśli potrzebujesz kolumn w kolumnie, wstaw do niej nowy row.Siatka responsywna
Klasy kolumn można łączyć z punktami przerwania. Jeden element dostaje kilka klas i każda obowiązuje od swojej szerokości w górę:
<div class="row"> <div class="col-12 col-md-6 col-lg-3">Produkt 1</div> <div class="col-12 col-md-6 col-lg-3">Produkt 2</div> <div class="col-12 col-md-6 col-lg-3">Produkt 3</div> <div class="col-12 col-md-6 col-lg-3">Produkt 4</div> </div>
- poniżej 768px działa
col-12: każdy produkt na całą szerokość, jeden pod drugim, - od 768px działa
col-md-6: dwa produkty w rzędzie, - od 992px działa
col-lg-3: cztery w rzędzie.
col-12 można pominąć. Element bez żadnej klasy kolumny dla małych ekranów i tak zajmuje cały wiersz.
Liczba kolumn ustawiana na wierszu
Gdy wszystkie kafelki są takie same, wygodniej powiedzieć wierszowi, ile ma ich mieścić w rzędzie. Robią to klasy row-cols-*. Kafelki dostają wtedy samo col.
<div class="row row-cols-1 row-cols-md-2 row-cols-lg-4"> <div class="col">Produkt 1</div> ... </div>
Odstępy, przesunięcia i wyrównanie
Odstępy między kolumnami: g-*
Kolumny mają domyślnie poziomy odstęp (rynnę, ang. gutter). Jego wielkość zmieniasz klasą na wierszu: od g-0 (bez odstępu) do g-5. gx-* zmienia tylko odstęp poziomy, gy-* tylko pionowy, czyli między rzędami, które się zawinęły.
Przesunięcie kolumny: offset-*
offset-md-2 zostawia przed kolumną pustą przestrzeń szerokości dwóch dwunastych. Typowe użycie: wąski blok na środku strony, np. formularz logowania col-md-8 offset-md-2.
Wyrównanie kolumn w wierszu
Wiersz jest kontenerem flex, więc przyjmuje klasy wyrównania. justify-content-center zbiera kolumny na środku, justify-content-between rozsuwa je do krawędzi, align-items-center wyrównuje je w pionie.
offset możesz dać wierszowi justify-content-center. Kolumna col-md-6 stanie wtedy na środku, niezależnie od tego, ile części zostaje po bokach.Marginesy i dopełnienia
Klasy odstępów mają jeden schemat nazwy: właściwość, strona, wielkość. Raz zrozumiany, pozwala pisać je bez zaglądania do dokumentacji.
| Część nazwy | Wartości |
|---|---|
| właściwość | m margines (na zewnątrz), p dopełnienie (w środku) |
| strona | t góra, b dół, s początek (lewa), e koniec (prawa), x lewa i prawa, y góra i dół, brak litery: wszystkie cztery |
| wielkość | 0 0, 1 0,25rem (4px), 2 0,5rem (8px), 3 1rem (16px), 4 1,5rem (24px), 5 3rem (48px), auto |
Przykłady: mt-3 to margines górny 16px, px-4 to dopełnienie po bokach 24px, mb-0 usuwa dolny margines akapitu, mx-auto wyśrodkowuje blok o ustalonej szerokości. Odstępy też mogą mieć punkt przerwania: p-2 p-md-5.
ml-3 i mr-3. W wersji 5 są to ms-3 i me-3 (start i end), bo przy językach pisanych od prawej strony lewa i prawa zamieniają się miejscami. Stare nazwy w wersji 5 nie działają.Kolory, tekst i ramki
Bootstrap ma osiem kolorów nazwanych według roli, a nie odcienia. Dzięki temu zmiana motywu strony nie wymaga zmiany nazw klas.
| Klasa | Co robi |
|---|---|
text-primary, text-danger… | kolor tekstu |
bg-success, bg-light… | kolor tła |
text-bg-dark | tło i dobrany do niego czytelny kolor tekstu naraz |
text-body-secondary | przygaszony tekst, np. podpis, data |
text-center, text-end | wyrównanie tekstu |
fw-bold, fst-italic, text-uppercase | pogrubienie, kursywa, wielkie litery |
fs-1 … fs-6 | wielkość tekstu jak nagłówki h1–h6 |
border, border-primary, border-3 | ramka, jej kolor i grubość |
rounded, rounded-pill, rounded-circle | zaokrąglone rogi |
shadow-sm, shadow, shadow-lg | cień |
bg-dark sam nie zmienia koloru napisów, dlatego łącz go z text-white albo od razu użyj text-bg-dark.Flex i widoczność
Wszystko, co znasz z display: flex, jest dostępne jako klasy. Dzięki nim pasek z logo po lewej i menu po prawej powstaje bez CSS:
<div class="d-flex justify-content-between align-items-center p-3">
<strong>Logo</strong>
<div class="d-flex gap-3">
<a href="#">Start</a> <a href="#">Kontakt</a>
</div>
</div>
| Klasa | CSS pod spodem |
|---|---|
d-flex | display: flex |
flex-column | flex-direction: column |
justify-content-between | justify-content: space-between (także -center, -end, -around) |
align-items-center | align-items: center |
gap-3 | gap: 1rem |
flex-wrap | flex-wrap: wrap |
flex-grow-1 | flex-grow: 1 (element bierze wolne miejsce) |
Ukrywanie zależne od szerokości
Klasy d-* ustawiają display, także z punktem przerwania. d-none ukrywa element, d-md-block pokazuje go od 768px. Razem dają element widoczny tylko na większych ekranach:
<aside class="d-none d-md-block">Reklama tylko na tablecie i komputerze</aside> <p class="d-md-none">Napis tylko na telefonie</p>
Typografia i obrazy
Bootstrap ustawia czytelną czcionkę systemową i rozsądne odstępy nagłówków. Kilka klas pozwala wyróżnić tekst bez pisania CSS:
| Klasa | Do czego |
|---|---|
display-1 … display-6 | bardzo duży nagłówek, np. w banerze strony |
lead | wyróżniony akapit wprowadzający, większy i lżejszy |
small, znacznik <small> | drobny dopisek |
list-unstyled | lista bez kropek i wcięcia |
list-inline + list-inline-item | pozycje listy w jednej linii |
blockquote + blockquote-footer | cytat z podpisem autora |
Obrazy
Obraz wstawiony do wąskiej kolumny potrafi wystawać poza nią, bo zachowuje swoją naturalną szerokość. Klasa img-fluid to max-width: 100%; height: auto: obraz zmniejsza się do szerokości rodzica i zachowuje proporcje. Dodaj ją do każdego zdjęcia w siatce.
Pozostałe klasy obrazów: rounded (zaokrąglone rogi), rounded-circle (koło, przy kwadratowym obrazie), img-thumbnail (ramka jak miniatura). Podpis pod zdjęciem robi się znacznikami figure, figure-img i figure-caption.
Przyciski i odznaki
Przycisk to zawsze dwie klasy: btn (kształt, odstępy, reakcja na najechanie) i wariant koloru. Te same klasy działają na znaczniku <button>, na odnośniku <a> i na <input type="submit">.
| Klasa | Co robi |
|---|---|
btn-primary, btn-danger… | przycisk wypełniony kolorem |
btn-outline-primary… | sama ramka w kolorze, wypełnienie po najechaniu |
btn-lg, btn-sm | większy, mniejszy |
w-100 | przycisk na całą szerokość rodzica |
atrybut disabled | przycisk wyszarzony i nieklikalny |
btn-group na rodzicu | przyciski sklejone w jedną grupę |
Odznaki
Odznaka to mała etykieta z liczbą lub słowem, np. przy pozycji menu albo w nagłówku: <span class="badge text-bg-danger">Nowość</span>. Z klasą rounded-pill ma kształt pigułki.
Pasek nawigacji
Navbar to najbardziej rozbudowany komponent Bootstrapa: na szerokim ekranie odnośniki stoją w rzędzie, a na wąskim chowają się pod przyciskiem z trzema kreskami (tzw. hamburger). Struktura wygląda groźnie, ale zawsze jest taka sama:
<nav class="navbar navbar-expand-md bg-dark" data-bs-theme="dark">
<div class="container">
<a class="navbar-brand" href="#">Rowery</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#menu">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="menu">
<ul class="navbar-nav ms-auto">
<li class="nav-item"><a class="nav-link active" href="#">Start</a></li>
<li class="nav-item"><a class="nav-link" href="#">Oferta</a></li>
<li class="nav-item"><a class="nav-link" href="#">Kontakt</a></li>
</ul>
</div>
</div>
</nav>
| Element | Rola |
|---|---|
navbar navbar-expand-md | pasek; od md (768px) menu jest rozwinięte, poniżej schowane pod przyciskiem |
data-bs-theme="dark" | jasne napisy dla ciemnego tła |
navbar-brand | nazwa lub logo witryny po lewej |
navbar-toggler | przycisk „hamburger”, widoczny tylko na wąskim ekranie; data-bs-target wskazuje id chowanego bloku |
collapse navbar-collapse | blok, który się chowa i rozwija |
navbar-nav, nav-item, nav-link | lista odnośników; active wyróżnia bieżącą stronę |
ms-auto na liście | dosuwa menu do prawej strony paska |
W podglądzie zmień szerokość okna na 400px i kliknij przycisk z kreskami. Rozwijanie działa dzięki skryptowi bootstrap.bundle.min.js. Bez niego przycisk się pokaże, ale nie zareaguje na kliknięcie.
data-bs-target="#menu" szuka elementu z id="menu". Literówka w jednym z nich to najczęstszy powód, dla którego hamburger nic nie robi.Karty
Karta to pudełko z ramką na jedną rzecz: produkt, wpis, osobę, ofertę. Ma opcjonalny obraz na górze, treść i stopkę.
<div class="card">
<img src="rower.jpg" class="card-img-top" alt="Rower górski">
<div class="card-body">
<h5 class="card-title">Rower górski</h5>
<p class="card-text">Rama aluminiowa, 21 biegów.</p>
<a href="#" class="btn btn-primary">Do koszyka</a>
</div>
</div>
Karty prawie zawsze stoją w siatce. Najwygodniej przez row-cols-* i klasę h-100 na karcie: wszystkie karty w rzędzie mają wtedy równą wysokość, nawet gdy opisy są różnej długości.
| Klasa | Rola |
|---|---|
card | pudełko karty |
card-img-top | obraz u góry, na całą szerokość karty, z zaokrąglonymi górnymi rogami |
card-body | treść z dopełnieniem |
card-title, card-text | tytuł i opis |
card-header, card-footer | pasek na górze i na dole karty |
Formularze
Pola formularza dostają klasy według rodzaju. Każde pole poprzedza etykieta połączona z nim atrybutami for i id, a cała para leży w bloku z odstępem pod spodem.
<form>
<div class="mb-3">
<label for="email" class="form-label">E-mail</label>
<input type="email" class="form-control" id="email">
</div>
<div class="mb-3">
<label for="miasto" class="form-label">Miasto</label>
<select class="form-select" id="miasto"><option>Gdańsk</option></select>
</div>
<div class="form-check mb-3">
<input class="form-check-input" type="checkbox" id="zgoda">
<label class="form-check-label" for="zgoda">Akceptuję regulamin</label>
</div>
<button type="submit" class="btn btn-primary">Wyślij</button>
</form>
| Pole | Klasa |
|---|---|
tekst, e-mail, hasło, liczba, data, textarea | form-control |
lista rozwijana select | form-select |
| pole wyboru i przycisk opcji | blok form-check, w nim form-check-input i form-check-label |
| etykieta nad polem | form-label |
| podpowiedź pod polem | form-text |
| pole z doklejonym tekstem, np. „zł” | blok input-group z input-group-text |
Pola obok siebie
Formularz może korzystać z siatki: row g-3 na formularzu i col-md-6 na blokach pól. Na telefonie pola stoją jedno pod drugim, od tabletu po dwa w rzędzie.
Tabele
Zwykła tabela HTML w Bootstrapie nie ma żadnego wyglądu, dopóki nie dostanie klasy table. Pozostałe klasy dokłada się na ten sam znacznik.
| Klasa | Co robi |
|---|---|
table | odstępy w komórkach, linie między wierszami, pełna szerokość |
table-striped | co drugi wiersz zacieniony |
table-hover | podświetlenie wiersza pod kursorem |
table-bordered | ramki wokół wszystkich komórek |
table-sm | mniejsze odstępy |
table-dark na thead | ciemny wiersz nagłówka |
table-success na tr | wyróżniony kolorem wiersz |
Szeroka tabela na telefonie
Tabela z wieloma kolumnami nie zmieści się na wąskim ekranie i rozepchnie stronę. Obejmij ją blokiem <div class="table-responsive">: tabela dostanie wtedy własny poziomy pasek przewijania, a reszta strony zostanie na miejscu.
Alerty, listy i okno modalne
Alert
Kolorowy komunikat: <div class="alert alert-success">Zapisano zamówienie.</div>. Kolor wybierasz według znaczenia: alert-success powodzenie, alert-danger błąd, alert-warning ostrzeżenie, alert-info informacja.
Lista grup
Lista w ramce, z pozycjami oddzielonymi liniami: ul.list-group z elementami li.list-group-item. Pozycja może mieć active, a gdy w środku jest odznaka, wygodnie ustawić ją z prawej przez d-flex justify-content-between.
Okno modalne
Okno modalne pojawia się nad stroną po kliknięciu przycisku i przyciemnia resztę. Działa dzięki skryptowi Bootstrapa, który czyta atrybuty data-bs-*: przycisk ma data-bs-toggle="modal" i data-bs-target z id okna, a przycisk zamykający w oknie ma data-bs-dismiss="modal".
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#okno">Regulamin</button>
<div class="modal fade" id="okno" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Regulamin</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Zamknij"></button>
</div>
<div class="modal-body">Treść regulaminu…</div>
</div>
</div>
</div>
data-bs-toggle z rodzajem komponentu (collapse, modal, dropdown, tab) i data-bs-target z id elementu, którym steruje. Nie piszesz przy tym ani linijki JavaScriptu.Cała strona na Bootstrapie
Czas złożyć wszystko w jedną stronę. Typowa strona-wizytówka ma pięć części i każdą znasz już z poprzednich lekcji:
- Pasek nawigacji:
navbar navbar-expand-mdz marką i menu. - Baner powitalny: blok z kolorowym tłem i dużymi odstępami (
py-5), a w nim kontener z nagłówkiemdisplay-5, akapitemleadi przyciskiem. - Oferta: kontener z wierszem
row row-cols-1 row-cols-md-3 g-4i kartami. - Formularz kontaktowy albo tabela, zależnie od treści.
- Stopka: ciemny pasek z wyśrodkowanym tekstem.
Zwróć uwagę, jak mało tu decyzji o wyglądzie: kolory, odstępy i układ wynikają z kilku klas na każdym bloku. Własny CSS dopisujesz dopiero, gdy chcesz czegoś, czego klasy nie dają, np. zdjęcia w tle banera.
Bootstrap w React
W aplikacji React (np. w zadaniu webowym INF.04) używasz tych samych klas co w HTML. Zmienia się tylko sposób podłączenia Bootstrapa i kilka zasad zapisu, bo komponent zwraca JSX, a nie HTML.
Podłączenie w projekcie Vite
npm create vite@latest sklep -- --template react cd sklep npm install npm install bootstrap npm run dev
Arkusz Bootstrapa importujesz raz, w pliku startowym src/main.jsx, przed własnymi stylami. Wtedy działa w każdym komponencie aplikacji:
import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import 'bootstrap/dist/css/bootstrap.min.css'; // najpierw Bootstrap
import './index.css'; // potem własne style
import App from './App.jsx';
createRoot(document.getElementById('root')).render(
<StrictMode><App /></StrictMode>
);
index.css i App.css reguły demonstracyjne, m.in. body { display: flex; place-items: center; }. Przez nie strona stoi na środku okna, a kontenery i siatka Bootstrapa wyglądają źle. Usuń zawartość obu plików (albo ich import) przed pracą z Bootstrapem.Bez internetu, gdy npm install nie zadziała, skopiuj bootstrap.min.css do folderu public i podłącz go w index.html projektu znacznikiem <link rel="stylesheet" href="/bootstrap.min.css">.
HTML a JSX: co trzeba zmienić
Nazwy klas Bootstrapa zostają bez zmian. Zmieniają się nazwy kilku atrybutów i sposób zamykania znaczników:
| HTML | JSX | Dlaczego |
|---|---|---|
class="btn btn-primary" | className="btn btn-primary" | class to słowo zarezerwowane w JavaScripcie |
for="email" | htmlFor="email" | for to pętla w JavaScripcie |
tabindex="-1" | tabIndex="-1" | atrybuty z kilku słów piszesz camelCase |
<img src="a.jpg">, <input>, <br> | <img src="a.jpg" />, <input />, <br /> | w JSX każdy znacznik musi być zamknięty |
style="max-width: 360px" | style={{ maxWidth: '360px' }} | styl jest obiektem JavaScriptu, nazwy właściwości camelCase |
value="1" w polu bez obsługi zmian | defaultValue="1" | value bez onChange blokuje pole |
<!-- komentarz --> | {/* komentarz */} | komentarz w JSX to wyrażenie JavaScriptu |
data-bs-toggle, aria-label | bez zmian | atrybuty data-* i aria-* zostają z myślnikami |
<label for="imie" class="form-label">Imię</label> <input id="imie" class="form-control"> <img src="logo.png" class="img-fluid">
<label htmlFor="imie" className="form-label">Imię</label>
<input id="imie" className="form-control" />
<img src={logo} className="img-fluid" />Obraz z folderu src importuje się jak moduł (import logo from './logo.png';) i wstawia w nawiasach klamrowych. Obraz z folderu public podajesz zwykłą ścieżką: src="/logo.png".
Klasy zależne od danych i stanu
W React klasy często wynikają z danych. Wartość atrybutu className może być dowolnym wyrażeniem w nawiasach klamrowych, najwygodniej szablonem tekstowym:
const [ulubiony, setUlubiony] = useState(false);
<button
className={`btn ${ulubiony ? 'btn-danger' : 'btn-outline-danger'}`}
onClick={() => setUlubiony(!ulubiony)}>
{ulubiony ? 'W ulubionych' : 'Dodaj do ulubionych'}
</button>
Karty, wiersze tabeli i pozycje listy generujesz z tablicy przez map. Każdy powtarzany element dostaje atrybut key, a klasy Bootstrapa piszesz raz, w szablonie:
<div className="row row-cols-1 row-cols-md-3 g-4">
{rowery.map((r) => (
<div className="col" key={r.id}>
<div className={`card h-100 ${r.promocja ? 'border-danger' : ''}`}>
<div className="card-body">
<h5 className="card-title">{r.nazwa}</h5>
<p className="card-text">{r.cena} zł</p>
</div>
</div>
</div>
))}
</div>
Menu, okna i inne elementy, które reagują na kliknięcie
Są dwie drogi i obie działają:
- Skrypt Bootstrapa. W
main.jsxdopiszimport 'bootstrap/dist/js/bootstrap.bundle.min.js';. Atrybutydata-bs-toggleidata-bs-targetdziałają wtedy tak samo jak w zwykłym HTML. To najszybsza droga, gdy kod przepisujesz z przykładu. - Stan Reacta. Komponent sam pamięta, czy menu albo okno jest otwarte, i dopisuje klasę
show. Nie potrzeba skryptu Bootstrapa, a React kontroluje cały wygląd. To droga zgodna z duchem Reacta, przydatna zwłaszcza wtedy, gdy otwarcie okna zależy od danych, np. po wysłaniu formularza.
function Pasek() {
const [otwarte, setOtwarte] = useState(false);
return (
<nav className="navbar navbar-expand-md bg-dark" data-bs-theme="dark">
<div className="container">
<a className="navbar-brand" href="#">Rowery</a>
<button className="navbar-toggler" onClick={() => setOtwarte(!otwarte)}>
<span className="navbar-toggler-icon"></span>
</button>
<div className={`collapse navbar-collapse ${otwarte ? 'show' : ''}`}>
<ul className="navbar-nav ms-auto">
<li className="nav-item"><a className="nav-link" href="#">Oferta</a></li>
</ul>
</div>
</div>
</nav>
);
}
Okno modalne ze stanem renderujesz tylko wtedy, gdy ma być widoczne. Klasa d-block pokazuje je bez skryptu, a osobny blok modal-backdrop show przyciemnia stronę:
{pokaz && (
<>
<div className="modal d-block" tabIndex="-1">
<div className="modal-dialog">
<div className="modal-content">
<div className="modal-header">
<h5 className="modal-title">Regulamin</h5>
<button className="btn-close" onClick={() => setPokaz(false)}></button>
</div>
<div className="modal-body">Zwrot w ciągu 14 dni.</div>
</div>
</div>
</div>
<div className="modal-backdrop show"></div>
</>
)}
data-bs-toggle i jednocześnie stan Reacta, skrypt Bootstrapa i React będą zmieniać tę samą klasę i menu zacznie się otwierać i zamykać samo.Formularz z walidacją
Pola w React zwykle są kontrolowane: wartość trzymasz w stanie (value i onChange). Klasy Bootstrapa dla błędów dokładasz warunkowo: is-invalid czerwieni pole, a blok invalid-feedback pod nim pokazuje komunikat.
<input
className={`form-control ${blad ? 'is-invalid' : ''}`}
value={imie}
onChange={(e) => setImie(e.target.value)}
/>
<div className="invalid-feedback">Podaj imię.</div>
Biblioteka react-bootstrap
Pakiet react-bootstrap daje gotowe komponenty Reacta z wbudowanym zachowaniem: <Button variant="primary">, <Container>, <Row>, <Col md={4}>, <Navbar expand="md">, <Modal show={pokaz}>. Instalujesz go obok Bootstrapa (npm install react-bootstrap bootstrap), a arkusz CSS i tak importujesz w main.jsx.
import { Container, Row, Col, Card, Button } from 'react-bootstrap';
<Container className="mt-4">
<Row>
<Col md={4}>
<Card><Card.Body><Button variant="success">Kup</Button></Card.Body></Card>
</Col>
</Row>
</Container>
Na egzaminie bezpieczniej pisać zwykłe znaczniki z klasami: arkusze opisują wygląd klasami Bootstrapa, a klucz oceniania sprawdza, czy klasy są na elementach. Komponenty react-bootstrap dają te same klasy w gotowej stronie, ale wymagają dodatkowej instalacji.
Bootstrap a własny CSS
Zmiana wyglądu Bootstrapa
Własny arkusz podłącz pod arkuszem Bootstrapa. Przy tej samej wadze selektora wygrywa reguła zapisana później, więc twoje style nadpiszą domyślne:
<link rel="stylesheet" href="css/bootstrap.min.css"> <link rel="stylesheet" href="css/styl.css"> <!-- po Bootstrapie -->
/* styl.css */
.navbar-brand { font-weight: 800; letter-spacing: 1px; }
#baner { background: url(baner.jpg) center / cover; }
- Nie zmieniaj znaczenia klas Bootstrapa (np.
.btn-primary { background: red }na całej stronie), jeśli możesz dodać własną klasę obok. Kod łatwiej wtedy zrozumieć. - Klasy pomocnicze (
mt-3,text-center,d-none) mają!important. Twojej reguły nie wygrają, dopóki sama nie użyje!important. Zamiast walczyć, po prostu usuń taką klasę z elementu. - Kolory całego Bootstrapa zmienia się zmiennymi CSS, np.
--bs-primary, albo przez własną kompilację, ale na egzaminie zwykle wystarcza nadpisanie kilku reguł.
W projekcie React własny arkusz importujesz w pliku komponentu (import './App.css';), a main.jsx importuje Bootstrapa przed nim. Szczegóły są w lekcji „Bootstrap w React”.
Kiedy Bootstrap, a kiedy własny CSS
| Sytuacja | Wybór |
|---|---|
| Arkusz podaje dokładne kolory, wymiary i reguły CSS do napisania | własny CSS; za brak wymaganych reguł traci się punkty |
| Zadanie wymaga „estetycznego” wyglądu bez szczegółów albo wprost proponuje Bootstrap | Bootstrap oszczędza czas |
| Strona ma działać na telefonie i komputerze | siatka Bootstrapa albo własne @media |
| Potrzebny jeden nietypowy element | Bootstrap plus kilka reguł we własnym arkuszu |
Najczęstsze błędy
| Objaw | Przyczyna |
|---|---|
| Strona bez żadnych stylów | zła ścieżka do bootstrap.min.css albo brak internetu przy CDN |
| Na telefonie wszystko malutkie, kolumny się nie układają | brak <meta name="viewport"> |
| Kolumny stoją jedna pod drugą na komputerze | brak row albo kolumny nie są jego bezpośrednimi dziećmi |
| Hamburger albo okno modalne nie reaguje | brak bootstrap.bundle.min.js albo data-bs-target nie pasuje do id |
ml-3 nic nie robi | to nazwa z Bootstrapa 4; w wersji 5 ms-3 |
| Własna reguła nie działa | arkusz własny jest nad Bootstrapem albo element ma klasę pomocniczą z !important |
Quiz
Pytania w stylu części pisemnej egzaminu. Po kliknięciu odpowiedzi zobaczysz wyjaśnienie.
Ściąga
Szablon strony
<meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="css/bootstrap.min.css"> ... <script src="js/bootstrap.bundle.min.js"></script> <!-- przed </body> -->
Punkty przerwania
(brak) < 576px · sm ≥ 576 · md ≥ 768 · lg ≥ 992 · xl ≥ 1200 · xxl ≥ 1400. Klasa z punktem działa od tej szerokości w górę.
Siatka
container / container-fluid | kontener stały / na całą szerokość |
row | wiersz; kolumny muszą być jego dziećmi |
col, col-4, col-md-6, col-auto | kolumna równa / 4 z 12 / połowa od md / szerokość treści |
row-cols-1 row-cols-md-3 | liczba kolumn w rzędzie ustawiana na wierszu |
g-0 … g-5, gx-*, gy-* | odstępy między kolumnami |
offset-md-2 | przesunięcie o 2 z 12 |
justify-content-center, align-items-center na row | wyrównanie kolumn |
Klasy pomocnicze
m/p + t b s e x y + 0–5/auto | mt-3, px-4, mb-0, mx-auto; 1 = 4px, 2 = 8px, 3 = 16px, 4 = 24px, 5 = 48px |
text-*, bg-*, text-bg-* | primary, secondary, success, danger, warning, info, light, dark |
text-center, text-end, fw-bold, fs-1…6, text-uppercase | tekst |
border, rounded, rounded-circle, shadow | ramka, rogi, cień |
d-flex, flex-column, justify-content-between, align-items-center, gap-3 | flex |
d-none d-md-block, d-md-none | widoczne od md / tylko poniżej md |
w-100, h-100, img-fluid | pełna szerokość, pełna wysokość, obraz dopasowany do rodzica |
display-1…6, lead, list-unstyled | typografia |
Komponenty
| przycisk | btn btn-primary, btn-outline-*, btn-lg, btn-sm |
| odznaka | badge text-bg-danger, rounded-pill |
| navbar | navbar navbar-expand-md › container › navbar-brand, navbar-toggler, collapse navbar-collapse#id › navbar-nav › nav-item › nav-link |
| karta | card › card-img-top, card-body › card-title, card-text |
| formularz | mb-3 › form-label + form-control/form-select; form-check › form-check-input + form-check-label |
| tabela | table table-striped table-hover, thead.table-dark, otoczka table-responsive |
| alert, lista | alert alert-success; list-group › list-group-item |
| okno modalne | przycisk data-bs-toggle="modal" data-bs-target="#id"; modal › modal-dialog › modal-content › modal-header, modal-body |
Bootstrap w React
npm install bootstrap // src/main.jsx, przed własnymi stylami: import 'bootstrap/dist/css/bootstrap.min.css'; import 'bootstrap/dist/js/bootstrap.bundle.min.js'; // tylko gdy używasz data-bs-*
class → className, for → htmlFor, tabindex → tabIndex | nazwy atrybutów w JSX |
<img />, <input />, <br /> | każdy znacznik zamknięty |
style={{ maxWidth: '360px' }}, {/* komentarz */} | styl jako obiekt, komentarz w klamrach |
className={`btn ${aktywny ? 'btn-primary' : 'btn-outline-primary'}`} | klasa zależna od stanu |
className={`collapse navbar-collapse ${otwarte ? 'show' : ''}`} | menu rozwijane stanem, bez skryptu Bootstrapa |
{lista.map((x) => <div className="col" key={x.id}>…</div>)} | karty i wiersze z tablicy, zawsze z key |