luq techblog

o tworzeniu słów kilka…

CSS idealny cross-browser 4 czerwca 2010

Filed under: CSS,JS,PHP,Web — Łukasz @ 23:06
Tags: , , ,

Jako nie-frontendowiec zawsze przeraża mnie pisanie styli cross-browser, nie znam na tyle co jaka przeglądarka interpretuje, co gdzie nie działa i jakim sprytnym sposobem to rozwiązać, żeby na reszcie przeglądarek się nie posypało. Idealnym wyjściem byłoby chyba pisanie css`a dla każdej przeglądarki z osobna, no może nie tak całkiem tak dla każdej z osobna…

 

Czy nie fajnym sposobem byłoby pisanie stron internetowych w ten sposób:

index.html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xml:lang="en" lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
	<link href="./style/style.php" rel="stylesheet" type="text/css" />
	
	<script type="text/javascript" src="./js/jquery-1.3.2.min.js"></script>
	<script type="text/javascript" src="./style/script_style.php"></script>
</head>
<body>
	<div id="foo">
		Lorem ipsum dolor sit amet, consectetur adipisicing elit. Proin nibh augue, suscipit a, scelerisque sed, lacinia in, mi. Cras vel lorem. Etiam pellentesque aliquet tellus. Phasellus pharetra nulla ac diam. Quisque semper justo at risus. Donec venenatis, turpis vel hendrerit interdum, dui ligula ultricies purus, sed posuere libero dui id orci. Nam congue, pede vitae dapibus aliquet, elit magna vulputate arcu, vel tempus metus leo non est. Etiam sit amet lectus quis est congue mollis. Phasellus congue lacus eget neque. Phasellus ornare, ante vitae consectetuer consequat, purus sapien ultricies dolor, et mollis pede metus eget nisi. Praesent sodales velit quis augue. Cras suscipit, urna at aliquam rhoncus, urna quam viverra nisi, in interdum massa nibh nec erat.
	</div>
</body>
</html>

wybieraniem odpowiedniego pliku styli zajmuje się plik style.php

style.php

<?php
	header('Content-type: text/css');
	
	$userAgent = $_SERVER['HTTP_USER_AGENT'];
	
	include './all.css';
	if( strpos( $userAgent, 'Firefox' ) !== false ){
		include './firefox.css';
	}
	elseif( strpos( $userAgent, 'IE' ) !== false ){
		include './ie.css';
	}
	else{
		include './default.css';
	}
?>

Oczywiście skrypt rozpoznania przeglądarki jest prościutki i docelowo nie powinien tak wyglądać, powinny być rozpoznane wersje przeglądarek etc… Chce przedstawić tylko samą idee. Docelowo mamy stworzyć stronę gdzie tłem jest obrazek a wyświetlany jest div z przezroczystością ustawioną na 40%, ma mieć zaokrąglone rogi i ustawioną ramkę wokół.
Na razie nie zajmujmy się Internet Explorerem.

all.css

body { 
	background-image: url(../gfx/background.jpg);
	font-family: verdana;
	font-size: 10px; 
	margin: 0;
	padding: 0;
}

#foo  {
	margin: 0 auto;
	margin-top: 300px;
	width: 300px;
	background-color: #6b743b;
	padding: 5px;
	color: #fff;
	border: 2px solid #2d3119;
	text-align: justify;
}

firefox.css

#foo {
	opacity: 0.4;
	-moz-border-radius: 5px;
}

default.css

#foo {
	opacity: 0.4;
	border-radius: 5px;
}

Co nam to daje? W Firefoxie w wersji 3.6.3 nie jest poprawnie interpretowana właściwość border-radius która jest zawarta w specyfikacji CSS3. Możemy oczywiście napisać dla wszystkich przeglądarek:

#foo {
	opacity: 0.4;
	-moz-border-radius: 5px;
	border-radius: 5px;
}

i zarówno na Firefox`ie jak i Chrome`ei (który w tym przypadku trzymie się standardu) będzie wyglądało jak należy, natomiast pod każdą przeglądarką walidując ten kod otrzymamy błąd, bo w standardzie właściwość -moz-border-radius nie istnieje. Więc dlaczego nie zrobić tak, żeby błędny (wg. standardu) kod CSS był przekazywany tylko tam gdzie to niezbędne do prawidłowego działania? Dzięki sposobowi który zaprezentowałem wyżej pod Firefox`em otrzymamy:

body { 
	background-image: url(../gfx/background.jpg);
	font-family: verdana;
	font-size: 10px; 
	margin: 0;
	padding: 0;
}

#foo  {
	margin: 0 auto;
	margin-top: 300px;
	width: 300px;
	background-color: #6b743b;
	padding: 5px;
	color: #fff;
	border: 2px solid #2d3119;
	text-align: justify;
}

#foo {
	opacity: 0.4;
	-moz-border-radius: 5px;
}

co jest równe 1 błędowi:

Właściwość -moz-border-radius nie istnieje : 5px  5px 

natomiast pod Chromem (v 5.0.375.55) otrzymamy w pełni zgodny kod:

body { 
	background-image: url(../gfx/background.jpg);
	font-family: verdana;
	font-size: 10px; 
	margin: 0;
	padding: 0;
}

#foo  {
	margin: 0 auto;
	margin-top: 300px;
	width: 300px;
	background-color: #6b743b;
	padding: 5px;
	color: #fff;
	border: 2px solid #2d3119;
	text-align: justify;
}

#foo {
	opacity: 0.4;
	border-radius: 5px;
}

Natomiast z IE7 już są większe problemy. Jeszcze w dość prosty sposób można ominąć brak opacity (używając filter:alpha(opacity=X)), ale uzyskanie zaokrąglanych rogów to już jest wyczyn. Możemy zrobić sobie obrazki rogów (albo dolnej i górnej belki, ew. lewy i prawy bok) jednak IE7 ma problem z wyświetlaniem przezroczystych obrazków .png. Można by pomyśleć o rozwiązaniu skryptowym w JavaScript`cie – jQuery Corner ale tutaj przy obrazku w tle dostajemy zaokrąglone rogi ale ta przestrzeń zaokrąglona pozostaje biała… Ja to próbowałem rozwiązać po swojemu i nie wyszło to idealnie ale też nie najgorzej.

 

Jak może ktoś zauważył index.html dołącza poza frameworkiem jQuery plik script_style.php

<?php
	header('Content-type: text/javascript');
	
	$userAgent = $_SERVER['HTTP_USER_AGENT'];
	
	include './all.js';
	if( strpos( $userAgent, 'Firefox' ) !== false ){
		include './firefox.js';
	}
	elseif( strpos( $userAgent, 'IE' ) !== false ){
		include './ie.js';
	}
	else{
		include './default.js';
	}
?>

Czyli to samo co mieliśmy wcześniej tyle tylko, że dla plików .js a nie .css.

 

all.js, firefox.js oraz defalut.js pozostają puste dla tego przykładu, natomiast ie.js prezentuję się tak:

$(document).ready(function(){
	var text = $('#foo').text();
	$('#foo').text('');
	
	$('#foo').prepend( '<div id="foo_top"></div><div id="foo_container">' + text + '</div>' );
	$('#foo').append( '<div id="foo_bottom"></div>' );
});

tj. przekształca nam nasz div o id=foo w:

 
<div id="foo">
    <div id="foo_top"></div>
    <div id="foo_container">
		Lorem ipsum dolor sit amet, consectetur adipisicing elit. Proin nibh augue, suscipit a, scelerisque sed, lacinia in, mi. Cras vel lorem. Etiam pellentesque aliquet tellus. Phasellus pharetra nulla ac diam. Quisque semper justo at risus. Donec venenatis, turpis vel hendrerit interdum, dui ligula ultricies purus, sed posuere libero dui id orci. Nam congue, pede vitae dapibus aliquet, elit magna vulputate arcu, vel tempus metus leo non est. Etiam sit amet lectus quis est congue mollis. Phasellus congue lacus eget neque. Phasellus ornare, ante vitae consectetuer consequat, purus sapien ultricies dolor, et mollis pede metus eget nisi. Praesent sodales velit quis augue. Cras suscipit, urna at aliquam rhoncus, urna quam viverra nisi, in interdum massa nibh nec erat.
    </div>
    <div id="foo_bottom"></div>
</div>

dokładamy do tego ie.css

 
#foo {
	filter:alpha(opacity=40);
	padding: 0px;
	width: 310px;
	border: 0px;
}

#foo_top, #foo_bottom {
	width: 310px;
	height: 5px;
	background-color: transparent;
}

#foo_top {
	background-image: url(../gfx/top.png); 
}

#foo_bottom {
	background-image: url(../gfx/bottom.png); 
}

#foo_container {
	background-color: #6b743b;
	padding: 0 5px;
	border-left:  2px solid #2d3119;
	border-right:  2px solid #2d3119;
}

dzięki temu, w odróżnieniu od jQuery Corner pozostałość po zaokrąglonych rogach zostaje wypełniona przez kolor wypełniający wnętrze #foo przezroczysty w 40%. Wszystko działałoby okej gdyby nie brak implementacji background-color: transparent w IE7. I jak tu się nie zirytować?! Btw. jak ktoś potrafi rozwiązać ten problem to ja chętnie zobaczę jak :)

 

I tutaj ukazuje się większy plus takiego rozwiązania. Jeśli chcielibyśmy we wszystkich przeglądarkach mieć zaokrąglone rogi musielibyśmy uciekać się do rozwiązania skryptowego, co raz: zabiera nam transfer bo ładowany jest jakiś plik z kodem pluginu czy jakiś nasz skrypt, dwa: spowalnia maszyny klientów (bo te operacje są wykonywane u nich) ofc. to jest chwila i tego nikt nie dostrzeże, ale zawsze. Można też zrobić obrazki rogów i wpakować je w szablon, ale dlaczego jeśli większość nowoczesnych przeglądarek obsługuje w taki czy inny sposób border-radius? Dzięki takiemu rozwiązaniu takie „dziadostwo” jest tworzone tylko na dziadowskich przeglądarkach.

 

Można dodać też inne zastosowanie, np. inny szablon na każdy dzień, szablon zależny od pogody czy godziny (można by dodać w js`ie pobieranie szablonu co X czasu tak co by user pozostawiając w zakładce stronę przez kilka godzin nie zdziwił się potem po jej przeładowaniu…)

 

Przykład wykonany do tego wpisu można oglądać tutaj

 

2 Responses to “CSS idealny cross-browser”

  1. Witaj @luq,
    tak ogólnie mówiąc teraz wprowadzany jest HTML 5 – o wiele mniej kodu niż ze standardem – strict. Tak samo CSS 3, świetnie się razem komponują. A tak jak wspomniałeś CSS 3 ma teraz możliwość stworzenia zaokrąglonych rogów. Czytałem, że IE nie będzie czytało w ogóle 3-ki, ja się nawet cieszę. Oby wycofali IE z rynku … Co do przeźroczystości … może PNG FIX. W necie i tak nie ma profesjonalnego narzędzia, który by to usunęło.

    Pozdrawiam,
    Dariusz Sajdak

  2. luq Says:

    Hej,

    o wiele mniej kodu mówisz? Nie bardzo rozumiem o co Ci chodzi, o zamiast flashowej wtyczki etc.? Co do IE9 to jasne, że nie odrzucą całkowicie standardu CSS3, to byłby strzał w kolano… Nie wiem gdzie to wyczytałeś ale dementuje. To by strasznie pogrążyło Microsoft ze swoim IE, który już i tak zdaje sobie sprawę, że nie mam monopolki na rynku przeglądarek. Co do jakiegoś modyfikatora .png to próbowałem jakiegoś programu, jednak nie dało mi to rezultatów, próbowałem też jakiejś wtyczki VML`owej w sumie nie pamiętam czy to VML był, ogólnie próbowałem mnóstwem sposobów jednak wszystko na nic, ale ja jam frotendowcem nie jestem więc się nie przejmuje za bardzo ;P


Dodaj komentarz