Kurs HTML i CSS · Moduł 9: Nowoczesny CSS

Modern CSS Features - przyszłość stylow ania egipskich hieroglifów

8 min czytania ·
W tej lekcji12

Witaj w przyszłości CSS! Podobnie jak starożytni Egipcjanie byli pionierami w architekturze, tak my jesteśmy świadkami rewolucji w CSS. Poznaj nowoczesne funkcje CSS z lat 2020-2024, które zmieniają sposób, w jaki stylujemy strony internetowe!

aspect-ratio - idealne proporcje

aspect-ratio pozwala na łatwe tworzenie elementów z zachowanymi proporcjami bez hacków z padding!

Przed aspect-ratio (stary sposób)

/* Stary hack z padding-bottom */
.video-container {
  position: relative;
  padding-bottom: 56.25%; /* 16:9 = 9/16 = 0.5625 = 56.25% */
  height: 0;
}

.video-container iframe {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}

Z aspect-ratio (nowy sposób)

/* Nowoczesny sposób - prosty i czytelny */
.video-container {
  aspect-ratio: 16 / 9;
  width: 100%;
}

.video-container iframe {
  width: 100%;
  height: 100%;
}

Analogia egipska: To jak idealne proporcje Wielkiej Piramidy (4:3) - zachowane niezależnie od skali!

Praktyczne przykłady aspect-ratio

1. Video responsive

.video-wrapper {
  aspect-ratio: 16 / 9;
  width: 100%;
  max-width: 800px;
  margin: 0 auto;
}

.video-wrapper iframe {
  width: 100%;
  height: 100%;
  border: none;
}

2. Image cards

.card-image {
  aspect-ratio: 4 / 3;
  width: 100%;
  object-fit: cover;
  border-radius: 8px;
}

3. Square avatars

.avatar {
  aspect-ratio: 1;  /* 1:1 = kwadrat */
  width: 100px;
  border-radius: 50%;
  object-fit: cover;
}

4. Golden ratio

.golden-box {
  aspect-ratio: 1.618;  /* Złoty podział */
  width: 100%;
  background: goldenrod;
}

5. Instagram post

.instagram-post {
  aspect-ratio: 1 / 1;  /* Kwadrat Instagram */
  width: 100%;
  max-width: 600px;
}

6. Mobile screens

.phone-mockup {
  aspect-ratio: 9 / 19.5;  /* Proporcje iPhone */
  width: 375px;
  border: 10px solid black;
  border-radius: 30px;
}

gap dla Flexbox i Grid

gap działa teraz zarówno w Grid jak i Flexbox! (od 2021)

/* Grid - od zawsze */
.grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 20px;  /* Row i column gap */
}

/* Flexbox - od 2021! */
.flex-container {
  display: flex;
  gap: 20px;  /* Odstęp między items */
}

Praktyczne przykłady gap

/* Navigation z gap */
.nav {
  display: flex;
  gap: 1.5rem;
  align-items: center;
}

/* Button group */
.button-group {
  display: flex;
  gap: 0.5rem;
}

/* Form fields */
.form {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

/* Card grid */
.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: 2rem 1rem;  /* 2rem row, 1rem column */
}

:is() i :where() - grupowanie selektorów

Nowe pseudo-classes pozwalają na eleganckie grupowanie!

:is() - z wagą specificity

/* Zamiast: */
h1 a,
h2 a,
h3 a,
h4 a,
h5 a,
h6 a {
  color: goldenrod;
}

/* Użyj :is() */
:is(h1, h2, h3, h4, h5, h6) a {
  color: goldenrod;
}

Specificity :is(): Bierze najwyższą specificity z listy!

/* Specificity = ID (100) */
:is(#id, .class, div) {
  color: red;
}

:where() - bez wagi specificity

/* Specificity = 0! */
:where(h1, h2, h3) {
  margin-top: 0;
}

/* Łatwo nadpisać */
h2 {
  margin-top: 1rem;  /* To wygra, bo :where() ma 0 specificity */
}

Praktyczne przykłady

/* Reset dla headings */
:where(h1, h2, h3, h4, h5, h6) {
  margin: 0;
  font-weight: 600;
}

/* Link states */
:is(a:hover, a:focus) {
  text-decoration: underline;
  color: goldenrod;
}

/* Form inputs */
:is(input, textarea, select):focus {
  outline: 2px solid #3498db;
  outline-offset: 2px;
}

/* Lists */
:where(ul, ol):where(:not([class])) {
  padding-left: 1.5em;
}

:has() - parent selector!

:has() to rewolucja - pozwala stylować rodzica na podstawie dzieci!

/* Styluj article, który MA obrazek */
article:has(img) {
  display: grid;
  grid-template-columns: 1fr 2fr;
}

/* Styluj card, który MA button */
.card:has(.button) {
  padding-bottom: 4rem;
}

/* Styluj form, który MA error */
form:has(.error) {
  border: 2px solid red;
}

Praktyczne przykłady :has()

1. Layout adaptation

/* Card z obrazkiem - inny layout */
.card:has(img) {
  display: flex;
  flex-direction: row;
}

/* Card bez obrazka - normalny layout */
.card:not(:has(img)) {
  text-align: center;
}

2. Form validation

/* Form field z errorem */
.form-field:has(input:invalid) {
  border-color: red;
}

.form-field:has(input:valid) {
  border-color: green;
}

/* Label gdy input ma fokus */
.form-field:has(input:focus) label {
  color: #3498db;
  font-weight: bold;
}

3. Checkbox styling

/* Styluj label gdy checkbox zaznaczony */
.checkbox-wrapper:has(input:checked) label {
  font-weight: bold;
  color: green;
}

.checkbox-wrapper:has(input:checked) {
  background: #e8f5e9;
}

4. Navigation highlighting

/* Highlight section w navigation */
nav:has(~ main #section-1) .nav-link[href="#section-1"] {
  color: goldenrod;
  font-weight: bold;
}

5. Empty state

/* Styluj container gdy pusty */
.list:not(:has(li)) {
  display: flex;
  align-items: center;
  justify-content: center;
}

.list:not(:has(li))::before {
  content: "Brak elementów";
  color: #999;
}

subgrid - zagnieżdżone siatki

subgrid pozwala dzieciom używać siatki rodzica!

.parent-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 20px;
}

.child-grid {
  display: grid;
  /* Użyj kolumn z rodzica! */
  grid-template-columns: subgrid;
  grid-column: span 2;
}

Praktyczny przykład

<div class="product-grid">
  <article class="product">
    <h3>Produkt 1</h3>
    <div class="product-details">
      <span class="price">$99</span>
      <button>Kup</button>
    </div>
  </article>
</div>
.product-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: 2rem;
}

.product {
  display: grid;
  /* Wyrównaj wszystkie .product-details w tej samej linii */
  grid-template-rows: auto 1fr auto;
}

.product-details {
  display: grid;
  grid-template-columns: subgrid;
  grid-column: 1 / -1;
  align-items: center;
}

@layer - Cascade Layers

@layer pozwala kontrolować cascade bez specificity!

/* Zdefiniuj kolejność layers */
@layer reset, base, components, utilities;

/* Layer reset - najniższy priorytet */
@layer reset {
  * {
    margin: 0;
    padding: 0;
  }
}

/* Layer base */
@layer base {
  body {
    font-family: Arial, sans-serif;
  }
}

/* Layer components */
@layer components {
  .button {
    background: #3498db;
    color: white;
  }
}

/* Layer utilities - najwyższy priorytet */
@layer utilities {
  .text-center {
    text-align: center;
  }
}

@container - Container Queries

Container Queries pozwalają stylować na podstawie rozmiaru kontenera, nie viewport!

.card-container {
  container-type: inline-size;
  container-name: card;
}

.card {
  padding: 1rem;
}

/* Gdy kontener > 400px */
@container card (min-width: 400px) {
  .card {
    display: flex;
    gap: 1rem;
  }

  .card img {
    width: 150px;
  }
}

/* Gdy kontener > 600px */
@container card (min-width: 600px) {
  .card {
    padding: 2rem;
  }
}

color-mix() - mieszanie kolorów

.element {
  /* Zmieszaj 50% blue z 50% red */
  background: color-mix(in srgb, blue 50%, red);

  /* Rozjaśnij kolor */
  background: color-mix(in srgb, #3498db, white 20%);

  /* Przyciemnij kolor */
  background: color-mix(in srgb, #3498db, black 20%);
}

accent-color - kolorowanie form controls

/* Zmień kolor checkboxów, radio, range */
input[type="checkbox"],
input[type="radio"],
input[type="range"] {
  accent-color: goldenrod;
}

/* Globalnie */
:root {
  accent-color: #3498db;
}

Inne nowoczesne właściwości

overflow: clip

.element {
  /* Jak overflow: hidden, ale nie tworzy scroll context */
  overflow: clip;
}

inset - skrót dla top/right/bottom/left

/* Zamiast: */
.element {
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
}

/* Użyj inset */
.element {
  inset: 0;
}

/* Lub per-side */
.element {
  inset: 10px 20px;  /* top/bottom left/right */
}

object-view-box - crop obrazków

img {
  object-view-box: inset(10% 20% 10% 20%);
  /* Przycina obrazek z wszystkich stron */
}

content-visibility - performance

.long-section {
  /* Nie renderuj poza viewport - OGROMNY boost performance! */
  content-visibility: auto;
  contain-intrinsic-size: 0 500px;
}

Wsparcie przeglądarek (2024)

FeatureChromeFirefoxSafariEdge
aspect-ratio88+ (2020)89+ (2021)15+ (2021)88+
gap w Flexbox84+ (2020)63+ (2018)14.1+ (2021)84+
:is()88+78+14+88+
:where()88+78+14+88+
:has()105+ (2022)121+ (2023)15.4+ (2022)105+
subgrid117+ (2023)71+ (2019)16+ (2022)117+
@container106+ (2022)110+ (2023)16+ (2022)106+
@layer99+ (2022)97+ (2022)15.4+ (2022)99+

Podsumowanie

Najważniejsze nowoczesne features:

  • aspect-ratio - idealne proporcje bez hacków
  • gap - odstępy w Flexbox i Grid
  • :is()/:where() - eleganckie grupowanie
  • :has() - parent selector!
  • subgrid - zagnieżdżone siatki
  • @layer - kontrola cascade
  • @container - responsive na poziomie komponentu

Dlaczego używać:

  • Czystszy kod
  • Mniej hacków
  • Lepsza wydajność
  • Łatwiejsze utrzymanie
Kod do tej lekcji: index.html
<!DOCTYPE html>
<html lang="pl">
<head>
    <meta charset="UTF-8">
    <title>Modern CSS - Projekt</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <div class="page">
        <header>
            <h1>Swiatynia Nowoczesnego CSS</h1>
            <p class="subtitle">Polacz wszystkie techniki w jednym projekcie</p>
        </header>
        <main class="grid-layout">
            <div class="card-container">
                <article class="card">
                    <div class="card-media">Container Queries</div>
                    <div class="card-body">
                        <h2>Adaptacyjne karty</h2>
                        <p>Reaguja na rozmiar kontenera.</p>
                    </div>
                </article>
            </div>
            <div class="card-container">
                <article class="card">
                    <div class="card-media">:has() + Nesting</div>
                    <div class="card-body">
                        <h2>Inteligentne selektory</h2>
                        <p>Rodzic stylowany przez dzieci.</p>
                    </div>
                </article>
            </div>
            <section class="scroll-section">
                <h2>Galeria scroll-snap</h2>
                <div class="snap-gallery">
                    <div class="snap-item" style="background:#d4af37">Skarabeusz</div>
                    <div class="snap-item" style="background:#8b6914">Ankh</div>
                    <div class="snap-item" style="background:#1e3a5f">Oko Horusa</div>
                    <div class="snap-item" style="background:#b87333">Piramida</div>
                </div>
            </section>
            <section class="form-section">
                <h2>Formularz z accent-color</h2>
                <label><input type="checkbox" checked> Opcja 1</label>
                <label><input type="range" min="0" max="100" value="70"></label>
            </section>
        </main>
    </div>
</body>
</html>

Pamiętaj: Modern CSS to jak odkrycie nowych hieroglifów - nowe możliwości, prostsze rozwiązania, potężniejsze narzędzia!

Hasła z dokumentacji w tej lekcji

Widzisz błąd w tej lekcji?

Sprawdź się

Odpowiedz na pytania z tej lekcji. Wybierz odpowiedź, a od razu zobaczysz, czy jest poprawna.

  1. 1. Co zmieniło się w obsłudze właściwości gap od 2021 roku?

  2. 2. Czym jest właściwość inset: 0 w CSS?

To 2 z 3 pytań do tej lekcji. Pozostałe rozwiążesz w grze.

Zadania praktyczne w grze

  • Układanie w poziomie

    Ułóż w jednej linii poprawną deklarację overflow: clip:

Przydatne artykuły