Perfection or Vanity

Project: Terminated

Blog nie jest już dalej prowadzony ani aktualizowany. Mimo tego, wpisy i komentarze są dalej dostępne. Możesz przeczytać pożegnalny wpis albo przejść do archiwum.

Wyobraźmy sobie, że budujemy listę odnośników (dajmy na to menu), której wypunktowania są obrazkami. Po najechaniu myszką na link obrazek zmienia się na inny, dodając interaktywności stronie.

Pokazanie obrazka tła w CSS dla stanu :hover występuje z opóźnieniem, ponieważ przeglądarka nie ściąga tych, które nie są używane. Co przekłada się na zniknięcie jakiejkolwiek ikonki. Wygląda to według mnie nieprofesjonalnie. Co więcej - istnieje kilka sposobów, aby podobnego zachowania uniknąć.

Na początku wypada sprecyzować dwie rzeczy. Nie mam zamiaru wykorzystywać list-style-image oraz li:hover.

Wypunktowanie graficzne ustawione przez list-style-image powinno pokazać się przy pierwszej linijce tekstu takiej pozycji. Jednak przeglądarki różnie ustawiają odstęp takiego obrazka względem tekstu:

Interpretacja list-style-image: Opera 9, IE 6 i 7, Firefox 2

Stan :hover będę wykorzystywał tylko razem z linkiem. Powody są dwa. Pierwszy to Internet Explorer 6 i wsparcie dla tej pseudoklasy tylko na hiperłączach. Drugi to kwestia użyteczności. Użytkownik chce kliknąć na link = tekst, więc po najechaniu na niego myszką powinna się zapalić ikonka. Podmiana ikony po najechaniu na nią samą (na wystającą część li) wskazuje, że kliknięcie przeniesie nas dalej. Błąd, bo nie przeniesie - klikamy na li.

Przejdźmy jednak do rzeczy. Udało mi się wypracować trzy sposoby osiągnięcia założenia z początkowych akapitów.

1. Warstwy

Mimo, że metoda warstw wykorzystuje oddzielne obrazki, nie występuje żadne widoczne opóźnienie. Użytkownik jest przyzwyczajony, że obrazki teł doładowują się po wczytaniu strony - jedyne czego nie chcę to wspomnianego laga.

Określam metodę warstwami, ponieważ ustawiłem jedno tło dla li i drugie dla a. Przez odpowiednie manipulowanie odstępem obrazki są jeden nad drugim. Najechanie myszką na link resetuje background i widać tło pozycji listy.

Demo. Odstęp pionowy dla obrazków ustawiłem przez emy, zapewniając trochę lepszy wygląd po zwiększeniu rozmiaru tekstu, w odróżnieniu od pikseli. Proszę pamiętać, że nie można po prostu wstawić 50% albo center. Wtedy ostatnia, wielolinijkowa pozycja miałaby marker w dziwnym miejscu.

Aby pokazać markery w sposób, jakiego byśmy oczekiwali po list-style-position: outside, musiałem nadać im wyświetlanie blokowe. Okej, ale co gdy nie chcesz aby 100% szerokości pozycji menu było klikalne? Użyłem float i dodałem trochę CSS, aby zapanować nad nowym układem. Demo - popatrz w kod, aby prześledzić zmiany.

2. Ujemna pozycja

Technika znana z CSS Rollovers. Sklejamy obrazek w jeden, aby po najechaniu na niego myszką przesunąć o ujemną wartość pikseli, pokazując jego drugą część.

W przypadku listy napotykamy jednak problemy. Użytkownik może dowolnie powiększyć tekst, bądź jego ustawienia ekranu / przeglądarki mogą wymusić przełamanie linii. Metoda ta wymaga przygotowania dość długich obrazków, z zapasem miejsca.

Dużo zależy też od typu listy, którą budujemy. Jeśli wiemy, że szerokość menu jest ograniczona - wykorzystajmy przesuwanie w poziomie. Demo.

Jeśli natomiast jesteśmy pewni, że mała ilość tekstu w linkach nie ma szans wpłynąć na wysokość pozycji listy - użyjmy przesuwania pionowego. Demo.

Wartość przesunięcia to szerokość albo wysokość obrazka minus szerokość albo wysokość ikony. Jeśli chcemy wyrównać ją pionowo do tekstu, należy jeszcze odjąć odstęp pionowy (w przykładzie jest to 3px).

Dodatkowo w takich podatnych na dynamiczne zmiany konstrukcjach polecam ustawić jako stan podstawowy obrazek przesunięty o ujemną wartość. Wtedy w przypadku nieprzyjaznych warunków layout popsuje się w stanie :hover. Możecie to prześledzić, powiększając znacznie tekst w drugim demie.

3. Generowana zawartość

Mimo, że wsparcie dla prawdziwego GC wśród przeglądarek jest mizerne, to jednak opracowałem zestaw hacków dla Explorera i Firefoksa (tak, Fx nieprzeciętnie ssie jeśli chodzi o ten moduł CSS) pozwalające cieszyć się zadowalającym efektem.

Zasada jest prosta. Wszystkim przeglądarkom serwujemy zgodny ze standardami kod, natomiast te na bakier dostają swoje workaroundy. Internet Explorer udostępnia mechanizm komentarzy warunkowych (znany wszystkim webdesignerom ;)) oraz expressions, pozwalające wstrzyknąć JavaScript do CSS-a.

Firefox (Gecko) pozwalają natomiast skorzystać z Extensible Binding Language i dołączyć przez CSS JavaScript dla danego elementu. Wykorzystałem XBL już w poście o text-overflow. Jest to niesamowicie użyteczna opcja, dzięki której możemy poprawiać zachowanie Gecko - jak popsute wyświetlanie generowanej zawartości oraz błąd z listą i display:block.

Na potrzeby tej metody również przygotowujemy sklejony plik tła. Tyle że teraz nie musimy martwić się o jego orientację i szerokość oraz wynikające z tego problemy - po prostu ustawiamy jeden stan obrazka obok drugiego.

Tworzymy więc za pomocą selektora li a::before element blokowy o podanych wymiarach z obrazkiem tła wewnątrz, pozycjonujemy go odnosząc się do li oraz ustawiamy potem na stan :hover przesunięcie tła. Opera sobie radzi, Fx wyczynia cuda na kiju, IE zaniemówił.

Dla nich należy więc utworzyć w JavaScript div z klasą .before, którego selektor dopiszemy do CSS, aby ustawić takie same opcje jak dla ::before. Dla IE będzie to:

  1. li a {
  2. -ieh: expression(
  3. this.p ? 0 : (
  4. ico = document.createElement('div'),
  5. ico.className = 'before',
  6. this.parentNode.insertBefore(ico, this),
  7. this.p = 1
  8. ),
  9. this.parentNode.firstChild.style.backgroundPosition = '0 0'
  10. );
  11. }
  12. li a:hover {
  13. -ieh: expression(
  14. this.parentNode.firstChild.style.backgroundPosition = '-13px 0'
  15. );
  16. }

Dokładnie tego kodu tłumaczyć nie będę, zamierzam przyjrzeć się expressions w jednym z następnych postów. Osoby zaznajomione z DOM na pewno rozpoznają większą część kodu. Czytelnicy śledzący moje posty przypominają sobie na pewno this.p(arsed), blokujące dodawanie divów w nieskończoność. Stan :hover przesuwa obrazek tła dla div.before, a zwykły selektor a przesuwa go na pozycję wyjściową - dzięki czemu całość działa przełącznikowo, a nie tylko raz.

Teraz Firefox. Nie jestem asem XBL, więc musiałem zaingerować w strukturę HTML. Oddzieliłem zgodne ze standardami linijki z GC do nowego pliku CSS i podlinkowałem go w nowym link. W ten sposób mogłem usunąć ten kawałek CSS z pliku XBL, aby nie psuł ostatecznego efektu (pamiętajmy, że Fx rozpoznaje selektory GC i próbuje coś z nimi robić… w tym przypadku bez większych rezultatów).

O samym XBL jednak. Dodać należy go do reguły hiperłącza w liście:

  1. li a {
  2. -moz-binding: url("moz-gc-fix.xml#XBLDocument");
  3. }

Plik moz-gc-fix.xml (nazwa dowolna) składa się z paru elementów XML i sekcji CDATA, gdzie umieszczamy nasz JavaScript. Całość jest lepszą i bardziej zgodną ze standardami wersją expression dla IE.

Mamy więc (podejrzyjcie kod, aby JS był czytelny) warunek na dodanie tylko raz elementu, wstawienie nowego diva przed link oraz dodanie zdarzeń onmouseover i onmouseout. Na końcu usuwam plik CSS z regułami GC. Demo.

Jeśli wiesz jak to zrobić z poziomu DOM aby nie trzeba było zmieniać JS z każdą nowo dodaną regułą - podziel się wiedzą.

W ten sposób efekt końcowy działa w znacznej części używanych obecnie przeglądarek. Możliwe, że sposób dotarcia do końca wydaje się lekko przekombinowany, ale tak naprawdę jest to prosta implementacja generowanej zawartości z paroma hackami na ociągające się przeglądarki. Dla mnie zdecydowanie najlepsza - uniezależnia nas od tła pod listą (warstwy) oraz jej wymiarów (przesuwanie).

Informacje i hiperłącza

Blog o projektowaniu zgodnych ze standardami stron internetowych.

Praktyczne przykłady, sztuczki CSS, sposoby obchodzenia błędów przeglądarek, lekki i nieinwazyjny JavaScript, użyteczny design, dostępność i skrypty użytkownika.

RSS

Informacje o wpisie

Napisał riddle 06 grudnia 2006 o 00:09

Kategorie: CSS, JavaScript & DOM, XML, XSL, XUL...

Dodaj do:

Wpisy archiwalne

Archiwum miesięczne

Dzięki!

Dodaj bloga do Technorati Favorites Dodaj bloga do Del.icio.us Blog należy do sieci 10przykazań.com

  1. ciekawe, ale jak dla mnie zbyt skomplikowane…

    jedno mnie zastanawia czemu w tym demie używasz JS a przeglądarka zwraca:
    The requested URL /-/xhtml/css-list-image/moz-gc-fix.js was not found on this server.

  2. Pardon, była stara wersja pliku .html na serwerze. Podczas edycji wyrzuciłem JS od razu do XML-a zamiast dodawać kolejny element do HTML-a.

  3. No tak, ale problem, o ktorym wspomniales wczesniej, czyli niepodlinkowana ikona nadal istenieje w ostatnim demie…

  4. Może to z racji pory, ale nie rozumiem o co Ci chodzi… czy ostatnie demo działa inaczej niż opisałem? Obrazek ładowany jest jeden, od razu i jego przełączanie to pozycja, więc niemożliwe że nie jest podlinkowany.

  5. w ostatnim demie po najechaniu na ikonkę i kliknięciu nie przenosi nas dalej więc nie różni się to niczym od :hover

  6. Nie rozumiem Waszej logiki. Nie da się kliknąć na ikonkę, ale co z tego. Zapala się? To różne metody, chodziło tylko o to, żeby nie występował lag po :hover z pokazaniem drugiego stanu ikony.

  7. Riddle, zadne odnośniki, demo etc nie działają...

  8. U mnie działa i wygląda dobrze, dzięki :)

  9. na pewno się przyda ;) dzięki

    ps. po naciśnięciu „czytaj więcej” na stronie głównej, nic się nie dzieje :| mam Fx 2.0

  10. Zdecydowanie przekombinowane, sam pomysł z przesuwaniem obrazka tła, jest bardzo dobry i tego bym się trzymał, reszta jest niepotrzebna. Wolę kilkadziesiąt bajtów więcej w obrazku tła, niż kombinować ze skryptami i innymi XBL-ami. Bo tak na dobra sprawę, dwa kluczowe przykłady różnią się tym, że w jednym używamy obrazka długiego, a w drugim krótkiego, no chyba że coś mi umknęło.

  11. A czy nie można by tego drugiego tła załadować gdzieś w innym miejscu strony?

  12. Pomysły ciekawe, aczkolwiek niepotrzebne. Wystarczy zastosować świetną sztuczkę w CSS opisaną na blogu Marko Dugonjić‘a — sposób wyjątkowo fajny i prosty w implementacji.

  13. O kurczę. Wspaniałe. :-) Dzięki. :)

    Wpis się jednak może przydać walczącym z GC(Generated Content). :P

  14. Shaitan [D4] 14 16 grudnia 2006, 19:42

    2 sposob nie dziala na ffx2 (linux)

  15. mam coś podobnego zrobić – obrazki przed i po tytule – before i after na IE nie działają – jak to obejść modyfikując tylko css ?

  16. Wyszukaj u mnie „expression” i znajdziesz rozwiązanie.

  17. Twój komentarz na starcie strony jest bzdurny. tak bzdurny jak tylko można sobie to wyobrazić. dla mnie nie masz już nic więcej do powiedzenia. nie znasz możliwość IE więc się nie wypowiadaj. po za tym IE oferuje PEŁNE wsparcie dle CSS 2.1

    jakieś uwagi?

Dodaj komentarz

Do formatowania komentarzy używaj Textile (HTML nie działa). Szczególnie jeśli wklejasz większe fragmenty kodu. W razie niepewności użyj podglądu komentarza.

Wypowiedzi obraźliwe, infantylne oraz nie na temat będą moderowane – pisząc postaraj się zwiększyć wartość dyskusji.

Komentarze nie służą do wysyłania wiadomości albo informowania o błędach, itd. Chcesz coś mi napisać – skontaktuj się.