Półprzezroczyste warstwy overlay i okienka div
08 kwietnia 2007

W erze Ajaksa otwieranie nowych okien za pomocą window.open() jest passé. Całkiem słusznie - po co rozpraszać użytkownika (i kazać mu czekać aż przeglądarka przetrawi rozkaz otwarcia okna), skoro przy pomocy prostego układu divów można zasłonić to co widzi na stronie warstwą overlay i na niej umieścić kolejną warstwę - okienko?
Tak działa sławny Lightbox otwierający obrazki albo Thickbox otwierający prawie wszystko. Tylko jest jedna rzecz, która mi się w tym nowym trendzie projektowania nie podoba - nadmierne wykorzystanie JavaScriptu. Nadmierne ponieważ 95% interfejsu potrzebnego do naszego efektu da się zbudować przy pomocy CSS.
Wyzwania
Podczas projektowania trzeba zmierzyć się z problemami:
- Czy wyświetlane okieno ma być wycentrowane? W pionie?
- Co się dzieje gdy przewijamy stronę? Czy w ogóle pozwolić nad to?
- Czy overlay zasłania całe okno, nawet jeśli treści jest malutko?
- Co się stanie gdy okieno jest wyższe niż widoczna część strony?
We wpisie opiszę wykorzystanie umiejscowienia w stałym miejscu ekranu, ponieważ z nim najwięcej jest problemów.
Overlay
Warstwa overlay musi rozciągać się nad całą stroną. Jako że będzie lewitowała nad wszystkim, jedyne co trzeba zrobić to upewnić się, że zajmuje 100% szerokości i wysokości viewportu (widocznej części strony).
Dla celów testowych dodajmy ją na końcu dokumentu. Wiadomo - w realnej aplikacji ten proces następuje w JS (albo dodawanie do DOM albo chowanie / pokazywanie).
<div id="overlay"><div id="window"><div id="inner">Some content</div></div></div>
Do #overlay wrzuciłem od razu strukturę okienka, ale o tym za chwilę. Taka struktura wymaga użycia obrazka tła dla #overlay, ponieważ zaaplikowanie opacity zwiększy przezroczystość wszystkiego w środku.
CSS umieszczający #overlay tak jak chcemy:
#overlay {position: fixed;top: 0;left: 0;width: 100%;height: 100%;background: url(overlay.png);}
Takie reguły zadziałają nawet w przypadku gdy treści jest za mało, aby wypełnić całe okno (i body będzie niższe).
Overlay a Internet Explorer 6
Co z IE6? Pisałem już jak emulować position: fixed za pomocą expression(). Dodatkowo należy określić wymiary #overlay - skopiować wymiary viewportu, które w Standards Mode są przechowywane w document.documentElement.clientWidth i .clientHeight.
#overlay {position: absolute;width: expression(document.documentElement.clientWidth + 'px');height: expression(document.documentElement.clientHeight + 'px');top: expression(offset = 0 + parseInt(document.body.currentStyle.paddingTop) + parseInt(document.body.currentStyle.marginTop),document.documentElement.scrollTop + offset + 'px');}
Pozostaje jeszcze kwestia tła, będącego półprzezroczystym plikiem PNG. Zgodnie z tym co pisałem kiedyś w temacie przezroczystości należałoby użyć filtru i rozciągnąć tło (sizingMethod="scale"). Ale nie jest to takie proste. Użycie filtru i implikacje hasLayout nie pozwalają określić typowo okienkowych stylów dla wewnętrznych divów. Przykładowo ustawienie szerokości albo wypozycjonowanie okienka na środku powoduje brak możliwości zaznaczania tekstu i klikania w linki.
Możliwe, że istnieje sposób na ominięcie tego zachowania, ale obawiam się że jedynie poprzez usunięcie poprzednich linijek CSS. Napisałem więc workaround - dodaję nową warstwę zaraz za #overlay, pozycjonuję ją w ten sam sposób, określam tło i dodaję filtr na przezroczystość.
#overlay, #ov {position: absolute; top: 0; left: 0;width: expression(document.documentElement.clientWidth + 'px');height: expression(document.documentElement.clientHeight + 'px');top: expression(offset = 0 + parseInt(document.body.currentStyle.paddingTop) + parseInt(document.body.currentStyle.marginTop),document.documentElement.scrollTop + offset + 'px');}#overlay {background: none;-ieh: expression(this.parsed ? 0 : (ov = document.createElement('div'),ov.id = 'ov',this.parentNode.insertBefore(ov, this),this.parsed = 1))}#ov {background-color: #000;filter: progid:DXImageTransform.Microsoft.Alpha(opacity=60);}
Overlay a Internet Explorer 7
Microsoft mówił nam, że poprawił działanie PNG w swojej najnowszej przeglądarce. Więc naiwnie wykasowałem linijki z filtrami i zostawiłem zgodną ze standardami deklarację tła w PNG. Misio natomiast poczęstował mnie dziesięciosekundowym renderowaniem strony i zwiechami podczas zmiany rozmiaru okna. Jest to kolejny dowód, że PNG nie zostało poprawione tylko brutalnie pohakowane. Ech.
Mimo wszystko CSS dla IE7 jest trochę lżejszy, ponieważ wspiera position: fixed. Nie ma żadnych problemów z określeniem width i height na 100%.
Okno
Okno postanowiłem wypozycjonować na środku ekranu. O centrowaniu też już pisałem, więc krótkie przypomnienie:
W poziomie centrujemy określając szerokość i dając lewy i prawy margines na
auto.W pionie centrujemy nadając wyświetlanie tabelkowe i korzystając z
vertical-align.
#overlay {display: table;}#overlay #window {display: table-cell;vertical-align: middle;}#overlay #inner {width: 50%;margin: 0 auto;padding: 15px;background-color: #fff;}
Należy jeszcze ograniczyć wysokość takiego okienka, aby zbyt duża ilość zawartości nie zniknęła poza ekranem.
#overlay #inner {max-height: 350px;overflow: auto;}
Okno a Internet Explorer
Centrowanie w pionie dla IE6 i 7:
#overlay #window {position: absolute;top: 50%;}#overlay #inner {position: relative;top: -50%;}
Max-height dla IE6:
#overlay #inner {height: expression(this.scrollHeight > 350 ? '350px' : 'auto' );}
Podsumowanie
Gdyby istniała potrzeba dopasowania do wysokości viewportu to niestety procenty nie zadziałają - można zastosować JavaScript. Dodatkowo w celach estetycznych można też ukryć scrollbar strony (przydatne zwłaszcza dla IE):
html, body {overflow: hidden;overflow-x: auto;overflow-y: hidden}
Skończone demo.
Generalnie takie ekrany włączamy przez JavaScript - dlaczego więc nie dodać paru zdarzeń dla window.resize/scroll i zapomnieć o CSS? Z jednego ważnego powodu - CSS jest wydajniejszy i szybszy - sprawdźcie jak żabkuje obrazek utrzymywany w stałym miejscu ekranu w Thickboksie.
Dodam też, że opisany przykład nie jest tylko dywagowaniem teoretyka - takie okienka z powodzeniem można stosować na stronach, głównie dzięki działaniu na IE. Nowy frontend Joggera (jeszcze na warsztacie ;)) takie okienka wykorzystuje.


