Верстка форм

  1. Не используйте для разметки групп инпутов div и h1-h6 #

    Почему? #

    Для разметки групп полей есть более подходящие теги: fieldset и legend. Они не только внесут разнообразие в код, но также сделают вашу форму более доступной.

    А как надо? #

    С чистыми fieldset и legend могут возникать затруднения при стилизации и позиционировании контента, но это легко решается дополнительными обёртками.

    Например, так как fieldset используется для групп полей, а у каждого поля есть лейбл, каждой паре input + label обычно требуется обёртка, и здесь можно удобно использовать ненумерованные списки (ul). После этого можно всё позиционирование делать для списка и его элементов, и с раскладкой больше не будет никаких проблем. Чтобы вместе с инпутом не читалась информация об элементах списка, его нужно скрыть от скринридеров, задав role="none".

    legend ведёт себя своеобразно, но его можно вырвать со своего места с помощью float: left, а для позиционирования текста внутри legend завернуть текст в спаны.

    • Плохо
      <div>
        <h3>Контакты</h3>
      
        <label for="name">Имя</label>
        <input type="text"
               name="name"
               id="name">
      
        <label for="surname">Фамилия</label>
        <input type="text"
               name="surname"
               id="surname">
      </div>
    • Хорошо
      <fieldset>
        <legend>Контакты</legend>
      
        <ul role="none">
          <li>
            <label for="name">Имя</label>
            <input type="text"
                   name="name"
                   id="name">
          </li>
          <li>
            <label for="surname">Фамилия</label>
            <input type="text"
                   name="surname"
                   id="surname">
          </li>
        </ul>
      </fieldset>
  2. Не используйте legend вместо label #

    Почему? #

    В некоторых макетах можно увидеть, что название для textarea выглядит как legend, и возникает соблазн поместить textarea в fieldset, а название поля поместить в legend.

    Это будет не самым правильными решением, потому что у всех инпутов должны быть лейблы. Если добавить скрытый лейбл, его содержимое будет дублировать уже имеющийся legend, и всё это вместе будет выглядеть довольно странно.

    Как это увидеть? #

    Посмотрите на форму без стилей:

    Опишите привычки кота
    А как надо? #

    Для одиночного текстового поля не нужны fieldset и legend, они для групп полей. Если такому полю требуется обёртка, можно использовать div. Название поля нужно поместить в label.

    Если стилизация legend не привязана к тегу, вы без проблем можете использовать эти же стили (а лучше класс) для стилизации лейбла.

    • Плохо
      <fieldset class="form-group">
        <legend class="form-group__title">
          Опишите привычки кота
        </legend>
        <label class="form-group__label
                      visually-hidden"
               for="cat-habits">
          Опишите привычки кота
        </label>
      
        <textarea class="form-group__textarea"
                  id="cat-habits"
                  placeholder="Введите текст"
                  ></textarea>
      </fieldset>
    • Хорошо
      <div class="form-group">
        <label class="form-group__title"
               for="cat-habits">
          Опишите привычки кота
        </label>
      
        <textarea class="form-group__textarea"
                  id="cat-habits"
                  placeholder="Введите текст"
                  ></textarea>
      </div>

    Теперь ничего не дублируется:


  3. Не используйте display: none для скрытия инпутов #

    Почему? #

    Инпуты, спрятанные таким образом, становятся полностью недоступны для скринридеров и навигации с клавиатуры

    Как это увидеть? #

    Установите фокус в первое поле и перемещаясь по форме с помощью Tab и стрелок попробуйте выбрать цвет кота:

    Цвет кота

    Ничего не получится, с клавиатуры выбор цвета недоступен.

    А как надо? #

    Для скрытия инпутов используйте класс .visuallyhidden:

    .visuallyhidden {
      position: absolute;
      width: 1px;
      height: 1px;
      margin: -1px;
      border: 0;
      padding: 0;
      white-space: nowrap;
      clip-path: inset(100%);
      clip: rect(0 0 0 0);
      overflow: hidden;
    }

    Это скроет инпут для обычных пользователей, но оставит его доступным для скринридеров. Почитать подробнее можно тут.

    Попробуйте теперь с помощью Tab и стрелок выбрать цвет кота (чтобы выбрать цвет нажмите пробел):

    Цвет кота

    Всё работает.

Итого

  • Не используйте для разметки групп инпутов div и h1-h6, есть более подходящие теги: fieldset и legend.
  • Не используйте legend вместо label для одиночного поля, ему не нужны fieldset и legend, достаточно div и label.
  • Не используйте display: none для скрытия инпутов, они становятся недоступны для скринридеров и навигации с клавиатуры. Скрывайте с помощью .visuallyhidden