Strona główna / Artykuły / Od 66% do 185px: Jak przeglądarki obliczają wartości CSS przed układem

Od 66% do 185px: Jak przeglądarki obliczają wartości CSS przed układem

Prześledź wartość CSS na wszystkich etapach: deklarowanej, kaskadowej, określonej, obliczonej, użytej i faktycznej, i zobacz, dlaczego jednostki względne oraz trik konwersji rem zachowują się w taki sposób.

1920 słów

Wygranie w hierarchii reguł nie oznacza końca procesu przetwarzania deklaracji CSS. Nawet jeśli width: 50% pokonuje wszystkie konkurencyjne reguły, przeglądarka nadal nie może przekazać wartości 50% swojemu silnikowi układu; musi najpierw określić, co dokładnie stanowi te pięćdziesiąt procent w danym kontekście, i przekształcić to wartość konkretną. Niniejszy przewodnik śledzi daną wartość na każdym etapie przetwarzania określonym w specyfikacji, pokazuje, gdzie rozstrzygane są jednostki względne takie jak rem oraz procenty, i wyjaśnia popularną sztuczkę konwersji px na rem wraz z jej ograniczeniami dotyczącymi dostępności.

Wartość, którą wpisujesz, to nie ta, która zostanie użyta

Znaczna część tego, co wpisujesz do pliku stylów, to relacja, a nie bezpośrednia miara. Szerokość może stanowić udział w przestrzeni rodzica:

width: 50%;

lub, w innej regule, inny udział:

width: 66%;

Rozmiar czcionki może być odnoszony do rozmiaru czcionki elementu korzeniowego:

font-size: 2rem;

a wysokość może stanowić ułamek rozdzielczości ekranu:

height: 50vh;

Żadna z tych wartości nie jest wyrażona w pikselach, a mimo to układ wymaga rzeczywistych wymiarów, aby określić, gdzie ma się znajdować każda ramka. Aby przezwyciężyć tę różnicę, każda wartość przechodzi przez określoną serię etapów:

Declared Value
      ↓
Cascaded Value
      ↓
Specified Value
      ↓
Computed Value
      ↓
Used Value
      ↓
Actual Value

Początkowo nazwy te wydają się żargonem, ale każdy etap odpowiada na konkretne pytanie. Poniższe sekcje omawiają je po kolei, używając jednego przykładu.

Wartość zadeklarowana: to, o co prosiłeś

Wartość zadeklarowana to po prostu wartość, jaka występuje w deklaracji. Przy założeniu:

width: 66%;

zadeklarowana wartość dla width to 66%. Jest to jedynie prośba, nic więcej. Element może mieć kilka zadeklarowanych wartości dla tej samej właściwości pochodzących z różnych reguł, więc pierwszym krokiem jest wybór jednej z nich.

Wartość kaskadowa: deklaracja, która przetrwała

Załóżmy dwa reguły, które obie ustalają szerokość akapitu. Jedna z nich używa selektora typu:

p {
  width: 100px;
}

a druga używa klasy:

.amazing {
  width: 66%;
}

Jeśli akapit ma klasę amazing, obie reguły do niego pasują. Selektor klasy jest bardziej specyficzny niż prosty selektor elementu, więc kaskada wybiera:

width: 66%;

To przetrwałe 66% to wartość kaskadowa. Ten etap jest ważny, ponieważ każdy kolejny krok działa tylko na jedynego zwycięzcę; przegrane deklaracje są odrzucane, zamiast być przetwarzane.

Wartość określona: upewnienie się, że każda właściwość ma taką wartość

Wartość określona jest wynikiem zapewnienia, że każda właściwość na każdym elemencie ma jakąś wartość. Reguła jest prosta:

  • jeśli istnieje wartość kaskadowa, staje się ona wartością określoną;
  • w przeciwnym razie, jeśli chodzi o właściwość odziedziczoną, określona wartość to obliczona wartość rodzica;
  • w przeciwnym razie jest to początkowa wartość właściwości, wartość domyślna z specyfikacji.
  • W naszym przykładzie występuje wartość kaskadowa, więc określona wartość pozostaje 66%, a ten etap wydaje się nic nie robić. Staje się to ważne dla właściwości, o których w ogóle nie wspomniano żadnej reguły – właśnie tutaj przydaje się dziedziczenie. Ten mechanizm jest omówiony w ostatniej sekcji.

    Wartość obliczona: rozwiązywanie problemów, które można rozwiązać bez układu strony

    Wartość obliczona to moment, w którym przeglądarka rozwiązuje wszystko, co może ustalić bez faktycznego układu strony. Wielkości względne oparte na rozmiarach czcionek stają się wielkościami bezwzględnymi, a słowa kluczowe są przekształcane w konkretne wartości. Rozważmy:

    font-size: 2rem;
    

    Jednostka tutaj:

    2rem
    

    Opisuje to związek typu „dwukrotność rozmiaru czcionki elementu korzeniowego”, a nie stałą wartość. Na etapie obliczeń przeglądarka sprawdza rozmiar czcionki elementu korzeniowego i przekształca tę wartość na piksele. Jeśli rozmiar czcionki elementu korzeniowego wynosi 16px, to obliczony rozmiar czcionki wyniesie 32px.

    Jednym z powodów, dla których ta konwersja następuje na tym etapie, jest dziedziczenie: wartość obliczona jest tą, którą odziedziczają elementy potomne, więc otrzymują one konkretną długość zamiast relacji, którą musiałyby ponownie interpretować w swoim własnym kontekście. Dlatego też nawarstwione rozmiary czcionki typu em działają w taki sposób, a procentowe wysokości wierszy czasami powodują ciasne ułożenie tekstu w elementach z większymi czcionkami.

    Część wartości nie może zostać jeszcze rozstrzygnięta. Szerokość w procentach zależy od rozmiaru bloku, który zawiera ją, a jego rozmiar jest znany dopiero po ustaleniu układu, dlatego 66% pozostaje zazwyczaj wartością procentową w obliczonej wartości i zostaje ostatecznie ustalony dopiero na następnym etapie.

    Użyta wartość: informacje o układzie

    Użyta wartość to wynik po uzyskaniu informacji o układzie. Wróć do:

    width: 66%;
    

    Sama w sobie wartość procentowa jest niekompletna, dopóki nie wiadomo, jaki jest jej udział w całości. W przypadku width tym odniesieniem jest szerokość bloku, który ją zawiera. Załóżmy, że sekcja nadrzędna jest:

    280px
    

    szeroka. Przeglądarka może teraz obliczyć:

    66% of 280px
    

    co daje następujący wynik:

    184.8px
    

    To wartość faktycznie użyta. To jest punkt zwrotny w procesie: przeglądarka nie przechowuje już procentu, który wpisałeś, lecz rzeczywistą wartość wynikającą z aktualnej geometrii strony. To samo dotyczy wartości takich jak szerokość auto, które mają sens dopiero po znaniu otaczającego je układu. Jeśli zapytasz element w JavaScript za pomocą getComputedStyle, wiele właściwości zależnych od układu, takich jak width, zwraca tę ustaloną wartość w pikselach, a nie procent, co jest przydatnym sposobem na obserwację tego procesu w praktyce.

    Rzeczywista wartość: dostosowanie do ograniczeń urządzenia

    Ostatni etap uwzględnia ograniczenia środowiska renderowania. Urządzenie nie musi koniecznie rysować wartości z dowolną dokładnością, więc użyta wartość może wyglądać mniej więcej tak:

    184.8px
    

    może ostatecznie zostać wyświetlona mniej więcej w ten sposób:

    185px
    

    To skorygowane wartość jest rzeczywistą wartością. W praktyce nowoczesne przeglądarki układają elementy z precyzją sub-pikselową i stosują zaokrąglanie lub dopasowanie w różnych momentach, w zależności od właściwości i silnika, więc nie należy polegać na konkretnej zasadzie zaokrąglania. Kluczowa koncepcja polega po prostu na tym, że może dojść do końcowej korekty pomiędzy obliczoną wartością a tą, która trafia na ekran.

    Gdy spojrzymy szerzej, cała ta sekwencja sprowadza się do jednego zdania: to, co zapisujemy w pliku stylów, nie musi koniecznie być tym, co ostatecznie wykorzysta przeglądarka, a pomiędzy nimi istnieją dobrze zdefiniowane etapy.

    Dlaczego jednostki względne stają się mniej tajemnicze

    To model wyjaśnia, dlaczego jednostki względne są tak cenne, a jednocześnie tak często błędnie rozumiane. Jednostki takie jak te:

    %
    rem
    em
    vh
    vw
    

    umożliwia opisywanie rozmiarów w odniesieniu do czegoś innego (kontenera, rozmiaru czcionki głównej, własnego rozmiaru czcionki elementu, obszaru widoku) zamiast używania stałych wartości w pikselach. To właśnie sprawia, że układy mogą dostosowywać się do różnych ekranów i ustawień użytkownika.

    Każda z nich musi jednak zostać rozwiązana w odniesieniu do swojego punktu odniesienia, zanim układ będzie mógł ją wykorzystać, i odbywa się to na różnych etapach: jednostki względne do czcionki – na etapie obliczeń, a procenty – w odniesieniu do bloku zawierającego – na etapie użycia. Biorąc pod uwagę ten proces, możesz zastąpić niejasną ideę, że „przeglądarka sama to rozwiązuje”, bardziej precyzyjnym pytaniem podczas debugowania: od czego zależy ta wartość i jaki jest aktualnie ten punkt odniesienia? Gdy responsywny układ zachowuje się niewłaściwie, przyczyną jest bardzo często punkt odniesienia różny od tego, co zakładałeś – na przykład procent rozwiązany w odniesieniu do nieoczekiwanego bloku zawierającego lub em kumulujący się poprzez kilka elementów wplecionych w siebie.

    Konwertowanie px na rem przy użyciu korzenia 10px

    Zrozumienie przetwarzania wartości pomaga również wyjaśnić powszechny proces dostosowywania rozmiarów: konwersję wartości pikselowych z projektu na rem. Załóżmy, że projekt określa:

    padding: 30px;
    

    a ty wolisz to przedstawić w ten sposób:

    padding: 3rem;
    

    Popularnym podejściem jest ustawienie rozmiaru czcionki korzeniowej na liczbę zaokrągloną:

    html {
      font-size: 10px;
    }
    

    Gdy to zostanie zrealizowane:

    1rem = 10px
    

    konwersje stają się prostymi obliczeniami mentalnymi:

    30px → 3rem
    40px → 4rem
    20px → 2rem
    

    Ogólnie rzecz biorąc:

    rem = pixels / 10
    

    Korzyścią nie są tylko uporządkowane liczby. Ponieważ każdy rem odnosi się do rozmiaru czcionki korzeniowej na etapie obliczeń, zmiana tej jednej wartości korzeniowej automatycznie skaluje wszystkie wymiary oparte na rem na stronie, co daje możliwość jednolitej kontroli nad systemem rozmiarów.

    Istnieje ważna uwaga. Ustawienie wartości korzeniowej na stałe 10px anuluje domyślną wielkość czcionki, którą użytkownik mógł wybrać w ustawieniach przeglądarki, co podważa jeden z głównych powodów używania rem w kwestiach dostępności. Powszechnie stosowaną alternatywą jest html { font-size: 62.5%; }: przy domyślnej wartości 16px w przeglądarce nadal otrzymujemy 10px, ale wartość ta skaluje się proporcjonalnie, gdy użytkownik zwiększa swoją preferowaną wielkość czcionki. Jeśli przyjmiesz ten model, pamiętaj również o ustawieniu czytelnej wielkości czcionki dla elementu body (na przykład 1.6rem), ponieważ w przeciwnym razie tekst przyjmie domyślną, zmniejszoną wielkość korzeniową.

    Gdy w ogóle nic nie zostało zadeklarowane

    Jedno pytanie pozostaje bez odpowiedzi po omówieniu powyższych kroków. Weźmy następujący kod:

    <div class="parent">
      <p>Hello World</p>
    </div>
    

    oraz regułę dla elementu otaczającego:

    .parent {
      color: red;
    }
    

    Nigdzie nie ma reguły w stylu:

    p {
      color: red;
    }
    

    Mimo to tekst akapitu jest czerwony. Akapit nie ma łańcuchowej wartości color, więc jego określona wartość musi pochodzić skąd indziej. Ponieważ color jest właściwością dziedziczoną, przeglądarka używa obliczonej kolorystyki elementu nadrzędnego. To właśnie jest dziedziczenie, które bezpośrednio wpływa na etap określania wartości opisany wcześniej. Aby szczegółowo zrozumieć, które właściwości są dziedziczone, dlaczego elementy potomne otrzymują wartości obliczone zamiast deklarowanych oraz w jaki sposób inherit i initial modyfikują domyślne ustawienia, dziedziczenie wymaga osobnego omówienia.

    Główne wnioski

    • Wartość CSS przechodzi przez sześć etapów: deklarowany, łańcuchowy, określony, obliczony, użyty i faktyczny.
    • Łańcuch wartości sprowadza wiele deklarowanych wartości do jednej łańcuchowej; tylko ta wygrana wartość jest dalej przetwarzana.
  • Określona wartość powraca do dziedziczenia lub wartości początkowej, jeśli nic nie zostało zadeklarowane.
  • Jednostki odnoszące się do czcionki, takie jak rem i em, stają się długościami bezwzględnymi na etapie obliczeń; szerokości procentowe czekają na ustalenie układu i są rozstrzygane w momencie użycia.
  • Rzeczywista wartość może zostać dostosowana ze względu na ograniczenia urządzenia, dlatego należy unikać polegania na dokładnym zachowaniu zaokrąglania.
  • Trik z 10px-root ułatwia konwersję na rem, ale 62.5% lepiej uwzględnia preferencje czcionkowe użytkownika niż stałe 10px.
  • Literatura pokrewna

  • Jak kaskada wybiera zwycięzcę: znaczenie, specyficzność i kolejność źródeł — Dowiedz się, jak przeglądarki rozstrzygają między sprzecznymi deklaracjami CSS, jak interpretować specyficzność jako porównanie czterech elementów oraz dlaczego reguły typu hover i !important tak często nas zaskakują.
  • Od pliku stylów do ekranu: gdzie CSS mieści się w procesie przeglądarki — Prześledź ścieżkę CSS od pobrania do pikseli: jak budowane są DOM, CSSOM i drzewo renderowania, gdzie odbywa się kaskada oraz jakie źródła stylów konkurują o każdy element.
  • Think in Invalidation: Praktyczny model tego, jak przeglądarki renderują strony — Naucz się rozumieć proces renderowania w przeglądarkach, zadając pytanie o to, co każda zmiana unieważnia, począwszy od problemów z układem i kosztu rysowania, aż po kompozycję, hydratację i strumieniowanie.
  • Pomijanie renderowania poza ekranem za pomocą content-visibility i contain-intrinsic-size — Dowiedz się, jak property content-visibility: auto zmniejsza koszt układu na długich stronach renderowanych przez serwer, dlaczego contain-intrinsic-size jest obowiązkowe oraz jak różni się od wirtualizacji.