Kawałek Kodu

Rzadko poruszamy się po tematach mainstreamowych w dziedzinie programowania, a dziś idziemy jeszcze dalej. Wpis schodzi na drugi plan. Pogadamy o elemencie, który odgrywa ważną rolę, pomimo, że zawsze chowa się za plecami swojego rodzica.

Oklepany scenariusz.

Byłbym zapomniał. Będzie o elemencie overlay. Czyli półprzezroczystej warstwie, którą najczęściej używa się jako tło przykrywające stronę podczas pokazywania jakiegoś wyskakującego okienka z komunikatem, powiększenia zdjęcia, czy zwizualizowania ładowania czegoś w tle. Zazwyczaj wykreowany jest z odrębnego elementu z użyciem JS, w momencie tworzenia samego rodzica. Ale nie zawsze używamy JS do tworzenia rodzica, więc i overlay możemy utworzyć bez angażowania skryptów.

Nowi aktorzy.

Skoro w JS tworzymy warstwę z odrębnego elementu, to w CSS narzuca się rozwiązanie z użyciem pseudoelementu. Zacznijmy od kodu HTML:

<div>Okienko z informacją</div>

i pierwszego CSS:

/* okienko */
div {
  position: fixed;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  max-width: 80%;
  height: 250px;
  width: 400px;
  background: #ee7101;
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* overlay */
div:before {
  content: "";
  position: fixed;
  left: 50%;
  top: 50%;
  width: 100vw;
  height: 100vh;
  background: rgba(0, 0, 0, 0.25);
  transform: translate(-50%, -50%);
  z-index: -1;
}

Otrzymamy:

Jak widać nie jest to do końca oczekiwany efekt, bo overlay zamiast schować się za rodzica, czyli okienko, schował się zaledwie za tekst w okienku. Pomimo, że nadaliśmy ujemny z-index (rodzic ma domyślnie z-index:0), to pseudoelement jako dziecko rodzica nie schowa się pod nim. W tym przypadku ujemny z-index przesunał overlay na warstwę niższą od węzła tekstowego. Nazwa pseudoelementu może sugerować, że jest on umieszczany przed (lub za) elementem, ale tak nie jest, jest nadal w środku. Być może trafniejszym nazewnictwem byłoby start i end.

Aby poprawić to rozwiązanie mamy dwa sposoby. Jednym z nich jest przeniesienie cech wizualnych z rodzica na element potomny. Dodamy element P, aby napędzić stracha overlay i ten schował się wreszcie za rodzica. HTML będzie więc taki:

<div><p>Okienko z informacją</p></div>

a CSS:

/* kontener dla okienka */
div {
  position: fixed;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  max-width: 80%;
  height: 250px;
  width: 400px;
}

/* tu mamy okienko */
div p {
  background: #ee7101;
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  margin: 0;
}
/* overlay */
div:before {
  content: "";
  width: 100vw;
  height: 100vh;
  position: fixed;
  left: 50%;
  top: 50%;
  background: rgba(0, 0, 0, 0.25);
  transform: translate(-50%, -50%);
  z-index: -1;
}

Tym razem pseudoelement i element P są dziećmi DIV, a pseudoelement ma niższy z-index, więc wskoczy pod P, co da efekt chowania się za całym okienkiem. Będzie nadal nad elementem DIV, ale teraz nas to nie interesuje, bo ten służy tylko jako kontener do wypozycjonowania P.

Drugie rozwiązanie to trochę taki z-index hack. Od tej pory element P nie będzie potrzebny, więc można wykorzystać kod HTML z początku wpisu. W CSS natomiast nie używamy właściwości z-index. Użyjemy translacji w osi Z (w przestrzeni 3D). Translacja w tej osi powoduje przesuwanie elementu bliżej lub dalej punktu (0,0,0) - przesuwamy bliżej lub dalej oczu użytkownika.

/* okienko */
div {
/* poprzednie właściwości +
   ustalamy, że będziemy generować
   nasz element i potomne
   w przestrzeni 3d
*/
  transform-style: preserve-3d;
}

/* overlay */
div:before {
/* poprzednie właściwości bez
   z-index, ale z translacją 3d
*/
  transform: translate3D(-50%, -50%, -1px);
}

Przesuwając w osi X oraz Y środkujemy element na ekranie, czyli tak jak do tej pory, ale przesuwając o 1px w tył w osi Z, overlay chowa się za okienkiem.

Drugoplanowe role poboczne.

Nie tylko te dwa rozwiązania ułatwiają tworzenie overlay. Można jeszcze obyć się bez pseudoelementów. Warstwa nie musi wypełniać przestrzeni pod okienkiem, bo przecież i tak jej tam nie widać. Skoro tak, to pewnie już wyczuwasz, że może to być np. właściwość border. Rzeczywiście tak jest. Tak jak wspomniałem obędziemy się bez dodatkowego elementu P. Nie będzie już potrzebny również z-index. CSS tym razem jest taki:

/* okienko */
div {
/* poprzednie cechy +
   border
*/
  border: 100vw solid rgba(0, 0, 0, 0.25);
  background-clip: padding-box;
}

Dlaczego tło jest docięte do granic padding-box? Ponieważ overlay (border) jest półprzezroczysty, to bez tej właściwości pomarańczowe tło okienka byłoby widać również pod overlay. W tym przypadku efekt byłby taki, że overlay miałby kolor ciemnopomarańczowy (półprzezroczysty czarny zmieszany z pomarańczowym tłem). Używając background-clip z taką wartością, ucinamy tło w momencie skończenia granic padding. Border jest poza padding, więc overlay działa samodzielnie. Szerokość border została dobrana eksperymentalnie, z zapasem. Może się jednak okazać, że overlay nie przykryje całego tła. Stałoby się tak gdyby ekran miał kilkukrotnie większą wysokość niż szerokość (bardzo długi układ portrait).

Najbliższą właściwością border jest box-shadow, którą być może używałeś czasem w zastępstwie border. A skoro używamy border jako overlay, to możemy użyć i box-shadow.

/* okienko */
div {
/* poprzednie cechy +
   box-shadow
*/
  box-shadow: 0px 0px 0px 100vw rgba(0, 0, 0, 0.25);
}

I jeszcze jedno rozwiązanie, chyba najmniej typowe. Być może pamiętasz o elemencie outline, który zachowuje się podobnie do box-shadow, ale nie ma możliwości ustalania rozmycia? No właśnie. Rozmycie nam nie jest potrzebne, więc:

/* okienko */
div {
/* poprzednie cechy +
   outline
*/
  outline: 100vw solid rgba(0, 0, 0, 0.25);
}

W następnym wpisie postaram się, aby głównego tematu nie zdominował jakiś cwaniaczek! Do przeczytania.

 

Przydatne linki:
Overlay z użyciem pseudoelementu i z-index.
Overlay z użyciem pseudoelementu i translacji 3d.
Overlay z użyciem border.
Overlay z użyciem box-shadow.
Overlay z użyciem outline.