Computer Keyboard - Głównie JavaScript

Głównie JavaScript

by Jakub T. Jankiewicz

15 Pytań na rozmowę rekrutacyjną z CSS

Grafika wektorowa przedstawiająca osobę z laptopem i tekst CSS w klamerkach

Były już pytania rekrutacyjne z JavaScript oraz pytania z React.js, tym razem 15 pytań, jakie bym zadał na rozmowie rekrutacyjnej z CSS. Takie pytania mogłyby się pojawić na rozmowie kwalifikacyjnej na stanowisko Front-End developer. Na pewno by były któreś z tych, gdybym ja rekrutował albo weryfikował kandydata.

Na stanowisko Front-End developer mogą się pojawić też pytania z HTML (ale raczej z HTML5 np. jakieś nowe API), ale Front-End to głównie CSS i JavaScript. A oto lista pytań:

1. Czy ten kod wypełni całą stronę na czerwono?

<!DOCTYPE html>
<html>
<body>
  <div style="height:100%;background:red;"></div>
</body>
</html>

Nie, ponieważ body ma margin: 10px, więc będzie biała ramka, ale to i tak nie ma znaczenie, ponieważ wysokość body zawiera tylko kontent, dlatego jego wysokość będzie równa 0, div też będzie miał wysokość 0. W CSS wysokość 100% jest zawsze w odniesieniu do rodzica. (jeśli musimy ustawić wysokość w procentach, nigdzie w drzewie rodziców nie może być height: auto, a taka wartość jest domyślnie na każdym elemencie, włączająć to html i body).

Aby rozwiązać te problemy należy ustawić:

body,html {
  height: 100%;
}
body {
  margin: 0;
}

Co ciekawe jeśli nie użyjemy <!DOCTYPE html> czyli html5, to cała strona będzie czerwona, oprócz marginesu na body (przynajmniej w Google Chrome).

Można także zastosować jednostkę vh, które działa podobnie jak % ale odnosi się do okna przeglądarki.

<!DOCTYPE html>
<html>
<body style="margin:0">
  <div style="height:100vh;background:red;"></div>
</body>
</html>

Nie powinno się jednak stosować styli inline, czyli w HTML, który powinien zawierać samą strukturę a nie wygląd. Tutaj chciałem pokazać najprostszy przykład dlatego użyłem jednego pliku.

2. Jak wycentrować element w pionie i w poziomie

  • Można użyć wyświetlania tabelkowego, w przypadku którego działa vertical-align:
.container {
    display: table;
    text-align: center;
}
.container .item {
    display: table-cell;
    vertical-align: middle;
}
.container .item div {
    background: blue;
    display: inline;
}
  • Można użyć position: absolute + transform:
.container {
    position: relative;
}
.container .item {
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
}

left i top 50% wyrówna lewą i górną krawędź elementu .item do środka a transform: translate wyrówna do środka względem samego elementu. Zadziała to ponieważ dla pozycji 50% jest w stosunku do kontenera natomiast 50% dla transform jest w stosunku do aktualnego elementu.

  • Inne rozwiązanie to nowy flexbox:
.container {
    height: 200px;
    display: flex;
    align-items: center;
    justify-content: center;
}
.container .item {
    width: 10em;
}
  • Można też użyć:
.container {
   margin: 0 auto;
   width: 100px;
}

ale to rozwiązanie zadziała tylko dla wyrównania w poziomie, margin: auto; nie wyrówna elementu w pionie.

3. Który selektor jest silniejszy

  • #content .item ul li[data-id]
  • #content .container .item li.selected

Siła selektora określa się za pomocą kilku liczb, które określają:

  1. liczbę selektorów identyfikatorów czyli #foo,
  2. liczbę klas, selektorów atrybutów np. [data-id] lub [data-id^="1"] oraz pseudo klas, takich jak :hover,
  3. liczbę elementów oraz pseudo elementów, takich jak ::before oraz ::after, które działają także z jednym dwukropkiem.

Siły obu selektorów to odpowiednio 1 2 2 oraz 1 3 1, dlatego drugi selektor ma większą siłę ponieważ ma 3 na drugiej pozycji (1 na trzeciej nie ma już znaczenia). Jeśli oba selektory odwołują się do tego samego elementu, pobrane zostaną właściwości z tego drugiego oraz te z pierwszego, których nie ma w tym drugim.

.#content .item ul li[data-id] {
   color: red;
   background: white;
}
#content .container .item li.selected {
   background: gray;
}

Zakładając, że wszystkie elementy li mają atrybut data-id, oraz że nie ma innych reguł dla elementów li. Element li.selected, będzie miał kolor czerwony oraz tło szare, natomiast pozostałe elementy li, będą miały kolor czerwony i białe tło.

Dodatkowo są jeszcze style inline (za pomocą atrybutu style), które nadpsują właściwości z każdego selektora oraz słowo kluczowe !important (dodaje się je na końcu właściwości np. float: left !important;), które nadpisuje wszystkie właściwości włączając style inline.

4. Wymień 4 selektory, które zaznaczają element z konkretnym indeksem

  • :nth-child(1) - wybiera kolejny element
  • :nth-last-child(1) - kolejny element od końca
  • :nth-of-type(1) - kolejny element danego typu np. div:nth-of-type(1) zaznaczy pierwszy div, nawet jeśli jest przed nim header
  • :nth-last-of-type(1) - to samo co poprzednie, ale od końca

Oprócz indeksu liczbowego, można także wstawiać literę n, za pomocą której można opisać proste równania, np, 3n zaznaczy co 3 element.

5. Jak wybrać pierwsze 10 elementów na liście

Należy użyć selektora nth-child oraz równania -n+10

ul li:nth-child(-n+10) {
   background: red;
}

-n oznacza wszystkie elementy przed pierwszym, a +10 przesuwa cały zakres o 10 elementów do przodu

6. Jak zaznaczyć parzyste elementy na liście

ul li:nth-child(even) {
    background: red;
}
/* lub */
ul li:nth-child(2n) {
    background: red;
}

Dla nieparzystych trzeba użyć odd lub 2n-1.

7. Jak sprawdzić czy zmienne css (ang. custom properties) lub dowolna inna właściwość jest obsługiwana przez przeglądarkę

Można użyć reguły @support (działa w każdej przeglądarce oprócz IE, która zignoruje cały kod wewnątrz, nie działają tam także zmienne CSS)

@supports (--css: variables) {
    .item {
       color: var(--color, white);
    }
}

Nie ma znaczenia jaką zmienną i jaką wartość podamy może być np. @supports (--color: red).

Jeśli nie znasz zmiennych CSS, możesz o nich przeczytać w artykule „Zmienne CSS.

8. Jak używać zmiennych CSS z liczbowymi wartościami

Najlepiej przypisać do nich wartości bez jednostki i użyć calc do skonwertowania ich na daną jednostkę. Robi się tak ponieważ konwersja w drugą stronę jest niemożliwa:

.item.selected {
   --width: 200;
}
.item {
    width: calc(var(--width, 100) * 1px);
}

Poniższy kod też zadziała, ale jak pisałem wyżej, nie można go potem zamienić potem na inną jednostkę.

.item.selected {
   --width: 200px;
}
.item {
    width: var(--width, 100px);
}
.other {
    /* to nie zadziała */
    line-height: calc((var(--width) / 100) * 1em);
}

Jako bonus można wspomnieć, że nie można animować zmiennych CSS, ale niedługo dostępne będzie nowe API, które jest częścią specyfikacji Houdini (a dokładnie Properties & Values API), dzięki któremu będzie można animować zmienne CSS. Realizowane będzie to w ten sposób, że zmienną CSS będzie można zarejestrować i podać jej typ za pomocą funkcji CSS.registerProperty. Funkcja jest już dostępna w Google Chrome, ale działa na razie głównie z Paint API (w uproszeniu jest to API, które daje możliwość obsługi właściwości background-image, poprzez takie samo API jak to od elementu canvas).

Tutaj moje proste demko Paint API (według podlinkowanej strony powinno działać w przeglądarkach Google Chrome/Chromium oraz Opera).

Jeśli chcesz zobaczyć jak działa Paint API, oraz ciekawy trick z nim związany, przeczytaj artykuł: „JS w CSS oraz rysowanie w CSS.

9. Jak ustawić i pobrać zmienną CSS z poziomu JavaScript-u

Aby pobrać wartość, która jest ustawiona w atrybucie style, wystarczy

element.style.getPropertyValue('--zmienna');

Aby pobrać wartość, która ustawiona jest w arkuszu lub zagnieżdżona w tagu style, należy użyć tego kodu:

var style = getComputedStyle(element);
style.getPropertyValue('--zmienna');

Aby zapisać wartość do zmiennej trzeba użyć:

var zmienna = element.style.setProperty('--zmienna', 'wartość');

10. Jak utworzyć selektor atrybutu, który nie jest wrażliwy na wielkość liter

W CSS selektor atrybutu, czyli li[data-id="foo"] jest wrażliwy na wielkość liter, dlatego gdy mamy element <li data-id="Foo">, oraz selektor [data-id="foo"] to nie będzie on dopasowany do tego elementu. Aby zaznaczyć element za pomocą selektora atrybutu, bez rozróżniania wielkości liter, należy zastosować taki selektor:

li[data-id="foo" i] {
    color: blue;
}

11. Jak utworzyć sprite w CSS

Należy utworzyć obrazek, gdzie wszystkie mniejsze obrazki będą zamieszczone obok siebie w pionie lub poziomie lub w obu osiach. Następnie należy ustawić background: url(sprite.png) no-repeat; i dla każdego elementu, który powinien mieć inną ikonę obrazek zmieniać background-position.

.icon {
    background: url(sprite.png) no-repeat;
    width: 64px;
    height: 64px;
}
.icon.smile {
    background-position: -64px 0;
}
.icon.thumb-up {
    background-position: -128px 0;
}
.icon.ball {
    background-position: -192px 0;
}

W powyższym przykładzie będziemy mieli 4 obrazki w spirte-cie uszeregowane w poziomie co 64 piksele. Pierwszy obrazek nie musi mieć background-position ponieważ będzie on równy 0 0, drugim będzie smile, trzecim thumb-up a czwartym ball.

12. Zadanie: zamień tekst linku na obrazek

<a href="/" class="logo">Company</a>

Odpowiedź:

.logo {
    background: url(logo.png);
    display: block;
    width: 100px;
    height: 50px;
    text-indent: -99999em;
}

13. Jak działa model pudełkowy (ang. box model)

Model Pudełkowy CSS Źródło: Wikimedia commons autor Felix.leg Licencja CC-BY-SA

Każdy element składa się z pudełka według standardu W3C, który nie jest zaimplementowany poprawnie w starszej wersji IE. Gdy ustawia się width albo height to zmieniana jest szerokość i wysokość zawartości, do której dodawane są padding, border oraz margin. Dlatego gdy jakiekolwiek z tych wartości jest podana to szerokość i/lub wysokość pudełka będzie większa niż ustawione width i/lub height. Można to skorygować ustawiając szerokość na calc(100% - padding - border).

Można zmienić to zachowanie za pomocą właściwości box-sizing, które przyjmuje wartości content-box (domyślana) oraz border-box, która spowoduje, że width oraz height będzie zawierała całe pudełko wliczając padding i border co może być bardziej intuicyjne. (według Can I use box-sizing jest zaimplementowany we wszystkich przeglądarkach, wliczając IE8).

I na koniec jest jeszcze jedna właściwość, która nie jest częścią modelu pudełkowego, jest nią outline. Działą tak jak border, ale ramka jest rysowana na zewnątrz border, nie zmienia się też szerokości oraz wysokość pudełka (outline jest niezależne).

14. Jak przyspieszyć animacje i przejścia (ang. transitions) w CSS

Jeśli jest taka możliwość, należy animować tylko właściwości transform oraz opacity, które są mało zasobożerne jeśli chodzi o animacje. Użycie transform: translate, do przesuwania elementu na ekranie, będzie bardziej płynne od zmiany właściwości left lub top. Dzieje się tak ponieważ, przy zmianie opacity oraz transform, nie jest wykonywana operacja layoutu, czyli obliczania wszystkich styli na stronie i aplikowania ich do poszczególnych elementów.

15. Jak ustawić wysokość lub szerokość na 100% w odniesieniu do całego okna przeglądarki

Stary sposób polegałby na ustawieniu body, html na 100% oraz każdego kontenera, aż do elementu, którego wysokość lub szerokości musimy ustawić. Inny sposób jest to użycie nowych jednostek vh oraz vw,, które działają tak jak procent, ale w odniesieniu do całego okna przeglądarki.

.element {
    width: 100vw;
    height: 100vh;
}

Istnieją także jednostki vmax oraz vmin, które oznaczają większą lub mniejszą z dwóch wartości, czyli vmax ==max(width, height) oraz vmin == min(width, height).

Bonus

Warto także znać Flexboxa oraz CSS Grid, ale jeśli chodzi o mnie, to raczej bym o nie nie pytał, może tylko czy kandydat je zna i czym się różnią. A odpowiedź na to pytanie brzmi: Flexbox tworzy layout w jednym wymiarze, w kolumnie lub wierszu, natomiast CSS Grid tworzy layout w dwóch wymiarach.

Referencje:

źródło strony (aby zobaczyć kod na GitHubie, musisz kliknąć przycisk raw)
Komentarze

Hasło, które podasz umożliwi ponowne zalogowanie się i np. usunięcie komentarza, jest dobrowolne. Email jest szyfrowany i używany do wysyłania powiadomień o odpowiedziach do komentarzy oraz do pobierania awatara dzięki usłudze Gravatar.com.