Monthly Archive for 06.2005

Standards versus reality, part 2

Dziś o listach. Listy niesortowane (<ul/>) są najczęściej wykorzystywanym typem wyliczeń w sieci, jeśli nie liczyć bulletów wstawianych jako <img/> na początku każdego akapitu (co jest naturalnie bez sensu).

Pierwszy kłopot z listami polega na tym, że każda przeglądarka w inny sposób implementuje wcięcia. Jedne robią to za pomocą atrybutu padding, inne za pomocą margin. Jedyna uniwersalna metoda, to wyzerować jeden, a określić drugi parametr:

ul.naszaLista li
{
	margin: 0;
	padding: 2px 2px 2px 20px;
}

Druga sprawa to odległość pomiędzy bulletem, a tekstem. Teoretycznie istnieje w CSS atrybut marker-offset, ale w praktyce nie istnieje dla niego wsparcie. W związku z tym, najlepszym wyjściem jest stworzyć własny obrazek dla bulleta i zadeklarować go jako background dla elementu listy:

ul.naszaLista li
{
	background: url('img/bullet.png') no-repeat 0% 50%;
	margin: 0;
	padding: 2px 2px 2px 20px;
}

W tym wypadku lewy padding (kolejność podawania parametrów jest zdefiniowana według kierunku ruchu wskazówek zegarka - góra, prawo, dół, lewo) ustawiamy w tym przypadku na szerokość obrazka + wymaganą odległość pomiędzy obrazkiem a tekstem.

Na koniec wspomnę jeszcze, że IE ma problem z połączeniem letter-spacing i line-height. W przypadku, kiedy zostaną zadeklarowane oba, IE przestanie pokazywać co drugi znak łamania wiersza (<br/>). Wspominałem o tym w lutym, kiedy błąd został przypadkowo odkryty przez naszego klienta, który nadużywał znaczników <br/> do formatowania tekstu na stronie. Do dziś nie znaleźliśmy obejścia tego problemu, na szczęście letter-spacing jest relatywnie rzadko używany.

Standards versus reality

Przy obecnej popularności webdesignu (a raczej bycia trendy i walidacji, o czym pisałem w zeszłym miesiącu), co drugi użytkownik sieci cytuje z pamięci regułki CSS, sypie kodem (X)HTML, chwali się beztabelkowymi osiągnięciami. Często te beztabelkowce zajmują pięć razy więcej miejsca (ale przecież bandwidth is cheap) i w środku korzystają z display: table;, ale nie o tym chciałem pisać. Zajmijmy się problemami, w rozwiązaniu których standardy niewiele pomagają.

Jedną z rzeczy, którą można bardzo łatwo zaimplementować za pomocą semantycznego HTML + CSS jest układ kolumnowy. Używa się do tego dwóch elementów <div/>, z czego jeden jest floatowany do krawędzi.

<div id="navbar">
	<p>To jest menu</p>
</div>
<div id="content">
	<p>To jest treść strony</p>
</div>
#navbar
{
	margin: 0 10px;
	background-color: #69f;
	float: left;
	width: 180px;
	height: 400px;
	border: 1px solid #ccc;
}
#content
{
	width: 475px;
	border: 1px solid #ccc;
	background-color: #fff;
}

Problemy zaczynają się pod IE, który raz, że nie radzi sobie z precyzyjnym pozycjonowaniem floatów (jeśli floatowany element jest dokładnie szerokości dostępnego miejsca, to następuje złamanie wiersza, wymagany jest dwupikselowy zapas), a dwa, z nieznanych nikomu przyczyn magicznie podwaja marginesy wszystkich pływających elementów, jeśli tylko są typu block.

O ile jedynym rozwiązaniem na precyzyjne umiejscowienie dwóch kolumn jest zastąpienie obu bloków dwukolumnową tabelką, o tyle drugi problem rozwiązuje się trywialnie. Tyle, że nikt przy zdrowych zmysłach by na takie rozwiązanie nie wpadł. Należy mianowicie wymusić na przeglądarce traktowanie elementów floatowanych jako elementy typu inline. Wyjście takie wydaje się mocno abstrakcyjne i pozbawione sensu, ale działa, wobec tego ograniczymy jego skutki do jedynej słusznej przeglądarki, która obejść takich wymaga.

#navbar
{
	margin: 0 10px 0 0;
	background-color: #69f;
	float: left;
	width: 180px;
	height: 400px;
	border: 1px solid #ccc;
}
* html #navbar
{
	display: inline;
}

Trik polega na tym, że w IE nie działa właściwie nic, a przede wszystkim nie działają tam selektory CSS, z selektorem gwiazdki na czele. Powyższa konstrukcja mówi tyle, że display: inline; powinno odnosić się do wszystkich elementów o id równym navbar, zawierających się w elemencie <html/>, który ma dowolnego rodzica. Standard HTML wyraźnie precyzuje, że element główny, <html/> nie może mieć żadnego rodzica w ramach jednego dokumentu (nie dotyczy to drzewa DOM stron opartych na ramkach, ale tam CSS przypisywany jest do każdego węzła głównego i nie jest dziedziczony przez subdokumenty). IE uważa, że jest inaczej, co pozwala (przynajmniej do wersji 6.0) łatwo ukrywać workaroundy przed innymi przeglądarkami.

Oczywiście, bardziej eleganckim rozwiązaniem byłoby dodanie marginesu (równego szerokości lewej kolumny + pożądanemu odstępowi) do prawej kolumny:

#navbar
{
	background-color: #69f;
	float: left;
	width: 180px;
	height: 400px;
	border: 1px solid #ccc;
}
#content
{
	margin: 0 0 0 190px;
	width: 475px;
	border: 1px solid #ccc;
	background-color: #fff;
}

Nie rozwiązuje to jednak problemu układów bardziej skomplikowanych (gdzie stosujemy więcej niż dwie kolumny z floatem).

Drugi z częstych problemów, to zmuszenie elementów pływających do rozciągania rodzica. Weźmy pod uwagę prosty układ:

<div id="parent">
	<div id="child">
		<p>Lorem ipsum dolor sit amet
		consectetuer adipiscing elit.</p>
	</div>
	<p>Lorem ipsum, baby!</p>
</div>
#parent
{
	background: #fff;
	border: 1px solid #ccc;
	color: #000;
	padding: 5px;
}
#child
{
	background: #eee;
	border: 1px solid #ccc;
	color: #000;
	float: right;
	width: 100px;
}

Ze względu na stosunkowo długi tekst w pływającym boksie (w porównaniu do krótkiego tekstu głównego), istnieje ryzyko, że boks dziecka będzie dłuższy od boksa rodzica, co (zgodnie ze standardem) spowoduje jego wystawanie poza obiekt rodzica (nie zostanie od przedłużony). Nie jest to na ogół działanie, jakiego oczekujemy, pojawiło się więc kilka rozwiązań tej niedogodności.

Najpopularniejsze polega na wstawieniu, tuż przed tagiem zamykającym rodzica, następującego zapisu:

<br style="clear: both;">

Metoda ta ma jednak dwie wady: niepotrzebnie zaśmieca kod strony (co jest dla wielu do pominięcia) i powoduje pojawienie się zbędnego znaku złamania wiersza (co w zależności od pogody i populacji muflona, jest przez IE ignorowanie bądź nie).

Najczystsza metoda nie wymaga ingerencji w kod HTML i sprowadza się do dodania w arkuszu CSS (dla elementu rodzica) jednej linijki:

overflow: auto;

Przeglądarka od tego momentu zaczyna się interesować wystającymi elementami i elegancko przedłuży nam obiekt rodzica do wymaganego rozmiaru. Należy jednak uważać, bo gdy rodzic ma zadeklarowaną stałą wysokość, to w jego boksie pojawią się paski przewijania (uzyskamy efekt taki, jak przy elemencie <iframe/>.

Kolejny problem to wymuszenie minimalnej wysokości elementu. Najprościej byłoby napisać:

#element
{
	min-height: 300px;
}

Jest jednak przeglądarka, która w dziedzinie wspierania standardów nigdy nas nie zawiedzie. IE skrupulatnie ignoruje wszelkie zapisy tego typu. Co więcej, nieprawidłowo implementuje też atrybut height, który w IE zachowuje się właśnie jak min-height. Z pomocą przychodzi nam wspomniany wcześniej hack:

#element
{
	min-height: 300px;
}
* html #element
{
	height: 300px;
}

I kolejny problem: model boksa w IE prawidłowo został zaimplementowany dopiero w IE 6.0 i to tylko w trybie strict (w przeciwieństwie do domyślnego quirks mode). Powoduje to, że w przeglądarkach z Redmont padding nie wpływa na finalny rozmiar boksa. Innymi słowy, jeśli nasz obiekt ma szerokość zadeklarowaną na 100px i 20px paddingu z obu stron, to w IE zajmie dokładnie 100px, a na treść pozostanie 60px (po odjęciu 2x 20px), podczas gdy we wszystkich pozostałych przeglądarkach element zajmie 140px, rezerwując na treść całe (zadeklarowane w CSS) 100px.

Jeśli nie jest wymagana zgodność ze starszymi przeglądarkami (np. IE 5.5), to problem dla ciebie nie istnieje. Wystarczy zadeklarować prawidłowy DOCTYPE i wymusić przejście przeglądarki w strict mode. W biznesie webdesignowym rzadko można sobie pozwolić na tego typu uproszczenia, bo ważny jest każdy klient serwisu, niezależnie od tego, jak starej przeglądarki używa. Jedynym sensownym rozwiązaniem pozostaje symulowanie paddingu za pomocą zagnieżdżonych elementów i marginesów.

<div id="outer">
	<div id="inner">
		<p>Treść.</p>
	</div>
</div>
#outer
{
	/* padding: 5px */
}
#inner
{
	height: 100%;
	margin: 5px;
}

W zależności od popularności tego tekstu, postaram się opisać więcej błędów i problemów, póki co - czekam na komentarze.

Znikam z sieci…

…przynajmniej tymczasowo. Robiłem akurat upgrade kernela wczoraj i, przy okazji, zmieniłem w końcu Lilo na Gruba. Po restarcie maszyny przypomniałem sobie, że Grub pozostał nieskonfigurowany, ale to nie powinien być problem, bo Grub jest interaktywny. Dziarsko zabrałem się za edycję menu, boot dla testu, nie działa, powrót do menu, zapomniałem dopisać initrd, reboot i… i nic. Nie mogę wejść nawet w interaktywny tryb Gruba. Ba, nie mogę wejść do setupu BIOSu. W moim pięknym Asusie padła klawiatura, w związku z czym straciłem stanowisko pracy.

Straciłem również dostęp do kilku projektów, w tym paru BardzoWażnychRzeczy™, od których zależą moje zaliczenia na studiach. Mam nadzieję, że serwis nie przetrzyma mi go 2 tygodnie, bo wtedy będzie już po najważniejszej części sesji. Póki co, nie mam maszyny, więc i na sieci mnie nie będzie, w pracy polityka firewalla odcina mi dostęp do wszystkiego, co nie chodzi przez HTTP, a i tak serwer Joggera jest na czarnej liście.

Miasto pełne awarii

Nasza firma ma chyba pecha do awarii. Nie mamy problemu ze sprzętem, oprogramowanie działa bez zarzutu, załoga jest kompetentna i swoje prace wykonujemy sumiennie. Inni się chyba na nas uwzięli.

Firma mieści się w centrum miasta, tuż obok kina Helios, stare budownictwo, za sąsiadów mamy między innymi Techland. Obsługuje nas chyba najgorsza podstacja elektryczna w całym Wrocławiu. Regularnie, raz w miesiącu, bez ostrzeżenia pada zasilanie. Pada i leży tak przez dobre 30-40 minut.

Ludzie pracujący przy designie rwą sobie włosy z głowy na myśl o uszkodzonych plikach na dysku, serwerownia ciągnie ostatkiem sił, bo bateria UPSów wytrzymuje obciążenie przez około 15 minut. Rozdzwaniają się telefony (tak, wiemy, że poczta nie działa, to nie nasza wina). Czasem serwery nie mają kontaktu ze światem, bo z braku prądu łącze zerwie się gdzieś po drodze, szlag nas trafia. Każda taka awaria jest dla energetyki miejskiej ogromnym zaskoczeniem (a dziwnym trafem zdarzają się zawsze po 16:00), a dla nas oznacza siedzenie po godzinach w pracy i podnoszenie biednych maszynek do stanu używalności.

Tak było też i dzisiaj, biuro z Qwiatem opuściliśmy punkt 19:30. Byłoby wcześniej, gdyby wystarczyło podnieść maszyny. Problem w tym, że szef chce mieć minimalny downtime (co wychodzi zupełnie odwrotnie) i wyraźnie nakazuje ciągnąć wszystko aż do ostatecznego padu UPSów.

Magiczny klawisz SysRq

Z premedytacją robię repost, bo nie ma co się silić na oryginalność w temacie obsługi systemu, a dużo ludzi nadal nie wie, do czego służy ten zabawny klawisz na ich klawiaturach.

Całkiem spora grupa osób wykorzystuje Linuksa jako podstawowe środowisko pracy, dziwi więc fakt, że większość z nich nie zdaje sobie sprawy z istnienia tak przydatnego klawisza, jak SysRq. Oczywiście, jego przydatność do pracy z codziennymi aplikacjami jest raczej znikoma, jednak okazuje się on nieoceniony, kiedy aplikacje te zawiodą.

Jak często zdarza ci się sięgać do przycisku “reset”, kiedy jakiś pamięciożerny program zajmie cały bufor iksów i komputer przestanie reagować na jakiekolwiek klawisze? Nawet, jeśli zdarzyło ci się to tylko raz w życiu, czy nie wolałbyś uniknąć wtedy konieczności rebootowania?

Z pomocą przychodzi nam debugger jądra. Jest on uruchamiany poprzez przekazanie wartości 1 do węzła /proc/sys/kernel/sysrq i jest domyślną wartością dla większości systemów. Jeśli chcesz to zrobić ręcznie, wystarczy:

echo 1 > /proc/sys/kernel/sysrq

W PLD działanie tego klawisza można kontrolować za pomocą pliku /etc/sysctl.conf:

# Enable the magic-sysrq key
kernel.sysrq = 1

SysRq to klawisz, którego obsługi w systemie linuksowym nie może przejąć żaden proces. Każde jego przyciśnięcie (a jest wywoływany przez jednoczesne przytrzymanie Alt i PrtScr) jest przetwarzane na poziomie kernela. O ile sam SysRq nie daje nam nic, o tyle jego przytrzymanie i przyciśnięcie jegnego z pozostałych klawiszy może przynieść o wiele ciekawsze rezultaty. Pełna lista poniżej:

  • Alt+SysRq+H wyświetla pomoc. Jest to lista możliwych funkcji z wyróżnionymi literami. Każda wyróżniona litera to skrót klawiszowy, który daną funkcję wyzwala. Jest to jedyna kombinacja, którą można bezpiecznie wypróbować na sprawnym systemie.
  • Alt+SysRq+B powoduje natychmiastowy reboot systemu, bez odmontowania dysków i zapisania ich buforów. Użycie w większości przypadków zaowocuje uszkodzonym systemem plików.
  • Alt+SysRq+E wysyła sygnał TERM do wszystkich procesów z wyjątkiem procesu init, prosząc o samounicestwienie wyżej wymienionych.
  • Alt+SysRq+I wysyła sygnał KILL do wszystkich procesów z wyjątkiem procesu init, wymuszając zabicie wszystkich procesów.
  • Alt+SysRq+K wysyła sekwencję SAK. Powoduje uśmiercenie wszystkich procesów związanych z bieżącym terminalem (bądź konsolą wirtualną). Przydatne, kiedy iksy odmówią współpracy.
  • Alt+SysRq+L wysyła sygnał KILL do wszystkich procesów, z procesem init włącznie. Zabicie procesu init powoduje unieruchomienie całego systemu.
  • Alt+SysRq+M wypisuje informacje o pamięci. Przydatne tylko do debugowania.
  • Alt+SysRq+O wyłącza system, jeśli funkcja taka jest dostępna.
  • Alt+SysRq+P wypisuje na bieżącą konsolę zawartość rejestrów i flag procesora. Przydatne tylko przy debugowaniu jądra.
  • Alt+SysRq+R przełącza tryb raw klawiatury. Pozwala na wysłanie Ctrl+Alt+Del nawet jeśli zawiesi się obsługująca aktualnie klawiaturę sesja X.
  • Alt+SysRq+S wymusza synchronizację buforów dyskowych dla wszystkich zamontowanych systemów plików. Przydatne jeśli musisz wymusić reboot, a nie chcesz ryzykować niespójności danych.
  • Alt+SysRq+T powoduje wypisanie listy wszystkich zadań.
  • Alt+SysRq+U próbuje przemontować wszystkie systemy plików w trybie tylko do odczytu. Powoduje synchronizację buforów dyskowych i pomaga uniknąć sprawdzania spójności dysków przy ponownym starcie.
  • Alt+SysRq+cyfry zmienia poziom debugowania (gadatliwość kernela) w zakresie od 0 (tylko Panic i Oops) do 9.