Graficzne przyciski formularzy w CSS
15 sierpnia 2006
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:
<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.
<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.
#addcomm {display: block;border: none;background: transparent url(img.png) 0 0 no-repeat;width: 129px;height: 21px;}
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
#addcomm {...height: 21px;font-size: 0;}
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.
#addcomm {...height: 21px;padding-top: 21px;}
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:
#addcomm::-moz-focus-inner {border: none;}
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.


