Expressions - poprawki błędów CSS w IE
14 stycznia 2007
W poprzednim poście opisałem expression() w teoretyczny sposób, skupiając się na składni, zasadach i ograniczeniach. Dzisiaj chciałbym pokazać jak niesamowicie przydatne są te małe kawałki kodu - na przykładzie poprawek paru najbardziej frustrujących błędów i braków implementacji CSS Explorera.
Wstęp
Zanim przejdę do meritum, chciałbym zaznaczyć, że napisany przeze mnie kod działa w trybie zgodności ze standardami - co oznacza IE6 / IE7 z odpowiednim DOCTYPE (więcej na ten temat). IE5 i IE6 w quirksmode umieją expressions, ale należy korzystać z innych metod DOM i uważać na większe ograniczenia CSS (np.: border box model).
Można też utyskiwać, że expressions nie są ostatecznym rozwiązaniem błędów Explorera, bo wymagają włączonego JavaScript do działania. Moja odpowiedź jest bardzo prosta - jeśli użytkownik wyłącza sobie JS to musi wiedzieć co robi. Przeważająca większość szaraczków tego nie robi i aby serwować im ładne i lekkie strony należy jakoś poprawić zachowanie ich zabugowanej przeglądarki. Quid pro quo.
First-child
-ie-xp: expression(this.parsed ? 0 : (this.className = (this === this.parentNode.firstChild) ? "first-child" : "",this.parsed = 1));
Przykład wykorzystania. Obejrzyj źródło, aby przejrzeć wykorzystany kod.
W tym kodzie wykorzystujemy operator wyrażenia warunkowego, aby sprawdzić czy obiekt this jest taki sam jak firstChild rodzica. Jeśli tak to dodajemy mu klasę first-child, którą możemy wykorzystać później w grupowaniu selektorów i aplikowaniu CSS.
Update: Poprawka dodająca klasę: this.className += …… " first-child".
Cudzysłowy w q
Internet Explorer ma niepełną obsługę elementu q odpowiadającego za cytat wtrącany - nie pojawiają się żadne cudzysłowy, więc nie można stwierdzić bez patrzenia w kod czy ktoś kogoś cytuje.
Podany niżej kod wstawi cudzysłowy angielskie, które nota bene są domyślne dla większości nowoczesnych przeglądarek, także tych zlokalizowanych. Istnieje nawet kod pomagający uzyskać odpowiednie znaki po zagnieżdżeniu tych elementów.
q {-ie-xp: expression(this.parse ? 0 : ((bugFix = this.insertAdjacentText("afterBegin", "\201C")),this.insertAdjacentText("beforeEnd", "\201D"),this.parse = 1));}q q {-ie-xp: expression(this.parseNested ? 0 : ((bugFix = this.insertAdjacentText("afterBegin", "\2018")),this.insertAdjacentText("beforeEnd", "\2019"),this.parseNested = 1));}
Wykorzystujemy tutaj metodę insertAdjacentText - z parametrem afterBegin wstawiamy tekst w elemencie przed wszystkim innym a z parametrem beforeEnd za wszystkim w środku. Jest to taka pseudo generowana treść, ale operująca tylko na tekście. Nie mamy możliwości stylowania wstawionego kawałka. Zmienna bugFix pomaga zwalczyć błąd expression (nawet tu są błędy, wszakże to jest IE).
Generowana zawartość - ::before
Zawsze mnie zastanawiało, czy separatory, używane przykładowo w linkach w stopce są zawartością czy tylko prezentacją. Można je wstawiać jako obrazki teł, ale pomyślałem, że można też to zrobić via GC. No bo czy nie denerwuje Was "<span>|</span>" na końcu każdego li?
-ie-xp: expression(this.parse ? 0 : (isFirst = (this === this.parentNode.firstChild) ? 0 : (separator = document.createElement('span'),textnode = document.createTextNode('\2022'),separator.appendChild(textnode),separator.className = "before",this.insertBefore(separator, this.firstChild),this.parse = 1)));
Wykorzystujemy więc sposób na first-child, aby pominąć pierwszy element (chcemy tylko punktory między linkami), tworzymy element, nadajemy mu klasę (grupowanie z prawdziwym GC) i wstawiamy przez insertBefore przed pierwszy element w li (this.firstChild).
Wypozycjonowanie w stałym miejscu ekranu
Aby umieścić coś na stronie za pomocą position: fixed w IE6 należy skorzystać z position: absolute i hacka podstawiającego stale aktualizowane wartości do top.
body { background: url(hack) fixed; }#above, #below { position: absolute; }#above {top: expression(offset = 0 + parseInt(document.body.currentStyle.paddingTop) + parseInt(document.body.currentStyle.marginTop),document.documentElement.scrollTop + offset + 'px')}#below {top: expression(offset = 0 + parseInt(document.body.currentStyle.paddingBottom) + parseInt(document.body.currentStyle.marginBottom),document.documentElement.clientHeight - this.offsetHeight - offset + document.documentElement.scrollTop + 'px');}
W tym fragmencie kodu dodałem offset, który sprawdza, czy body ma jakiś margines bądź padding i jeśli tak odsuwa element o taką wysokość od krawędzi ekranu. Tak się to właśnie dzieje, gdy podamy top: 0 w kodzie zgodnym ze standardami.
Kod równoznaczny z bottom: 0 to po prostu wysokość okna minus wysokość pozycjonowanego elementu minus wspomniany offset. Całość nie drga podczas scrollowania dzięki ustawieniu background-attachment: fixed na body. Ja podałem jak zawsze fake'owy ciąg znaków, ale możecie tam dać jakiś przezroczysty GIF.
Min/max-width szerokość layoutu - revisited
O sposobie na IE6 i max-width już pisałem, ale teraz rozszerzyłem podany kod, aby uwzględniał także min-width oraz nie sypał się, gdy ustawimy padding / obramowanie na body albo nasz layout.
-ie-xp: expression(this.style.borderWidth = (this.currentStyle.borderWidth == "medium") ? "0" : this.style.borderWidth,bodyInnerWidth = document.body.clientWidth -parseInt(document.body.currentStyle.paddingLeft) -parseInt(document.body.currentStyle.paddingRight) -parseInt(document.body.currentStyle.marginLeft) -parseInt(document.body.currentStyle.marginRight) -parseInt(this.currentStyle.paddingLeft) -parseInt(this.currentStyle.paddingRight) -parseInt(this.currentStyle.borderLeftWidth) -parseInt(this.currentStyle.borderRightWidth),this.style.width = (bodyInnerWidth < 401) ? "400px" : (bodyInnerWidth > 701 ? "700px" : "auto" ))
Pierwsze linijki wykonują sprawdzenie wspomnianych przeszkadzajek layoutu - obramowanie, marginesy i dopełnienia. Później następuje sprawdzenie szerokości ekranu i przypisanie na sztywno określonych wartości. Pierwsza wartość to min-width, następna max-width. Warunek zawsze musi zawierać wartość o jeden większą od żądanej (400px - w warunku musi być 401), inaczej IE polegnie.
Gdzie szukać więcej informacji:
MSDN - skarbnica wiedzy na temat CSS i DOM używanego w Explorerze - pełnego niestandardowych rozszerzeń, które przydają się podczas walki z błędami.
IE7 - biblioteka JavaScript niwelująca przepaść między IE a resztą świata, dewelopowana przez Deana Edwardsa - jej działanie opiera się na dodawaniu expressions za pomocą
setExpression()- metody nie poruszanej przeze mnie ze względu na preferencje trzymania wszystkiego w plikach CSS. Mimo, że nigdy jej nie użyłem, to niewątpilwie można znaleźć tam dużo hacków na dziwactwa IE.How to Create - autor strony napisał serię artykułów o tym jak zabrać się do poprawek IE. Uwzględnia nawet najstarsze wersje przeglądarek, więc tam można się udać po pomoc odnośnie IE5.







