Budowa formularzy

Oryginał tego tekstu jest autorstwa Riddle. Na Licencji CC.

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.

  <form action="">
    <div>
    </div>
  </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.

  <input class="text" type="text" />
  <input class="check" type="checkbox" />
  <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:

  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 klikaniem maleńkiego kwadracika żeby zaznaczyć pole — kliknij jego opis. Tak więc wygląda nasz formularz:

  <form action="">
    <fieldset>
      <legend>Komentarz</legend>
        <label for="fNick">Nick</label>
          <input id="fNick" name="fNick" class="text" type="text" />
        <label for="fMail">Mail</label>
          <input id="fMail" name="fMail" class="text" type="text" />
        <label for="fText">Treść</label>
          <textarea id="fText" name="fText" cols="40" rows="10"></textarea>
        <input id="fSave" name="fSave" class="check" type="checkbox" />
          <label for="fSave">Zapamiętaj dane</label>
        <input id="fSubmit" name="fSubmit" class="submit" type="submit" value="Dodaj komentarz" />
    </fieldset>
  </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ąć 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 divform na liniowy. Podejście metodą br wymagałoby usunięcia tych znaczników z wielu stron.

  <form action="">
    <div>
      <legend>Komentarz</legend>
        <div>
          <label for="fNick">Nick</label>
          <input id="fNick" name="fNick" class="text" type="text" />
        </div>
        <div>
          <label for="fMail">Mail</label>
          <input id="fMail" name="fMail" class="text" type="text" />
        </div>
        <div>
          <label for="fText">Treść</label>
          <textarea id="fText" name="fText" cols="40" rows="10"></textarea>
        </div>
        <div>
          <input id="fSave" name="fSave" class="check" type="checkbox" />
          <label for="fSave">Zapamiętaj dane</label>
        </div>
        <div>
          <input id="fSubmit" name="fSubmit" class="submit" type="submit" value="Dodaj komentarz" />
        </div>
    </div>
  </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ść.

  label {
    display: block;
    width: 100px;
  }

Zamiast pikseli można także użyć procentów, emów, etc. Efekt jaki osiągnęliś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.

  label {
    display: block;
    width: 100px;
    float: left;
  }
  input, textarea {
    display: block;
    float: left;
  }

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.

  div {
    overflow: hidden;
    clear: both;
    margin-bottom: 0.5em;
  }

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 labelinput w kodzie został z lewej strony bez odstępu. Można to zmienić aplikując input z klasą check lewy margines:

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

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

  label.check {
    width: auto;
  }

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

 input.check,
  input.submit {
    margin-left: 100px;
  }

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ć dodatkową regułą CSS naprawiającą błąd:

   input[type=checkbox],
   button[type=submit] {
     display: inline;
   }

display:inline zostanie zignorowane, ponieważ elementy mające float nie reagują na zmianę display (poza none).


Zmodyfikowano: 26.08.2011, 00:45
submit