JavaScript 3.11.25

Zaawansowane formularze


Chceckbox - wybór prawda/fałsz 0/1, inaczej zachowuje się niż radiobutton, przydatny jest w odbieraniu zgód od użytkowników, tak żeby dać mu możliwość kontrolowania/wyrażenia zgody, każdy z osobna można zaznaczyć (RODO, zgoda na przetwarzanie danych, regulaminy itd. )

checked - domyślnie zaznaczony

value - jest wysyłany do servera w momencie gdy checbox jest zaznaczony, czyli to co jest w value zostanie wysłane, jeśli nie jest zaznaczony nic nie zostanie wysłane

Dobrym pomysłem jest używanie chcecboxów a potem opisów, bo ja wcale nie musze klikac w checbox, ale w label (jak klikam w label juz sie zanzacza)- dobry feature accesibility

name="interest" ono się nie wysyła jak nie zaznaczymy

Radiobutton- różnica między RB a checbox- możliwy do zaznaczenia jest tylko jeden, przeglądarka odznacza jeśli inny zaznaczamy, tylko jeden element grupy może być wybrany, radiobuttony musza być zgrupowane (fieldset, label), value tak samo jak w checbox, ustawianie domyślnej wartości jest dobrym pomysłem checked (podczas ładowania str juz sie zaznacza)

Zaawansowane pola:

input type - file, wymagana metoda post, wymagane wskazany tryb/typ w jakim te dane są encodowane, enctype="multipart/multiform"

accept="image/*" Mamy wpływ jaki rodzaj danych chcemy aby użytkownik mógł przesłać, documents - .pdf, .doc, .docx, wiele zdjęć/plików - multiple

to że my ograniczamy przeglądarkę do jakichś typów plików, to tu widać (w formularzu do przesyłania) to nie znaczy ze użytkownik nie może wysłać nam jakiegoś innego pliku niż ten co by chcemy, np. ktoś sprawdzi gdzie są wysyłane dane np action/upload jest w stanie sam wysłać nam zapytanie do serwera i wtedy te pliki nie maja znaczenia co my sobie zaznaczymy, ale po str. serwera te dane czy ten plik faktycznie jest pdf doc. itd. trzeba zweryfikować.

type="date/datetime" - dostajemy pole kalendarza -lokalny kalendarz użytkownika (np. z domyślną datą), nie trzeba javascript do tego jeśli takie pole nam tylko wystarcza. date time czas i data, date sama data, można stworzyć pole do ograniczonych wartości (min, max). Idealne do rezerwacji, harmonogramów, planowania. Nawet b stara przeglądarka będzie w stanie to odczytać tylko użytkownik będzie musiał wpisać ręcznie. W Javascript można sobie zakodować, że np. pokazuje tylko przyszłe daty (np od dziś) a nie z przeszłości (podmienic min max)

Walidacja formularzy

ValidationAPI- wbudowane w przeglądarkę

Listy rozwijanie SELECT

Prosty select - bez domyślnej wartości value="" – wybierz kraj – (wartość pusta)

Select z domyślnym wyborem - jeśli nie ma value=""

Select z grupowaniem opcji - kiedy mamy dużo do wyboru <optgroup label="czego grupa dotyczy">a tu selecty</optgroup>

Select może być nie tylko jednowyborowy, może stworzyć tabele wyników np. po zainteresowań, przypisywanie więcej niż 1 kategorii do czegoś atrybut multiple size="x" powoduje ze pole się rozciąga na x wartości x to cyfra

Select z wyłączonymi opcjami (xs wyprzedane, S dostepny, M dostepny) disabled

można dać disabled w ogóle do selecta gdzie nie można wypełnić jeżeli czegoś nie wybraliśmy, formularz zamówienia -dodatkowe pola aktywują się dopiero jak wybierzemy np. chce fakturę, adres wysyłki inny niż adres na fakturze, można sięgnąć do bazy danych przez JS i wtedy on zaznacza/odznacza czy np. dana koszula jest dostępna

Zaawansowana walidacji formularzy

Walidacja zakresów - jak źle wpiszemy z ręki to przeglądarka pokazuje monit np. ze wartość nie może być mniejsza niż 1 min, max step

Walidacja długości - ilość znaków minlenght, max lenght

Walidacja dat - j.w w select, min max

Walidacja wzorców - patterns regex telefony, kolor

Web Safe Color Chart
Web safe colors emerged during the early era of the internet; a standardized palette of 216 colors that displayed consistently across all major browsers.

step - zwiększenie o 1 lub o o.5 lub o 5 etc.

w JavaScript stawiamy liczby z kropka a nie z przecinkiem

Dlaczego zaczęto walidować w JS? W HTML jest problem taki, że przeglądarka jest nie za mądra, waliduje wszystko po kolei i zatrzymuje się na każdym błędzie, może być wiele źle wypełnionych pól, a trzeba walidować wszystko na raz wtedy widzimy, co zostało źle wypełnione. Długi formularz - zły UX

W tworzeniu formularzy, oprócz tego, że chcemy aby były walidowane, chcemy aby były dostępne - atrybuty aria

aria-label

aria-describedby,

aria-required="true"

aria-labelledby


CSS - Kaskadowe Arkusze Stylów

CSS ma inny styl komentarza * / */

Podstawy i selektory

3 sposoby dodawania CSS do dokumentu HTML

Kaskadowe- czyli dziedziczą właściwości po kolejnych stylach, jeśli nie będą zdefiniowane to będzie do wszystkich to samo

  1. dodawanie elementów bezpośrednio do taga np. inline style=" color:red; font-size: 18px; font-weight:bold;" nie jest to efektywne, bo tyczy się tylko jednego elementu anie zestawu elementów
  2. Internal CSS embedded class="internal-example" tag <style> </style>W NAGŁÓWKU head dokumentu, dotyczy tylko tej str na której jest dodany w head.
  3. 3. External CSS zalecane dla większości projektów link rel="stylesheet" href="styles.css" pozwala na reuse

Najważniejszy styl to inline jeśli jest zdefiniowane zawsze będzie ponad <style> i ponad external. Jeżeli dany tag posiada inline a w <style> lub external to robi mix np. dodaje padding, jeśli w inline jest color to będzie color z inline, ale jeśli w p nie ma padding to padding dodaje się od tych innych stylów. Więc te style się sklejają, ale nadal kolejność ma znaczenie -KASKADOWOŚĆ

Inline nie jest zalecany, używamy w bardzo specyficznych przypadkach, nie da się użyć go wielokrotnie, ciągle trzeba dodawać go, ciężko dokonywać zmian itd. Najlepiej w <style></style> lub w zewnętrznym pliku css.

!important nadpisuje styl

body { } do sekcji, selektor typu wybiera wszystkie elementy opisany przez dany tag

.internal-example { } selektor klas wszystkie elementy o przypisanej klasie

#internal-id mówi przeglądarce znajdź mi te id i daj mu ten styl selektor id, wybiera konkretne id

Różnica span a div - span inline a div w nowej lini bez odstępu (nie łamie lini) a paragraf nowa linia z odstępem

Jeżeli mamy class to width i height bedzie działać do elementow boxowych div i paragraph a nie inline czyli span

można zdefiniować wszystkie strong i em {} w stylu css

gwiazdka {} to selektor uniwersalny czyli zastosowuje się do wszystkiego, dla całego dokumentu ustaw marginesy, odstępy, rozmiar boxów, to jest reset

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Sposoby dodawania CSS</title>
    
    <!-- SPOSÓB 2: Internal CSS (embedded) -->
    <style>
        /* Style dla całego dokumentu */

        h1, h2, h3 {
            color: blue;
            background-color: blueviolet;
        }


        body {
            font-family: Arial, sans-serif;
            margin: 20px;
            background-color: bisque;
        }


        .internal-example {
            color: green;
            font-weight: bold;
        }
        
        #internal-id {
            background-color: lightgreen;
            padding: 10px;
        }
    </style>
    
    <!-- SPOSÓB 3: External CSS (zalecane dla większości projektów) -->
    <link rel="stylesheet" href="styles.css">
</head>

<!-- SPOSÓB 1: Inline CSS -->
    <p style="color: red; font-size: 18px; font-weight: bold;">
        To jest tekst ze stylami inline (czerwony, 18px, pogrubiony)
    </p>
    
    <p style="background-color: yellow; padding: 10px;">
        Kolejny paragraf ze stylami inline (żółte tło, padding)
    </p>
    
    <!-- SPOSÓB 2: Internal CSS (z sekcji <style> powyżej) -->
    <p class="internal-example">
        To jest tekst stylowany przez internal CSS (zielony, bold)
    </p>
    
    <div id="internal-id">
        Ten div używa ID z internal CSS (zielone tło)
    </div>
    
    <!-- SPOSÓB 3: External CSS -->
    <p class="external-example">
        Ten tekst używałby stylów z zewnętrznego pliku styles.css
    </p>


      /* To jest komentarz w CSS */
        /* Komentarze mogą być
           wieloliniowe */
        
        /* RULESET (reguła) składa się z: */
        /* selector { property: value; } */
        
        /* UNIVERSAL SELECTOR - targetuje wszystkie elementy */
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }


        /* Selector - określa KTÓRE elementy stylować */
        h1 {
            /* Declaration block - w nawiasach klamrowych {} */
            
            /* Deklaracja składa się z property: value; */
            color: blue;              /* property: color, value: blue */
            font-size: 32px;          /* property: font-size, value: 32px */
            text-align: center;       /* property: text-align, value: center */
            margin-bottom: 20px;      /* każda deklaracja kończy się średnikiem */
        }
        
        /* Wiele selektorów może mieć te same style (grouping) */
        h2, h3, h4 {
            color: darkblue;
            font-family: Georgia, serif;
        }
        
        strong, em {
            color: darkblue;
        }


        /* Selector może być złożony */
        .highlight {
            background-color: yellow;
            padding: 5px;
        }
        
        /* Białe znaki są ignorowane - możemy formatować jak chcemy */
        p { color: gray; line-height: 1.6; }  /* W jednej linii */
        
        /* Lub z wcięciami dla czytelności (preferowane) */
        .box {
            width: 200px;
            height: 200px;
            background-color: lightblue;
            border: 2px solid darkblue;
        }

button {} zdefiniowanie stylu buttonu

button:hover {} zdefiniowanie po najechaniu kursorem, to są pseudoklasy, jest ich więcej, możemy zdefiniować kiedy dokładnie ma ten styl się aktywować, jeżeli ten warunek przestaje istnieć, to wracamy do klasy głównej

:hover (po najechaniu), 
:active (podczas kliknięcia), 
:focus (ma fokus), 
:visited (odwiedzony link), 
:link (nieodwiedzony link), 
:first-child (pierwszy dziecko), 
:last-child (ostatni dziecko), 
:nth-child(n) (n-te dziecko), 
:not() (negacja). Pseudo-elements tworzą i stylują części elementu: 
::before (przed treścią), ::after (po treści), 
::first-line (pierwsza linia), 
::first-letter (pierwsza litera), 
::selection (zaznaczony tekst).

Co jest najważniejsze? Jaki styl jest najważniejszy? Jaki typ selektora jest najważniejszy?

!important

div p {} - wszystkie p w div

no-repeat nie powtarza obrazu np. w div

body {
            font-family: Arial, sans-serif;
            padding: 20px;
            line-height: 1.6;
        }
        
        /* DESCENDANT COMBINATOR (spacja) - wszystkie p wewnątrz div */
        div p {
            color: blue;
        }
        
        /* CHILD COMBINATOR (>) - tylko bezpośrednie dzieci */
        .parent > p {
            font-weight: bold;
        }
        
        /* ADJACENT SIBLING (+) - pierwszy p bezpośrednio po h2 */
        h2 + p {
            background-color: lightyellow;
            padding: 10px;
        }
        
        /* GENERAL SIBLING (~) - wszystkie p będące siblings of h3 */
        h3 ~ p {
            color: green;
        }
        
        /* ATTRIBUTE SELECTORS */
        
        /* [attr] - ma atrybut */
        [disabled] {
            opacity: 0.5;
            cursor: not-allowed;
        }
        
        /* [attr="value"] - dokładna wartość */
        [type="text"] {
            border: 2px solid blue;
            padding: 5px;
        }
        
        /* [attr^="value"] - zaczyna się od */
        [href^="https"] {
            color: green;
        }
        
        /* [attr$="value"] - kończy się na */
        [href$=".pdf"] {
            background: url('data:image/svg+xml,...') no-repeat;
            padding-left: 20px;
        }
        
        /* [attr*="value"] - zawiera */
        [class*="btn"] {
            display: inline-block;
            padding: 10px 20px;
            background-color: lightblue;
        }
 /* PSEUDO-CLASSES - określają specjalny stan elementu */
        
        /* :hover - po najechaniu myszką */
        .button:hover {
            background-color: darkblue;
            color: white;
        }
        
        /* :active - podczas kliknięcia */
        .button:active {
            transform: scale(0.95);
        }
        
        /* :focus - ma fokus (kliknięty lub Tab) */
        input:focus {
            border-color: blue;
            outline: 2px solid lightblue;
        }
        
        /* :visited i :link - dla linków */
        a:link {
            color: blue;
        }
        
        a:visited {
            color: purple;
        }
        
        a:hover {
            color: red;
            text-decoration: none;
        }
        
        /* :first-child, :last-child, :nth-child */
        .list-item:first-child {
            font-weight: bold;
        }
        
        .list-item:last-child {
            color: red;
        }
        
        .list-item:nth-child(even) {
            background-color: lightgray;
        }
        
        /* :not() - negacja */
        p:not(.special) {
            color: gray;
        }
        
        /* PSEUDO-ELEMENTS - stylują część elementu */
        
        /* ::before i ::after - dodają treść */
        .note::before {
            content: "📝 ";
            font-size: 20px;
        }
        
        .warning::before {
            content: "⚠️ ";
        }
        
        /* ::first-line - pierwsza linia tekstu */
        .intro::first-line {
            font-weight: bold;
            font-size: 1.2em;
        }
        
        /* ::first-letter - pierwsza litera */
        .drop-cap::first-letter {
            font-size: 3em;
            float: left;
            line-height: 0.8;
            margin-right: 5px;
        }
        
        /* ::selection - zaznaczony tekst */
        ::selection {
            background-color: yellow;
            color: black;
        }

Ważność jest kalkulowana na podst. tego jak styl jest zbudowany oraz gdzie jest zdefiniowany

Specyficzność:

0,0,1 (1 element)

0,1,0 (1 klasa)

1,0,0 unique

.important czyli bije wszystko inne

 /* SPECIFICITY (specyficzność) */
        
        /* Specificity: 0,0,1 (1 element) */
        p {
            color: gray;
        }
        
        /* Specificity: 0,1,0 (1 class) - WYGRYWA nad element */
        .text {
            color: blue;
        }
        
        /* Specificity: 0,1,1 (1 class + 1 element) - WYGRYWA nad class */
        p.text {
            color: green;
        }
        
        /* Specificity: 1,0,0 (1 ID) - WYGRYWA nad wszystkim powyżej */
        #unique {
            color: red;
        }
        
        /* !important - WYGRYWA nad wszystkim (używaj ostrożnie!) */
        .important {
            color: orange !important;
        }
        
        /* SOURCE ORDER - przy równej specificity, wygrywa późniejszy */
        .order-test {
            color: purple;
        }
        
        .order-test {
            color: brown; /* Ta reguła wygrywa (późniejsza) */
        }
        
        /* INHERITANCE (dziedziczenie) */
        
        .parent {
            color: darkblue;
            font-size: 18px;
            border: 2px solid black; /* NIE jest dziedziczone */
        }
        
        /* Dziecko dziedziczy color i font-size od rodzica */
        /* Ale NIE dziedziczy border */
        
        /* Wymuś dziedziczenie */
        .child-inherit {
            border: inherit; /* Wymusza dziedziczenie border */
        }
        
        /* Resetuj do initial */
        .child-initial {
            color: initial; /* Resetuje do domyślnego czarnego */
        }
        
        /* CSS RESET przykład */
        .reset-example * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

CSS właściwości tekstu i kolorów

Font Family

przegladarka użuwa domyślnej czcionki, jeśli nazwa czcionki zawiera spacje musi być zapisana w " Times New Roman"

serif - ozdobniki na literkach np. Georgia

sans-serif - bez ozdobników

monospace - każda litera tej samej szerokości (elementy zależne od długości tekstów w javascript łatwo obliczyć jaką szerokośc ma mieć element np mozna policzyc znaki i już)

Jeśli chcemy by strona była szybka i czytelna - sans-serif lub monospace

Font Size

px - można w pikselch,

em względnie do rodziców

rem- względny do root

Font weight

max 900, mix 100, 500-600 to takie normalne wartości

bold, light, number

nie wszystkie wagi są dostępne dla każdej czcionki, czionka musi mieć zdefiniowny styl, zaczwyczaj maja normal bold i light ale bolder i lighter nie każda czcionka ma wiec mogą sie nie wyświetlić

Font Style

normal, italic

Font height

Wysokość lini, interlinia

/* FONT-FAMILY - różne rodziny czcionek */
        .serif-font {
            font-family: Georgia, "Times New Roman", Times, serif;
        }
        
        .sans-serif-font {
            font-family: Arial, Helvetica, Verdana, sans-serif;
        }
        
        .monospace-font {
            font-family: "Courier New", Courier, monospace;
        }
        
        /* FONT-SIZE - różne rozmiary */
        .size-px {
            font-size: 16px; /* Absolutny rozmiar w pixels */
        }
        
        .size-em {
            font-size: 1.5em; /* Względny do rodzica (150%) */
        }
        
        .size-rem {
            font-size: 1.5rem; /* Względny do root (zwykle 16px * 1.5 = 24px) */
        }
        
        .size-percent {
            font-size: 150%; /* Względny do rodzica */
        }
        
        /* FONT-WEIGHT - grubość czcionki */
        .weight-normal {
            font-weight: normal; /* lub 400 */
        }
        
        .weight-bold {
            font-weight: bold; /* lub 700 */
        }
        
        .weight-lighter {
            font-weight: lighter; /* Względny do rodzica */
        }
        
        .weight-number {
            font-weight: 600; /* Numeryczna wartość */
        }
        
        /* FONT-STYLE - styl czcionki */
        .style-normal {
            font-style: normal;
        }
        
        .style-italic {
            font-style: italic;
        }
        
        /* LINE-HEIGHT - wysokość linii */
        .line-height-tight {
            line-height: 1.2; /* Ściśnięty (120% font-size) */
        }
        
        .line-height-normal {
            line-height: 1.6; /* Normalny (160%) */
        }
        
        .line-height-loose {
            line-height: 2; /* Luźny (200%) */
        }
        
        /* Przykład długiego tekstu dla line-height */
        .long-text {
            max-width: 600px;
            background-color: #f0f0f0;
            padding: 15px;
            margin: 10px 0;
        }

Text Properties

Align

Decoration

transform

spacing

  /* TEXT-ALIGN - wyrównanie tekstu */
        .align-left {
            text-align: left;
        }
        
        .align-center {
            text-align: center;
        }
        
        .align-right {
            text-align: right;
        }
        
        .align-justify {
            text-align: justify;
        }
        
        /* TEXT-DECORATION - dekoracje tekstu */
        .decoration-underline {
            text-decoration: underline;
        }
        
        .decoration-overline {
            text-decoration: overline;
        }
        
        .decoration-line-through {
            text-decoration: line-through;
        }
        
        .decoration-none {
            text-decoration: none; /* Usuwa - przydatne dla linków */
        }
        
        .decoration-styled {
            text-decoration: underline wavy red;
        }
        
        /* TEXT-TRANSFORM - transformacja wielkości liter */
        .transform-uppercase {
            text-transform: uppercase;
        }
        
        .transform-lowercase {
            text-transform: lowercase;
        }
        
        .transform-capitalize {
            text-transform: capitalize;
        }
        
        /* LETTER-SPACING - odstępy między literami */
        .spacing-normal {
            letter-spacing: normal;
        }
        
        .spacing-wide {
            letter-spacing: 3px;
        }
        
        .spacing-tight {
            letter-spacing: -1px;
        }
        
        /* WORD-SPACING - odstępy między słowami */
        .word-spacing-wide {
            word-spacing: 10px;
        }
        
        /* TEXT-INDENT - wcięcie pierwszej linii */
        .indent-paragraph {
            text-indent: 2em;
        }

Kolory

Hex Hexadecimal #000000 kod szesnastkowy, można dodać kanał alfa czyli jego przeźroczystość #00000080

RGB/RGBA rgb(255,87,51) 0.5 0.7

HSL/HSLA format który wskazuje na 3 parametry hue saturation lightnes odcień, nasycenie, jasność; Warianty dla łatwiejszej manipulacji: Jaśniejszy L:80%, Ciemiejszy L:40% S:50% bardziej w szary

Color Keywords

tomato, red, cała gama kolorów predefiniowanych

/* HEXADECIMAL (hex) */
        .hex-full {
            background-color: #FF5733; /* Pełna forma */
        }
        
        .hex-short {
            background-color: #F53; /* Skrócona forma #FF5533 */
        }
        
        .hex-alpha {
            background-color: #FF573380; /* Z alpha (50% opacity) */
            color: black;
        }
        
        /* RGB */
        .rgb-format {
            background-color: rgb(255, 87, 51); /* RGB bez alpha */
        }
        
        .rgba-format {
            background-color: rgba(255, 87, 51, 0.5); /* RGBA z alpha */
            color: black;
        }
        
        .rgb-modern {
            background-color: rgb(255 87 51 / 0.7); /* Nowoczesna składnia */
            color: black;
        }
        
        /* HSL */
        .hsl-format {
            background-color: hsl(9, 100%, 60%); /* Hue 9°, pełne nasycenie */
        }
        
        .hsla-format {
            background-color: hsla(9, 100%, 60%, 0.5); /* Z alpha */
            color: black;
        }
        
        .hsl-modern {
            background-color: hsl(9 100% 60% / 0.7); /* Nowoczesna składnia */
            color: black;
        }
        
        /* Warianty HSL - łatwo tworzyć odcienie */
        .hsl-lighter {
            background-color: hsl(9, 100%, 80%); /* Jaśniejszy (lightness 80%) */
        }
        
        .hsl-darker {
            background-color: hsl(9, 100%, 40%); /* Ciemniejszy (lightness 40%) */
        }
        
        .hsl-desaturated {
            background-color: hsl(9, 50%, 60%); /* Mniej nasycony */
        }
        
        /* COLOR KEYWORDS */
        .keyword-named {
            background-color: tomato; /* Nazwany kolor */
        }
        
        .keyword-basic {
            background-color: red; /* Podstawowy kolor */
        }
        
        /* CURRENTCOLOR */
        .current-color-demo {
            color: blue;
            border: 3px solid currentColor; /* Border koloru tekstu */
            background-color: white;
            padding: 10px;
            margin: 10px;
        }
        
        /* TRANSPARENT */
        .transparent-demo {
            background-color: transparent; /* Przezroczyste tło */
            border: 2px solid black;
            color: black;
        }

Background

Bg color background color: #000000; padding: var

bg image background image

bg-no-repeat

bg-cover

Gradients

background: linear-gradient

background: radial-gradient

gradient multi-stop definiowany przez więcej niż dwa pkt

6 wersji kolorystycznych, tam gdzie to możliwe używać obrazków svg bo się ładnie skalują, nie trzeba używać wielu wersji, same się ogarniają, łatwo się też je styluje

można zablokować włączanie trybu ciemnego, a jeśli b chcemy by działało- należy przygotować dwie wersje

Units rozmiar w zaleznosci od np responsywnosci

 /* BACKGROUND PROPERTIES */
        .bg-color { background-color: #f0f0f0; padding: var(--spacing); }
        .bg-image { background-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100"><circle cx="50" cy="50" r="40" fill="%233498db"/></svg>'); padding: 100px; }
        .bg-no-repeat { background-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="50" height="50"><rect width="50" height="50" fill="%23e74c3c"/></svg>'); background-repeat: no-repeat; padding: 100px; }
        .bg-cover { background: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100"><circle cx="50" cy="50" r="40" fill="%2327ae60"/></svg>') no-repeat center / cover; height: 200px; }
        
        /* GRADIENTS */
        .gradient-linear { background: linear-gradient(to right, #3498db, #e74c3c); padding: var(--spacing); color: white; }
        .gradient-radial { background: radial-gradient(circle, #f39c12, #e74c3c); padding: var(--spacing); color: white; }
        .gradient-multi { background: linear-gradient(45deg, red 0%, yellow 33%, green 66%, blue 100%); padding: var(--spacing); }
        
        /* UNITS */
        .unit-px { font-size: 16px; }
        .unit-em { font-size: 1.5em; } /* 150% rodzica */
        .unit-rem { font-size: 1.5rem; } /* 150% root (24px jeśli root=16px) */
        .unit-percent { width: 50%; background: #ecf0f1; padding: 10px; }
        .unit-vw { font-size: 3vw; } /* 3% viewport width */
        .unit-vh { height: 50vh; background: #bdc3c7; } /* 50% viewport height */
        .unit-calc { width: calc(100% - 40px); background: #95a5a6; padding: 10px; }
        
        /* CSS VARIABLES */
        .with-variable { background: var(--primary); color: white; padding: var(--spacing); }
        .variable-override { --primary: #e74c3c; background: var(--primary); color: white; padding: var(--spacing); }