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.

Oddzielenie warstwy prezentacyjnej do zewnętrznego arkusza stylów jest bardzo pomocne w późniejszych zmianach na stronie - edycja jednej linijki i gotowe. Jednak podczas projektowania kompleksowych stron możemy natknąć się na problem, jaki stwarzają graficzne przyciski formularzy. A nawet parę problemów, wliczając wybór elementu, zachowanie przeglądarek oraz dostępność.

Zanim przejdę dalej, chciałbym powiedzieć, że zdarza mi się korzystać ze stylowanych w ten sposób przycisków formularza, choć nie jestem ich fanem. Czasem wymogiem jest albo estetyka pracy albo określony design - konsystencja elementów strony i przekaz wizualny bywają ważniejsze. Zdaję sobie także sprawę z problemu wyłączenia obrazków a włączenia CSS.

Niedoskonałości HTML-a

HTML oddaje nam do dyspozycji element, pozwalający użyć obrazka jako przycisku:

  1. <input type="image" src="obrazek.png" alt="Wciśnij mnie" />

Gołym okiem widać, że konstrukcja tego przycisku jest prawie identyczna jak elementu img. Podajemy w źródle ścieżkę do obrazka oraz definiujemy tekst alternatywny.

Na mniejszych stronach użycie tego sposobu jest całkiem rozsądne, udostępnienie tekstu, który pojawi się jeśli użytkownik nie pobiera obrazków sprawia, że rozwiązanie jest dostępne.

Ale nie jest użyteczne. Raz - trzeba dbać o poprawność ścieżek, dwa - zmiana / wyrzucenie obrazka → zmiana HTML. Nie o to nam chodzi, gdy projektujemy serwis w oparciu o CSS. Podobnie ma się sprawa z wykorzystaniem pseudoklas :hover i :active, aby stworzyć interaktywny przycisk.

Wersja 100% CSS

Postanowiłem użyć w teście zwykłego submit i nadać mu wygląd za pomocą CSS. Ustawiłem mu tekst w value, aby użytkownicy przeglądarek tekstowych i czytników ekranu się nie pogubili.

  1. <input id="addcomm" type="submit" value="Dodaj komentarz" />

Pozbyłem się obramowania, ustawiłem tło i nadałem mu dokładne wymiary. Ustawiłem też wyświetlanie blokowe, żeby na pewno wszystko było ok.

  1. #addcomm {
  2. display: block;
  3. border: none;
  4. background: transparent url(img.png) 0 0 no-repeat;
  5. width: 129px;
  6. height: 21px;
  7. }

Taki CSS spowoduje, że otrzymamy przycisk z tłem w postaci obrazka, ale tekst będzie przeszkadzał, wisząc nad nim. Należy teraz go usunąć.

Od razu do głowy przychodzi nadanie zerowej wielkości tekstu

  1. #addcomm {
  2. ...
  3. height: 21px;
  4. font-size: 0;
  5. }

Próbowałem znaleźć w specyfikacji zapis czy wolno używać zera w wielkości tekstu, ale doszukałem się tylko wykluczenia wartości ujemnych. Firefox respektuje taki zapis i tekst znika, Opera ustawia swoje minimum - 2px, a Explorer swoje - 1px.

Próba odsunięcia tekstu przez text-indent nie działa (mimo, że ustawiłem wyświetlanie blokowe dla kontrolki).

Natomiast zadziała górne dopełnienie, przesuwając tekst poza widzialny fragment elementu określony przez height w CSS.

  1. #addcomm {
  2. ...
  3. height: 21px;
  4. padding-top: 21px;
  5. }

W Explorerze 6 i Firefoksie taki zapis znika tekst. Jak przyjrzeć się dobrze CSS-owi, to widać że wysokość przycisku to 21px, padding tyle samo - razem 42px. Wszystkie trzy przeglądarki nie zaprotestowały i nie zwiększyły realnej wysokości przycisku.

Zostawmy to na chwilę. Opera pozostawia nie wiedzieć czemu kilka pikseli górnej części. Należy więc zwiększyć dopełnienie. Ale wcale nie o taką małą wartość - u mnie dopiero 10 pikseli więcej pomogło, a dla pewności że podczas zwiększania rozmiaru tekstu coś nie wyskoczy, dałem łącznie 40.

Teraz realna wysokość elementu to 61px. Dopiero Firefox wraca do respektowania box-modelu jeśli padding będzie większy niż wysokość input. Opera, IE - ni drgną. Ktoś mi wytłumaczy o co chodzi, albo to jest troszkę chore? Tak czy inaczej, nadałem max-height dla przycisku i efekt zadowala.

Sprawa fokusu wokoło przycisku po naciśnięciu - Opera w ogóle nie aplikuje czegoś takiego, Firefox dla tekstu (teraz przesuniętego), lecz brak tam też kursora łapki. Można to zmienić przez cursor: pointer. Explorer zachowuje się jakby nic nie zaszło. :)

Osiągnąłem wreszcie zamierzony efekt (podrasowany - wykorzystuje efekt rollover obiecanymi :hover i :active), przynajmniej w najpopularniejszych przeglądarkach (Safari nie pozwala ostylować przycisków, więc dostaniemy domyślną szklaną pigułkę).

Znalazłem obejście dla wychodzącej w Firefoksie poza przycisk obwódki, gdy się go wciśnie. Kod:

  1. #addcomm::-moz-focus-inner {
  2. border: none;
  3. }

Nie wiem jak to rozwiązanie działa pod rzadszymi przeglądarkami, ale jeśli gdzieś coś się psuje, a zależy nam na zgodności wszędzie, to zawsze można pójść na totalną łatwiznę i dodać dwa przyciski submit. Jeden z opisem (value), ukryty przez CSS (ale nie przez visbility albo display) a drugi bez, z zaaplikowanym obrazkiem. ;)

Szkoda, że nie istnieje metoda CSS podmieniająca src w <input type="image"/> - wtedy wszyscy byliby szczęśliwi.

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 15 sierpnia 2006 o 17:12

Kategorie: CSS, Design

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. Damn! Skąd Ty to wszystko wyciągasz? :>

    Na zadane mi pytanie: "Znasz HTML'a?" niedługo będę odpowiadał "To jakiś nowy provider GSM?".

    BTW. zamierzony efekt osiągnięty, ale czemu nie wprowadzony w życie?

  2. Hmmm, a dlaczego nie zrobić tego przy użyciu JS?
    [oprócz wygody jaką dają CSSy]

  3. GiM: W 90% przypadków tak się robi, ale czemu nie w CSS? ;>

  4. @R: jest jeszcze jeden mały minus, w przeglądarce, obsługującej grafikę ale nie CSSy, nie będzie ładnego guziczka widać, no ale coś za coś.

  5. Maciej Strzelecki 5 15 sierpnia 2006, 19:01

    Dlaczego input a nie button? Wg semantyniki to właśnie znacznik button odpowiada za wszelakie przyciski w formularzach.

  6. @Maciej: wrong, submit jest od wysyłania formularzy, niektóre przeglądarki nie chcą wysłać formularza, jeśli jest to button a nie submit.

  7. Button sprawia *megaproblemy* w IE przy wysyłaniu formularza. :-(

  8. Maciej Strzelecki 8 15 sierpnia 2006, 19:09

    [GiM]: „wrong, submit jest od wysyłania formularzy”

    input jest znacznikiem pozwalającym użytkownikowi wprowadzić nową zawartość, natomiast za wysyłanie bądź czyszczenie formularza odpowiada jednak button (m.in. po to został wprowadzony do specyfikacji HTML 4.0 i jest preferowany w XHTML 1.1).

    [W3C]: „The BUTTON element defines a submit button, reset button, or push button. Authors can also use INPUT to specify these buttons, but the BUTTON element allows richer labels, including images and emphasis. However, BUTTON is new in HTML 4.0 and poorly supported among current browsers, so INPUT is a more reliable choice at this time.”

  9. Maciej, chyba nie mówisz poważnie? :-) <input type="submit" /> różni się od <input type="text" />, sprawdź sam. ;)

    Edit: Ok, rozumiem już o co Ci chodzi… Mimo wszystko jednak utopijna wizja z tym buttonem. Już lepsze WebForms 2.0.

  10. Wow, zastosowałeś znany od lat trik z paddingiem i overflow.
    Zaiste, odkrywcze. /me jest pod wrażeniem ;-)

    Maciej: Śmieszne jest to powoływanie się na XHTML 1.1, kiedy 70+% użytkowników nie używa przeglądarki z obsługą 1.1 (a jedynie z XHTML 1.0 w trybie zgodności wstecznej, czyli faktycznie zupy znaczników z HTML 4 z pozamykanymi <br/>-ami).

  11. Marcoos, o to chodzi że ja tam nie dostawiałem overflow. :-) Z tego co widzę, nawet jak dodam overflow: visible to nadal tak samo przeglądarki się zachowują.

  12. Maciej Strzelecki 12 15 sierpnia 2006, 19:27

    [marcoos]: „Śmieszne jest to powoływanie się na XHTML 1.1, kiedy 70+% użytkowników nie używa przeglądarki z obsługą 1.1 (a jedynie z XHTML 1.0 w trybie zgodności wstecznej, czyli faktycznie zupy znaczników z HTML 4 z pozamykanymi <br/>-ami).”

    Równie śmieszne co pisanie stron zgodnych z CSS 2.1, kiedy w praktyce prawie żadna przeglądarka nie ma pełnej obsługi tego standardu.

    Jestem zwolennikiem teorii, na pewno mało pragmatycznej, że pisanie stron zgodnie ze standardami wymusi na producentach przeglądarek dostosowanie się do nich, dlatego odwołałem się do specyfikacji XHTML.

  13. Dobry wpis i przydatny kod, ale na litość boską nie "konsystencja elementów strony"!

  14. Riddle a wiesz co zobaczy, a raczej czego nie zobaczy urzytwownik który zwyczajnie wyłączył pobieranie obrazków ? :-) Odp: empty space...

    BTW. button jest elegancko obsługiwany przez wiekszość przeglądarek.

  15. Czytajcie uważnie, proszę.

  16. Dobry artykuł, nie radze sobie z elementami formularzy w CSS, szczególnie z przyciskami. Zazwyczaj nie styluje ich bo w każdej przeglądarce wychodzą mi inne :\

  17. Ostatnie moje zabawy z inputem typu image rozczarowały mnie tym, że Opera jako jedyna nie przesyła w formularzu wartości pola a tylko jego współrzędne. FF i IE przesyłają zarówno współrzędne jak i value. Wydawało mi się to logiczne i wysoce przydatne ale w3c faktycznie nie pisze nic o value więc Opera to olewa. Tym bardziej interesujący jest dla mnie ten art :)

  18. <blockquote>Próbowałem znaleźć w specyfikacji zapis czy wolno używać zera w wielkości tekstu, ale doszukałem się tylko wykluczenia wartości ujemnych. </blockquote>

    Oczywiście, ale również wspomniane tam jest, wprawdzie w innym kontekście, ale jednak:
    <blockquote>Note 1. To preserve readability, a UA applying these guidelines should nevertheless avoid creating font-size resulting in less than 9 pixels per EM unit on a computer display.</blockquote>

    W związku z tym nieprawdziwe jest stwierdzenie jakoby Opera ustawiała tam swoje minimum równe 2px:
    <blockquote>Firefox respektuje taki zapis i tekst znika, Opera ustawia swoje minimum - 2px, a Explorer swoje - 1px.</blockquote>

    Opera respektując przytoczoną wyżej uwagę o dostępności posiada stosowną opcję: opera:config#UserPrefs|MinimumFontSize której wartość domyślna wynosi 9px. Użytkownik *może* zmienić jej wartość i ustawić tam nawet 0, co skutkuje, że Opera będzie się zachowywać identycznie jak Firefox w tym przypadku. Jednak władza w tym zakresie spoczywa w rękach *użytkownika*, a nie autora strony i bardzo słusznie. Już nieraz spotykałem się, które radośnie miały ustawioną wielkość fontu na bodajże 6px. Czytać się tego nijak nie dało :)

  19. <blockquote>Ktoś mi wytłumaczy o co chodzi, albo to jest troszkę chore?</blockquote>
    Sprawa jest prosta. Stylowanie formularzy cechuje się niezmierzoną liczbą błędów: http://lofotenmoose.info/css/destroy/buttons.xhtml ;)

  20. Hm. Przejrzałem wszystkie przykłady, i każdy wyglądał tak samo... :)
    O braku :hover już nie wspomnę nawet...

    mls @ Safari

  21. To teraz po proszę uniwersalny przykład przycisku z zaokrąglonymi rogami tak aby rozmiar dopasowywał się sam do ilości tekstu w przycisku.. to by była dopiero sztuczka :)

  22. Paweł 'SiD' Majczyk 22 22 sierpnia 2006, 10:21

    O ile dobrze pamiętam to na ALA było już, szukaj pod 'sliding doors'.

  23. Świetny artykuł, nie wiem skąd Riddle bierze czas na to wszystko, podziwiam :)

  24. bardzo ciekawe ale mam jedno pytanko. Dlaczegoz nie ustawic zwyklych grafik ktore ladniej wygladaja i dac im CSS-y. Przy malej znajomosci JS wszystko wypali :)

  25. A mi pod aktualnie najnowszym FF nie respektuje max-height i przyciski mają pod sobą kilkadziesiąt pixeli przerwy, co powoduje rozjechanie się części strony.

  26. Aktualnie najnowszy FF = ?

  27. Ja daje font-size: 0em; i też działa.

  28. Aktualnie najnowszy Firefox, 1.5.0.6, na stronie brak innych elementów, rodziców, które miałyby ew. wpływ na to działanie.

  29. Tycjan: Jeśli przeczytałbyś wpis zauważyłbyś, czemu rozwiązanie ze zmniejszeniem tekstu do 0 nie może być używane.

    KK: To bardzo dziwne, powiedz - czy to Fx pod linuksa? Czy możesz podlinkować źródło strony oraz screenshot?

  30. Przepraszam, moja wina, gdzieś w trakcie modyfikacji usunąłem display:block i dlatego max-height nie dawało oczekiwanego rezultatu.

    Inna sprawa, że to rozwiązanie nie zadowala mnie, ponieważ chcę mieć 4 przyciski tego typu obok siebie, a display:block to wyklucza :( Szkoda.

  31. Float: left;

  32. :) Działa, wcześniej zostawiłem display:inline i dopasowałem margin i padding odpowiednio dla IE i FF i też działało.

  33. ostatnio znalazlem rozwiazanie „chowania tekstu” – wystarczy go powiekszyc np do 500em i wtedy calkiem wychodzi poza obszar submita. moze kots o tym wspominal ale nie chcialo mi sie czytac wszystkich komentarzy.

    pozdrawiam

  34. Pięknie to wszystko działa co opisałeś, a ja mam jeszcze jeden problem. Jak nadać styl strzałkom w polu select, albo file..?

  35. Oj nie da się… file w ogóle nie ruszysz, a select polecam nie dotykać.

  36. Jeżeli chodzi o to „chowanie tekstu” to nie wiem jak wy ale ja wpisałem jedynie (value = „”) i na tym koniec – nic się nie pojawia i nie trzeba się motać z jakimś zmniejszaniem itd!

  37. oczywiście chodzi o „podwójne uszy”!

  38. :) Działa, wcześniej zostawiłem display:inline i dopasowałem margin i padding odpowiednio dla IE i FF i też działało.

    W jaki sposób można ustawić osobno padding dla FF i dla całej reszty przeglądarek?
    Mam ten sam problem co KK. Chcę mieć przyciski w „inline”. A może można jednak zmusić FF do obsługiwania max-height dla elementów nie-blokowych?

  39. Witam!
    Fajnie działa tylko że w całym tym zamieszaniu doszedłem do wniosku ze najlepsze graficzne formularze to te wykonane w Flashu (dla bogatych) lub w Javie (dla normalnych).
    Riddle wykombinowałem taką małą sztuczkę:
    <image src="sendme.jpg" onclick="sendForm()" alt="wyślij formularz" id="smim"/> <input tyle="submit" id="smis" value="wyślij">

    teraz wystarczy tylko pobawić się css i wypozycjonować obrazek nad przyciskiem. Oczywiście problem powyłączanych obrazków i JS można rozwiązań w dość ładny sposób.
    Niewyświetlanie obrazka – obrazek nie wyświetlony nie zasłoni przycisku. Można więc go nacisnąć.
    Brak JS – obrazek dostaje display: block; w JS przy ładowniu strony a w css ma display: none; W ten sposób brak JS spowoduje odstylowanie formularza… no ale cóż jak chce się być pięknym to trzeba pocierpieć

  40. Dobry pomysł. Chociaż wolę dodać taki obrazek dynamicznie w JS oraz dodać zdarzenie (click) via addEventListener (attachEvent w IE), żeby nie zaśmiecać kodu. :)

    Display: none nie można używać – czytniki ekranu tego nie zauważą. O wiele lepiej ustawiać width i height na 0 oraz dodawać overflow: hidden

    PS: No i <img/> a nie <image/> oraz JavaScript a nie Java. :D

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ę.