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.

Standardy sieciowe i przejrzysty kod czasem stwarzają problemy z rzeczami bardzo prostymi. Jeden z nich jest dość pospolity - musimy złożyć formularz. W większości przypadków nie powinniśmy korzystać z tabeli - formularz napisany na blokach div bądź im podobnych elementach może być później przekształcony, tabela jest statyczna i mało efektywna.

Na początek napiszmy strukturę takiego formularza. Wykorzystamy znaczniki, które przez co niektórych webmasterów zostały już zapomniane, bądź nigdy nie używane. Fieldset jest zestawem pól formularza, w naszym będzie tylko jeden taki zestaw.

  1. <form action="">
  2. <fieldset>
  3. </fieldset>
  4. </form>

Fieldset posiada domyślne dopełnienie w środku, odsuwające kontrolki od, także domyślnego, obramowania. Można wyłączyć taki wygląd przez CSS.

  1. fieldset {
  2. border: none;
  3. padding: 0;
  4. }

Następnie możemy nazwać nasz zestaw pól, bądź w tym wypadku, formularz. Służy do tego znacznik legend. Umiejscawia się domyślnie centralnie na krawędzi fieldset, gdybyśmy nie wyłączali obramowania byłoby to dobrze widoczne.

  1. <form action="">
  2. <fieldset>
  3. <legend>Komentarz</legend>
  4. </fieldset>
  5. </form>

Dalej wypada zacząć dodawać pola formularza. Input, textarea, select gdy potrzeba. W przypadku elementów input warto nadać klasę określającą z jakim typem mamy do czynienia.

  1. <input class="text" type="text" />
  2. <input class="check" type="checkbox" />
  3. <input class="radio" type="radio" />

Bo o ile możemy korzystając z selektorów atrybutów odnieść się do każdego z typu przez:

  1. input[type=text], input[type=radio]…

To starsze przeglądarki oraz Internet Explorer 6 nie zrozumieją takiego zapisu. Powinno się oddzielić style dla pól formularza, bo nie wszystkie właściwości CSS aplikują się jednakowo we wszystkich agentach. Osobiście jestem także zwolennikiem niestylowania przycisków submit - zwykle to przeglądarka korzystając z wyglądu kontrolek systemowych powinna się nimi zająć. O ile jeszcze nadanie stylu „przycisku” - wypukły kawałek zakolorowanego miejsca mówi, że da się go kliknąć, to zupełnie płaski, niczym tekstowy input jest złym rozwiązaniem.

Kolejnym elementem wartym wspomnienia, co więcej - prawie niezbędnym w przypadku pól checkbox czy radio - jest label. Etykietka tekstowa przypisana do którejś z kontrolek, aktywująca focus bądź zaznaczająca pole wyboru w tej kontrolce. Koniec z kliknaniem maleńkiego kwadracika żeby zaznaczyć pole - kliknij jego opis. Tak więc wygląda nasz formularz:

  1. <form action="">
  2. <fieldset>
  3. <legend>Komentarz</legend>
  4. <label for="fNick">Nick</label>
  5. <input id="fNick" name="fNick" class="text" type="text" />
  6. <label for="fMail">Mail</label>
  7. <input id="fMail" name="fMail" class="text" type="text" />
  8. <label for="fText">Treść</label>
  9. <textarea id="fText" name="fText" cols="40" rows="10"></textarea>
  10. <input id="fSave" name="fSave" class="check" type="checkbox" />
  11. <label for="fSave">Zapamiętaj dane</label>
  12. <input id="fSubmit" name="fSubmit" class="submit" type="submit" value="Dodaj komentarz" />
  13. </fieldset>
  14. </form>

Uwaga do zapamiętania, jeśli jeszcze ktoś nie kojarzy - o ile w XHTML nie identyfikuje się już elementów za pomocą name, tylko id, to pola formularzy korzystają z atrybutu name aby przekazać skryptowi po stronie serwera wymagane zmienne i dane.

Zarówno input (textarea, nieużyty tutaj select tak samo) jak i label są elementami liniowymi, co oznacza że pojawiają się na stronie jak tekst - jeden za drugim ciurkiem. Dlatego osoby początkujące starające się podejść drogą standardów do formularzy często wstawiają znacznik złamania linii za każdym inputem - br.

Rozwiązanie to nie jest optymalne. Wyglądać może i będzie znośnie, ale nie na samym wyglądzie się teraz skupiamy. Ja proponowałbym ując każdą kontrolkę z jej opisem w div. Div jako element blokowy łamie linię przed sobą i za sobą co stworzy podobny efekt rozdzielenia pól formularzy; także gdy wyłączymy style. Co więcej - gdyby nam kiedyś znudził się wygląd takiego formularza, możemy zmienić element div w form na liniowy. Podejście metodą br wymagałoby usunięcia tych znaczników z wielu stron.

  1. <form action="">
  2. <fieldset>
  3. <legend>Komentarz</legend>
  4. <div>
  5. <label for="fNick">Nick</label>
  6. <input id="fNick" name="fNick" class="text" type="text" />
  7. </div>
  8. <div>
  9. <label for="fMail">Mail</label>
  10. <input id="fMail" name="fMail" class="text" type="text" />
  11. </div>
  12. <div>
  13. <label for="fText">Treść</label>
  14. <textarea id="fText" name="fText" cols="40" rows="10"></textarea>
  15. </div>
  16. <div>
  17. <input id="fSave" name="fSave" class="check" type="checkbox" />
  18. <label for="fSave">Zapamiętaj dane</label>
  19. </div>
  20. <div>
  21. <input id="fSubmit" name="fSubmit" class="submit" type="submit" value="Dodaj komentarz" />
  22. </div>
  23. </fieldset>
  24. </form>

Po lekkim (tylko wygląd kontrolek, kolory oraz tekst) ostylowaniu otrzymujemy taki oto formularz. Pierwszą rzeczą rzucającą się w oczy jest brak wyrównania pól tekstowych względem siebie - sterczą nierówno za tekstem.

Należy je odepchnąć równo od opisów pól, aby stworzyły siatkę jak w przypadku tabeli. W tym przykładzie zamienimy w CSS label na element blokowy i nadamy mu szerokość.

  1. label {
  2. display: block;
  3. width: 100px;
  4. }

Zamiast pikseli można także użyć procentów, emów, etc. Efekt jaki osiągneliśmy nadal nie jest taki jakbyśmy sobie życzyli. Label z uwagi na blokowość wytworzył nową linię za sobą i przeniósł input pod siebie. Więc należy zamienić input na blok oraz ustawić pływanie w lewą stronę, tak samo jak w przypadku label.

  1. label {
  2. display: block;
  3. width: 100px;
  4. float: left;
  5. }
  6. input, textarea {
  7. display: block;
  8. float: left;
  9. }

Po włączeniu float należy zadbać, aby poszczególne linijki pól formularza - złożone z divów - nadal rozdzielały kontrolki. Jako że wszystkie elementy w środku diva zostały wybite z flowu dokumentu, więc on sam stanie się prawie bezużyteczny - pusty div nie przedstawia wartości na stronach. Należy więc zadbać, aby zaczął się „przejmować” elementami które są w środku, nawet jeśli mają float i wystają. Możemy także dodać od razu odstęp pionowy.

  1. div {
  2. overflow: hidden;
  3. clear: both;
  4. margin-bottom: 0.5em;
  5. }

Dodałem także clear: both, aby upewnić się że na pewno formularz pojawi się tak jak sobie wymarzyłem (Internet Explorer zwykle w tym miejscu się foszy). Efekt jest już lepszy. Pozostał tylko ten checkbox, który ze względu na odwrotne położenie elementów label i input w kodzie został z lewej strony bez odstępu. Można to zmienić aplikując input z klasą check lewy margines:

  1. input.check {
  2. margin-left: 100px;
  3. }

Oraz wyłączyć szerokość dla etykietki tego pola, której dodajemy też klasę:

  1. label.check {
  2. width: auto;
  3. }

Podobnie robimy z samotnym przyciskiem wysyłającym komentarz:

  1. input.check,
  2. input.submit {
  3. margin-left: 100px;
  4. }

Gotowy formularz prezentuje się całkiem jak tabela - jest jednak wolny od niesemantycznych znaczników i działa sprawniej za pomocą label - kliknij w tekst etykietki formularza a zobaczysz jak pozytywny efekt powoduje.

Z powodu błędu obliczania odległości po zaaplikowaniu float dla elementów, w Internet Explorerze checkbox oraz przycisk będą odsunięte o 100px za bardzo w prawo. Można rozwiązać to stosując komentarz warunkowy z dodatkową regułą CSS naprawiającą błąd:

  1. <!--[if lte IE 6]>
  2. <style type="text/css">
  3. input.check,
  4. input.submit {
  5. display: inline;
  6. }
  7. </style>
  8. <![endif]-->

Nie jest to jednak jedyny elegancki sposób umieszczania kontrolek w formularzu. Od jakiegoś czasu jestem zwolennikiem używania listy definicji dl wraz ze znacznikami dt i dd. Zastanawiałem się czy można nagiąć nazwę „lista definicji” aby wytłumaczyć to przeznaczenie - lecz jeśli przyjąć, że tytułem dt jest etykietką pola a definicją dd samo pole, to chyba nic złego się nie stanie.

Niewątpliwym plusem takiego rozwiązania jest bardzo przejrzysty układ widoczny po wyłączeniu stylów. Tak to zrobione zostało między innymi w panelu administracyjnym tego bloga. W niedługim czasie mam zamiar opisać więcej sposobów na radzenie sobie z formularzami i ich wyglądem, tam też znajdzie się tutorial struktury opartej na dl.

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.

Informacje o wpisie

Napisał riddle 06 marca 2006 o 16:43

Kategorie: CSS, HTML & Semantyka, Standardy sieciowe, Użyteczność

Dodaj do:

Wpisy archiwalne

Archiwum miesięczne

  1. styli -> stylów.
    Nie ma w kodzie nigdzie "label.check". Swoją drogą, nie powinno być - klasę nadaj DIVowi obejmujacemu (używamy kaskady). Poza tym, DIV jest tu IMO zbędny, można śmiało wrzucić input w labelki i tym ostatnim nadać odpowiednie klasy.

  2. > "starsze przeglądarki oraz Internet Explorer 6"
    W pewnym sensie IE6 jest już starszą przeglądarką... :-)

  3. Puck: Jak wyłączysz style to label okaże się bardzo mądrym pomysłem, tak. ;-)
    Błąd poprawiłem, nie mogę tego zapamiętać. :] A label.check jest w kodzie przykładu.

    Ktoś: IE6 przy NN4/IE4 to Ferrari. ;D

  4. Od razu mi się przypomniał ten artykuł: http://nf.hyperreal.info/patrz/dostepne-formularze/

  5. O formularzach był też fajny odbijany (na grupie dyskusyjnej pl.comp.www) : http://tnij.org/btn

    I nie mogę sobie przypomnieć, gdzie czytałem że submit powinien być poza fieldset :/

  6. thx, nawet nie wiedziałem o takim znaczniku jak fieldset albo label ^^""
    trza się dokształcić

  7. Swisti: Najpewniej powinien być, jeśli dotyczy paru fieldsetów - tutaj mamy jeden i chyba nie przeszkadza on tak bardzo… poza tym ładnie się mieści w obramowaniu.

  8. Puck: styli jest poprawne.

  9. Riddle, piszesz:

    "W większości przypadków nie powinniśmy korzystać z tabeli - formularz napisany na blokach div bądź im podobnych elementach może być później przekształcony, tabela jest statyczna i mało efektywna."

    Co to znaczy, że tabela jest statyczna? Czy formularz zrobiony za pomoca <div> jest mniej statyczny? A może wręcz dynamiczny?

    Co to znaczy, że jest mało efektywna? Bardzo łatwo wyrównanie uzyskać za pomocą tabeli (lewa kolumna - opisy pól, prawa - pola): wysoka efektywność pracy (czyli wydajność). Żeby zrobić to za pomocą DIV-ów, trzeba kombinować (chodzi o prosty efekt wyrównania etykiet do prawej/lewej i pól do lewej, tak jak np. tutaj: http://www.blogger.com/signup.g). Dobra, przynajmniej ja muszę kombinować, a przy tabelach nie muszę - dlatego gdy projektowałem aplikację webową rok temu, to nie bawiłem się tam w DIV-y, tylko formularze robiłem tabelkami, chociaż cały kod "waliduje się" względem XHTML i sam układ strony jest na DIV-ach; to właśnie było efektywne... a dla osiągnięcia tego prostego wyrównania potrzebny był cały długi artykuł. Heh...

    (Nie kwestionuję całej reszty artykułu. Jest ok.:-)

    Els

    PS. Co do styli vs stylów: PWN mówi, że tylko "stylów" (http://so.pwn.pl/slowo.php?begin=styl, pierwsza pozycja listy).

  10. teraz nie mówi się stylów tylko stajli :P
    a no, ja też robię zazwyczaj formularze na tabelkach, bo szybciej, a czasu szkoda. prawda jednak jest taka, że divy to przyszłość internetu, i nie ma, że boli, trzeba uzywac

  11. Ja tylko dodam, że można to robić inaczej:
    - label jako pojemnik nie tylko opisu, ale i elementu input (niepotrzebny wtedy div). W nowych przegladarkach nie jest wtedy również potrzebny atrybut "for".
    - pozycjonowanie input np.tak: position: absolute; top: auto; right: ilestam px;



  12. • Robert, no można, ale jak już napisałem Puckowi, jak wyłączysz style to co będziesz z tego miał?
    • Pozycjonowanie zawsze też można, dzięki w sumie za przypomnienie, ale to trochę nieeleganckie, nie sądzisz? :)

  13. Otaczanie kazdego elementu divem, tylko po to aby bez styli byla nowa linia, to lekka ekstrawagancja imho. Już lepiej tradycyjny <br /> wstawić. :)

    Dlaczego position:absolute jest nieelegancka? ja bardzo ją lubię :) wśród wielu zalet, jest i ta, że mniej z nią kłopotów w IE, niż z róznymi floatami. (inna zaleta taka, że relatywnego do końca nie zrozumiałem dotąd :-))

  14. Ale te divy i tak się przydają, żeby w razie czego dać tło, odstępy zrobić, zapobieć problemom nachodzenia. Ale tak, wiem… można z label zrobić blok i będzie fajnie. Czasem jednak nie tylko o brak tych paru znaczników chodzi, wiesz? :-)

  15. Widzę, że powracasz do notek o tematyce jednak związanej ze standardami/projektowaniem stron, to dobrze ;-) Czekam na kolejne artykuły, pozdrawiam.

    btw. ło bosz, cóż to za wymysł, żeby pisząc coś w tym okienku i następnie naciskając tab (cicho licząc, że przeskoczy się do okienka wpisywania kodu z obrazka) przechodziło się to topu? ;o

  16. Przepraszam za ten tabindex, został mi z innego projektu, a tutaj są ustawione już w topie i searchu. Wywaliłem, powinno automatycznie teraz chodzić od pola do pola.

  17. Co do <br /> i 'usuwaniem' go z wielu dokumentów: nie prościej nadać mu display: inline?
    A jesli chodzi o label, to sam też wolę wstawić w niego inputa i nadać mu display: block. Divitis jest szkodliwe ;)

    BTW, Captcha jest strasznie nieczytelna...

  18. • Ooj, ale divitis to zamienianie <h2> przez <div> na przykład. I muszę sprawdzić ten br jako inline… trochę nieprawdopodobne mi się to wydaje. ;D
    • Captcha - poprawiłem, liczę że teraz jest lepiej. Pozdrawiam. :)

  19. Jak zwykle czytałem co piąty akapit, więc jeśli coś przeoczyłem to przepraszam.
    W każdym razie zastanawiam się dlaczego wymiary <textarea/> są podane przez rows i cols? Nie łatwiej i wygodniej definiować je normalnie w stylach przez width i height?

  20. Divitis to nie tylko zamiana <hx/> i innych na <div/>. Tak, to dość szczególne stadium choroby, ale nie jedyne. Widziałem przypadki, gdzie autor wszystko wstawiał w dodatkowe <div/>: <div><h1>tytuł</h1></div>, <div><p><span>Treść akapitu</span></p></div> itd. Najlepiej się kierować zasadą - co za dużo to niezdrowo. ;)

    A co do list definicji: był taki czas, że pamiętali o nich chyba tylko sami twórcy specyfikacji. Ktoś potem wyciągnął je na wierzch i przedstawił światu. Teraz znowu widzę, że lista definicji stała się doskonałym remedium na wszystko. Można w niej umieścić menu, formularz, listę odnośników, zapis rozmowy i co tam jeszcze człowiekowi do głowy przyjdzie. Taka nowa mutacja divitis: definitis listus maximus.

    Nie, jestem przeciwny upychaniu wszystkiego w dodatkowe kontenery, bo [bardzo-ważny-powód-stworzony-z-potrzeby-chwili] (kiedyś w ten sposób usprawiedliwiano układy oparte na tabelach). CSS, choć jeszcze nie doskonały, udostępnia dość sporo metod upiększania dokumentu. Jeśli będziemy do tego jeszcze wciskać wszędzie nadmiarowe pudełka, to potem okaże się, że nowy arkusz stylów będzie zawierał przede wszystkim definicje je zerujące (ukrywające). Ja wiem, że głupIE, stare przeglądarki, (t)oporni użytkownicy itd. Ale jeśli my nie zaczniemy iść z technologicznym duchem czasów to tym bardziej nasi klienci/czytelnicy się z miejsca nie ruszą.

  21. Miałem przyjemność używać samego label, tak, kiedyś też chciałem pisać jak najmniej znaczników. Ale czasem się nie opłaca - i z mojego, nie tak długiego doświadczenia, ale zawsze, wnoszę że div tam jest dość ważnym elementem, który może wiele rzeczy ułatwić i naprawić. Bo jak do tego dojdą floaty pojemników, to można łatwo nadać hasLayout inputom i labelom i przestaje się czasem wszystko sypać. ;-)

  22. \"Zarówno input (textarea, nieużyty tutaj select tak samo) jak i label są elementami liniowymi\"

    no na pewno nie mówi się \"liniowymi\"

    \"Osobiście jestem także zwolennikiem niestylowania przycisków submit - zwykle to przeglądarka korzystając z wyglądu kontrolek systemowych powinna się nimi zająć. O ile jeszcze nadanie stylu „przycisku” - wypukły kawałek zakolorowanego miejsca mówi, że da się go kliknąć, to zupełnie płaski, niczym tekstowy input jest złym rozwiązaniem.\"

    nie widzę ku temu absolutnie żadnych przesłanek.. skoro W3C dało nam input[type=\"image\"] to znaczy, że nic w tej kwestii nie oczekuje.

    No i ten workaround dla IE z użyciem komentarza warunkowego jest całkowicie zbędny, bo { display: inline } możemy wrzucić bezpośrednio tam gdzie używamy { float: left, margin-left }, a to z tego powodu, że każdy element z float innymi niż none staje się automatycznie elementem blokwym, więc { display: inline } nie ma żadnego znaczenia.

    Do wszsytkich krytykujących div\'y wokół par label-input.
    <div> jest lepszy od <br />, bo jest od niego bardziej elastyczny - więcej możnaw stylach z divem osiągnąć, a te 4 znaki więcej wcale nie oznaczają, żę popadamy w divitis. Co więcej <br /> ma konkretne zastosowanie i nie jest nim robienie pionowych odstępów.
    <div> jest lepszy od samego <label>, bo gdy wyłączymy style w przeglądarce formularz nadal ma zadany przez nas wygląd. Co więcej jeśli miał być to sposób na zmniejszenie ilości wymaganego kodu (bo nie trzeba w takim przypadku stosować \'for\'), to też się nie udało, bo IE tego nie supportuje.

    No i jeszcze raz.. pisze się \'stylów\', a nie \'styli\' ;)

  23. Ffreak, dzięki za spory komentarz, ale część rzeczy już wyjaśniliśmy i tylko się powtarzasz. I wybacz, ale mówi się liniowymi - takie tłumaczenie inline jest zrozumiałe dla wszystkich. Chyba że masz killer-translation, to wysłuchamy.

    Pozdrawiam.

  24. Jeśli używasz float, to wartość display jest ignorowana (w kIEpskim nie zawsze, ale to inna bajka) - float implikuje display:block.

    Dorzuciłbyś się z tym opisem do kursu Browsehappy? http://kurs.browsehappy.pl/Krok/

  25. Aktualnie mam trochę spraw na głowie, treść jest na CC (w menu link) więc nie widzę problemu - choć jak piszę sam tego raczej tam nie dodam.

  26. W książkach WNT "inline" tłumaczy się jako "wtrącane" i sądzę, że tłumacze mają większe pojęcie o tłumaczeniu od Ciebie.

    Twoja wersja z "liniowymi" chyba najbardziej zajebiście brzmi w kontekście "funkcja liniowa".

  27. Khorne, pewnie, ale kto to "wtrącane" zrozumie? Jak dla mnie to kolejne udziwnienie. Nie lepiej: inline -> in line -> w linii -> liniowy?
    A tłumaczeniu zwrotów technicznych mówi się nie od dzisiaj - i przeważnie te tłumaczenia są jedynie źródłem śmiechu, a nie pożytku. :-P

  28. To już lepiej zostawić w oryginale, niż kulawo tłumaczyć. A dobre tłumaczenia są wykonalne, vide przytoczone serie WNT: "klasyka informatyki" i "inżynieria oprogramowania". Wymóg jest jeden: tłumacz musi znać się na rzeczy, a nie brać terminy z sufitu.

  29. Khorne: Czepiasz się. Liniowe rozumie każdy z kim dotąd miałem przyjemność rozmawiać. I wybacz moją kulawą znajomość angielskiego, ale zamierzam właśnie tak pisać o elementach inline, oki? :-)

  30. A ci Twoi znajomi na serwery nie mówią przypadkiem "plikacze", a na pewnego bohatera pewnej książki "Bilbo Bagosz"?

  31. Oj nic mi nie mow na temat Bilbo..
    Jak w polskim tlumaczeniu (tym "nowym") przeczytalem "krzaty" zamiast "krasnali" to malo sie nie zesr* z gniewu i nie padlem na zawal.

  32. Prosiłbym o zachowanie tematu dyskusji i spuszczenie z tonu, w Twoim przypadku, Khorne.

  33. Dzięki za ten artykuł. Kilka dni szukałem, aż wreszcie znalazłem tutaj, chodzi mi o to:
    div {
    overflow: hidden; <---
    ...
    }
    Nie wiedziałem dlaczego po dodaniu float:left bloki się rozjeżdżają - no a teraz już wiadomo.
    Dzięki.

  34. Riddle, a czy potrafisz uzasadnić merytorycznie, dlaczego użyłeś elementu DIV, a nie elementu P ?

  35. [Elsindel]: „Co to znaczy, że jest mało efektywna? Bardzo łatwo wyrównanie uzyskać za pomocą tabeli (lewa kolumna - opisy pól, prawa - pola): wysoka efektywność pracy (czyli wydajność). ”



    Elsindel: tu jest uzasadnienie dlaczego nie tabelkom (www.webstandards.org/learn/tutorials/accessible-forms/beginner)
    pozdrawiam

  36. Zapraszam równierz do tego artu:
    http://www.alistapart.com/articles/prettyaccessibleforms/

    Troche bardziej skomplikowane, ale efekt jest za to... uuuuu, cacy!

  37. regdos.com 37 27 listopada 2006, 01:55

    Artykuł pomocny w praktyce postanowiłem zastosować to co tutaj zostało pokazane i wszystko działało do czasu kiedy chciałem wyświetlić coś dodatkowego pod div’em owszem wyświetlało się, ale poprawnie tylko pod FF i O a pod IE za cholerę nie chciało.
    Pomimo, że div miał „overflow: hidden; clear: both;” to IE „foszył” jak to ładnie określił autor artykułu i nie przejmował się tym co ma wewnątrz, czyli cokolwiek nie dawałem pod div’em pojawiało się oczywiście za inputem a nie pod nim.
    Po rozmowie z googlami rozwiązaniem okazało się nadanie height:100% dla div’a, po tym zabiegu IE też dobrze pokazuje.

  38. bardzo dobry artykuł, dzięki :)))