Placeholder dla pól formularzy był stosowany od zawsze, nierzadko bowiem brakowało miejsca na stronie i trzeba było gdzieś upchać label elementu. Najpierw każdy pisał własne rozwiązania, z czasem jednak pojawił się HTML5 wraz z atrybutem placeholder, który rozwiązał wszystkie problemy. No prawie wszystkie.
Dzisiaj zapomnę o atrybucie placeholder i pokażę swój sposób radzenia sobie z problemem. Zapraszam!
Po co mi kolejny placeholder / polyfill?
Od tego przede wszystkim powinienem zacząć. Po co wymyślać koło na nowo? Przecież w HTML5 pojawił się atrybut placeholder. Ma jednak pewne wady:
- Nie potrafi spełnić wszystkich zachcianek klientów.
Co prawda mamy pewną możliwość stylowania atrybutu placeholder, niemniej to może nie wystarczyć :-) Element możemy ostylować w niemalże każdej nowoczesnej przeglądarce przez pseudo-klasę ::input-placeholder. Żeby jednak nie było za kolorowo, musimy użyć prefiksów oraz różnego zapisu dla różnych przeglądarek:
- ::-webkit-input-placeholder
- :-moz-placeholder
- ::-moz-placeholder
- :-ms-input-placeholder
Oczywiście ograniczeń i problemów jest więcej.
- Nie wszystkie przeglądarki wspierają HTML5, nie mówiąc o samym atrybucie placeholder czy jego stylowaniu.
No dobra, element ten nie jest obsługiwany głównie przez Internet Explorer do wersji 9 (włącznie) oraz Operę Mini. Niestety jednak wielu wciąż musi wspierać te starocie, a zostawienie pola formularza bez jakiejkolwiek etykiety czy podpowiedzi byłoby słabym rozwiązaniem. Trzeba coś z tym zrobić.
Na szczęście i to zostało już zrobione. Wielokrotnie. Jest jednak jeden mały minus – nadal mamy problem z punktem nr 1.
I choć jestem wielkim fanem cross-browser polyfills oraz JavaScript-driven feature detection, tym razem do problemu podszedłem z nieco innej strony.
Kod potrzebny do obsługi placeholdera
Zacznijmy od stworzenia i omówienia potrzebnego kodu HTML:
1 2 3 4 | <span class="field"> <label for="firstname" class="placeholder">First Name</label> <input type="text" name="firstname" id="firstname"> </span > |
- Pole formularza ma nie ma atrybutu placeholder. Nie opieramy się tutaj na tej funkcjonalności przeglądarek (mimo wielu zalet, w tym przede wszystkim, prostoty użycia).
- Do pola dodajemy element label o klasie placeholder (można zmienić wg własnego widzimisię).
- Pole formularza i etykietę obudowujemy w kontener.
Następnie potrzebujemy nieco CSS:
1 2 3 4 | .field {position: relative} .js .placeholder {position: absolute; top: 0; left: 0; bottom: 0; right: 0; overflow: hidden; text-overflow: ellipsis} .js .placeholder-focus {color: #ccc} .js .placeholder-hidden {display: none} |
- Kontener o klasie field to element liniowy, a co ważniejsze – posiada position: relative.
- Etykieta o klasie placeholder jest pozycjonowana absolutnie nad polem formularza, tym samym go zasłaniając – zarówno w pionie, jak i poziomie. Zatem jeśli ktoś kliknie w label, który będzie zawsze nad polem, zostanie mimo wszystko przeniesiony do pola.
- Pojawiła się klasa js, która informuje, że użytkownik ma włączoną obsługę JavaScriptu. Taka klasa powinna być podpięta do elementu BODY, np. w taki sposób:
1document.body.className += ' js';
W ten sposób poradzimy sobie w przypadku przeglądarek z obsługą JavaScriptu, jak i bez (z tym, że dla przeglądarek bez JavaScriptu będziemy musieli umieścić etykietę nad polem lub pokazywać ją w jeszcze inny sposób).
Brakuje nam jeszcze tylko kodu JavaScript odpowiedzialnego za wywołanie pluginu:
1 2 3 4 5 | <script src="jquery.js"></script> <script src="placeholder.js"></script> <script> jQuery('.placeholder').placeholder(); </script> |
Zasada działania
Plugin podpinamy do wszystkich etykiet o klasie placeholder. To te same elementy, które przy pomocy CSS pozycjonujemy nad polami formularza. Jak łatwo się domyślić, JavaScript pełni tu tylko jedną rolę – dodaje lub usuwa klasy określające status pola formularza.
Jeśli pole jest wypełnione, pojawia się klasa ukrywająca placeholder. Jeśli natomiast pole jest puste, placeholder jest ponownie pokazywany.
To wszystko.
Przewaga nad standardowym placeholderem
Największą zaletą takiego podejścia jest możliwość dowolnego stylowania placeholdera – w końcu to zwykły element label. Możesz więc nadawać mu pogrubienie, zmieniać kolor pod design strony czy ustawiać animację przy pojawianiu się i znikaniu. Wszystko to przy pomocy CSS3 lub kilku linijek w jQuery (jeśli ma być kompatybilne z IE).
Kolejną zaletą jest, że plugin zadziała na każdej przeglądarce, nawet na IE6 :-) Choć to też kwestia odpowiedniego ostylowania elementów placeholdera.
Ostatnią, acz równie ważną zaletą jest prostota tego rozwiązania. Nie musimy rozpoznawać typu pola, jak przy innych polyfillach – nieważne, że to pole typu password, number czy textarea – nasz placeholder „wisi” nad właściwym polem.
Do wad natomiast można zaliczyć nadmierny HTML – wcześniej wystarczyło ustawić atrybut placeholder, a tutaj musimy dodać dodatkowe dwa elementy. Również użycie JavaScriptu jest wadą, bowiem w przeglądarkach z wyłączoną obsługą JavaScriptu, placeholder będziemy musieli pokazać np. nad polem formularza.
Niestandardowy placeholder – pokaż przykład
Aktualny kod znajdziesz natomiast na GitHubie :-) Konstruktywna krytyka mile widziana!
Ja tu widzę jeden dodatkowy: span.
Nie wspomniałeś o największym plusie tej metody: braku problemów z dostępnością. Label de facto jest wymagany dla pola formularza a placeholder nigdy nie miał go zastępować. Dlatego tak bardzo wkurza mnie, gdy w super wspaniałym przykładzie ostylowania placeholdera nikt nie wspomina o label, który tam być powinien. A jeśli już nie ma go gdzie umieścić, to albo właśnie technika inline labels jak tu, albo coś na kształt .visuallyhidden z H5BP.
Nazywanie ostylowanego label „niestandardowym placeholderem” umniejsza jego rolę – tak jakby ten atrybut był od znacznika ważniejszy. A nie jest. I warto o tym pamiętać.
Następnym razem użyj codepen-a albo jsfiddle to przykładów :)
@Comandeer: mądrze mówisz, dzięki za uzupełnienie wpisu! :)
@wookieb: pomyślę o tym. Najchętniej zmieniłbym cały design strony, bo ten jest nieciekawy, ale zawsze brakuje czasu by za to się zabrać. Wcześniej czy później się tym zajmę :)