Сделайте форму удобной на маленьком экране

HTMLBeginner
Практиковаться сейчас

Введение

Still & Spoke проводит небольшие субботние занятия по керамике. Страница студии готова, но форме нужны видимые подписи, встроенная проверка ввода, условно обязательная заметка о помощи с местом и макет для клавиатуры на узком экране. Вы создадите настоящую локальную запись, а не просто сообщение об успехе. Независимая Study form показывает полный пример до изменения вашей работы.

Нужны основы элементов HTML, селекторов и макетов CSS, а также объекты, функции, выбор элементов DOM и события JavaScript. Здесь изучаются связь подписей с полями, ограничения браузера, доступные описания, условный required, видимый фокус и используемые адаптивные правила. В первой работе запросы обслуживают готовый обработчик отправки и локальный API; следующая создаёт этот обработчик. Все люди и адреса вымышлены; письма и платежи не отправляются. Это практическое упражнение по удобству, не полная сертификация доступности. 50 минут — оценка автора с учётом чтения и обычных ошибок.

Используйте Workspace для команд, Studio для сайта. Можно менять /home/labex/project/stillspoke/form.html, validity.js и form.css. Сохраните остальные файлы, готовый API, правила вместимости и существующих посетителей. Каждая работа запускается независимо. Сервер вставляет точное содержимое form.html в оформленную оболочку: он не дополняет отсутствующие подписи и не создаёт вашу работу заново. После обновления дождитесь загрузки страницы перед использованием формы. Надписи сайта остаются английскими на всех языках документации.

Дайте каждому элементу видимую подпись

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

В Studio выберите ссылку Study form. Это переход внутри сайта, не переключение Tab LabEx. У примера собственные API и база; он не завершает вашу работу и не занимает её места. Нажимайте Tab, пока Your name не получит видимую обводку. Введите Example Guest, нажмите Tab, введите sample@example.test. Перейдите Tab к Session, нажмите C для Clay, slowly / 10:00 и прочитайте выбранный заголовок. Стандартный список поддерживает ввод начала названия. Нажмите Tab к флажку помощи, Tab к необязательной заметке и Tab к Reserve my place. Нажмите Enter один раз. Дождитесь в Submission result текста Reserved for Example Guest и выданной сервером Confirmation SS-…. Пассивное сообщение отправки исчезнет. Фокус перейдёт к разделу результата, чтобы его было легко найти.

Изображение показывает результат с отдельным заголовком и настоящим номером. Ваш номер будет другим.

Настоящее подтверждение в независимой форме-примере

Выберите Studio records в примере. Найдите те же имя, адрес, понятное время и номер. Страница читает принятые записи, а не текст результата браузера. Выберите Back to signup, затем Work form для возврата к своей странице. Она ещё не завершена и не имеет новой рабочей записи; результат примера не считается.

Переключитесь на Workspace. cd меняет текущий каталог этого терминала; абсолютный путь начинается с /. pwd выводит каталог. Эти команды явно задают место редактирования:

cd /home/labex/project/stillspoke
pwd

Ожидаемый вывод:

/home/labex/project/stillspoke

Значения name формы — ключи API: name, email, session, support, note. HTML-id обозначает один элемент страницы. for подписи ссылается на id поля, поэтому щелчок по видимой подписи или её чтение вспомогательной технологией определяет элемент. Здесь Your name использует for="person", а отправляемый ключ — name; задачи атрибутов различаются. Вложенный в подпись флажок получает неявную связь. autocomplete="name" и autocomplete="email" указывают тип информации для подсказок браузера, сами данные не отправляют. Исчезающий при вводе заполнитель не заменяет видимую подпись.

required отклоняет пустое значение до запроса. type="email" просит браузер отклонять неверный синтаксис адреса, но не доказывает его владельца. minlength="2" требует два символа в имени. Первый пустой пункт заставляет выбрать реальный сеанс. value пункта — стабильная идентичность на сервере; видимое название предназначено человеку. Не выводите связь из позиции.

aria-describedby содержит ID через пробел. Он связывает поле с постоянной подсказкой и изначально пустым абзацем ошибки. Подсказка объясняет правило до сбоя, ошибка добавляет причину после отказа сервера. Помимо цвета нужны ясные слова. aria-hidden="true" скрывает от вспомогательных технологий только декоративную стрелку. ↗ — числовая ссылка HTML: ASCII-исходник отображается стрелкой. Абзац Sending имеет role="status" для пассивных объявлений. aria-labelledby результата указывает на ID заголовка и даёт разделу имя. Начальный hidden скрывает пустой результат до появления содержимого. У отдельного раздела tabindex="-1": скрипт может его сфокусировать без дополнительной остановки в обычном порядке Tab. Объявление статуса мы не фокусируем.

Следующая команда заменяет только form.html. cat записывает следующий текст; > перезаписывает указанный файл. Маркер HTML в кавычках после << начинает here-document: до строки только с HTML всё является буквальным содержимым файла. Кавычки запрещают shell интерпретировать символы HTML. Вставьте весь блок с конечным маркером. Возвращение приглашения означает окончание записи; отдельной клавиши сохранения нет. Не вставляйте обратные кавычки Markdown. Для небольших JavaScript и CSS далее используется тот же способ.

cd /home/labex/project/stillspoke
cat > form.html <<'HTML'
<form id="signup">
  <div class="pair">
    <div class="field">
      <label for="person">Your name (required)</label>
      <input id="person" name="name" required minlength="2" autocomplete="name"
             aria-describedby="name-help name-error">
      <small id="name-help">At least two characters.</small>
      <p class="error" id="name-error"></p>
    </div>
    <div class="field">
      <label for="email">Email (required)</label>
      <input id="email" name="email" type="email" required autocomplete="email"
             aria-describedby="email-help email-error">
      <small id="email-help">Practice address: you@example.test</small>
      <p class="error" id="email-error"></p>
    </div>
  </div>
  <div class="field">
    <label for="session">Session (required)</label>
    <select id="session" name="session" required aria-describedby="session-help session-error">
      <option value="">Choose a time</option>
      <option value="clay-morning">Clay, slowly / 10:00</option>
      <option value="clay-afternoon">Clay, slowly / 14:00</option>
    </select>
    <small id="session-help">Choose a listed time. The afternoon session is full.</small>
    <p class="error" id="session-error"></p>
  </div>
  <label class="check"><input type="checkbox" name="support"> I need seating assistance</label>
  <div class="field">
    <label for="note">Seating note (required when assistance is selected)</label>
    <textarea id="note" name="note" rows="2" aria-describedby="note-help note-error"></textarea>
    <small id="note-help">When assistance is selected, describe the help in at least 5 characters.</small>
    <p class="error" id="note-error"></p>
  </div>
  <button type="submit">Reserve my place <span aria-hidden="true">&#8599;</span></button>
  <p id="progress" role="status"></p>
  <section id="result" aria-labelledby="result-heading" tabindex="-1" hidden>
    <h3 id="result-heading">Submission result</h3>
    <p id="message"></p>
  </section>
</form>
HTML

Вернитесь в Studio и обновите рабочую страницу. Подписи должны читаться и после ввода. Щёлкните Email, наблюдая переход фокуса к полю, затем Tab для продолжения в порядке документа. На пустой форме активируйте Reserve my place: браузер должен сфокусировать Your name и объяснить обязательность. Введите один символ и повторите, чтобы увидеть правило длины. Возьмите имя вроде Morgan Vale; введите not-an-email для другого отказа по формату. Это встроенные сообщения, не HTTP 422: браузер ещё не отправил запрос записи. Для исправления в сфокусированном поле выделите текст через Ctrl+A или Cmd+A и замените. Опечатка не требует сбрасывать VM.

Сейчас заметка необязательна даже с выбранной помощью. Это поведение добавляется следующим. Узкий макет тоже ещё не оформлен. Самопроверка: у всех пяти элементов видимые связанные подписи, подсказки остаются видны, пустые обязательные значения отправить нельзя.

Свяжите заметку о месте с флажком

Сделайте заметку обязательной только при запросе помощи с местом, сохраняя уже введённый текст.

Флажок предоставляет булево checked: true при выборе, иначе false. Поле или текстовая область имеет свойство required, соответствующее HTML-ограничению. STUDIO — готовый объект конфигурации, загружаемый scenario.js; его noteMin для занятия равен 5. Читайте это число, не предполагая одинаковость всех будущих занятий. Конфигурация даёт данные сценария, а не вашу условную логику.

querySelector возвращает первый элемент по CSS-селектору; [name="support"] и [name="note"] соответствуют этим атрибутам. Выбор идёт по API-name. При изменении флажка функция обновляет два встроенных ограничения. В condition ? first : second условный оператор выбирает first при истине, иначе second. Минимум заметки поэтому пять при помощи и ноль без неё. Один вызов updateNote() также задаёт состояние при загрузке. Слушатель change повторяет его при переключении. Меняются ограничения, не .value, поэтому снятие флажка не стирает черновик.

В Workspace замените validity.js. Маркер JS работает как прежний HTML:

cd /home/labex/project/stillspoke
cat > validity.js <<'JS'
const support = document.querySelector('[name="support"]');
const note = document.querySelector('[name="note"]');
function updateNote() {
  note.required = support.checked;
  note.minLength = support.checked ? STUDIO.noteMin : 0;
}
support.addEventListener('change', updateNote);
updateNote();
JS

Вернитесь в Studio, обновите страницу. Через Tab заполните имя длиной от двух символов, синтаксически правильный адрес вроде morgan@example.test и Clay, slowly / 10:00. На I need seating assistance нажмите Space. Оставьте заметку пустой и активируйте Reserve my place. Теперь браузер должен сфокусировать Seating note и потребовать значение. Введите near, выйдите через Tab и попробуйте снова: четыре символа меньше требуемых пяти. minlength применяется к пользовательскому вводу; здесь текст действительно набирается, а не присваивается скриптом.

По необходимости вернитесь Shift+Tab к флажку и снимите его через Space. Заметка необязательна, near остаётся. Выберите помощь снова и замените заметку на A seat near the entrance. Сохраните ввод для следующего шага; обновление теряет неотправленные поля, но переход между Tab LabEx оставляет страницу открытой.

Если флажок ничего не делает, вернитесь в Workspace и покажите точный сохранённый файл:

cd /home/labex/project/stillspoke
cat validity.js

Сравните его с коротким блоком, включая checked и последний updateNote();. При необходимости замените полным блоком и обновите Studio. Отсутствующий скрипт или ошибка JavaScript отличается от встроенного отказа пустой заметки: отсутствие записи само по себе не доказывает работу ограничения. Самопроверка: флажок меняет обязательность, короткий набранный текст отклоняется только при выборе, существующая заметка сохраняется.

Сохраните читаемость формы и видимый фокус

Завершите макет, создайте настоящую рабочую запись и прочитайте соответствующий принятый результат.

Две колонки должны уметь складываться. 1fr 1fr CSS Grid делит место поровну между именем и почтой; min-width: 0 разрешает сжатие. При ширине окна не более 800 пикселей медиазапрос делает одну колонку. width: 100% с box-sizing: border-box включает отступы и границы в доступную ширину. input:not([type="checkbox"]) исключает флажки из полноширинного правила, оставляя их маленькими квадратами. Текст читается без наведения. Готовая оболочка уже располагает историю над формой на маленьком экране; ваши правила вписывают форму в неё.

:focus-visible даёт видимую обводку клавиатурному фокусу. Цвет не единственный признак: важны слова об обязательности, тексты ошибок и форма обводки. Ясные эквивалентные рамки или тени допустимы, удаление всех признаков фокуса — нет. [aria-invalid="true"] оформляет поле, отмеченное сервером; .error:empty скрывает только пустой абзац ошибки, не подпись или нужное объяснение. overflow-wrap: anywhere переносит длинные номера и вымышленные адреса. Предпочтение уменьшенного движения предотвращает добавление плавных перемещений для тех, кому нужна меньшая анимация; здесь анимация не нужна.

В Workspace замените form.css:

cd /home/labex/project/stillspoke
cat > form.css <<'CSS'
form { margin-top: 28px; }
.pair { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; }
.field { min-width: 0; margin-bottom: 18px; }
label { display: block; margin-bottom: 7px; font-size: 13px; font-weight: bold; }
input:not([type="checkbox"]), select, textarea {
  width: 100%; box-sizing: border-box; padding: 11px 12px;
  border: 1px solid #89988a; border-radius: 3px;
  font: inherit; font-size: 15px; color: #243d35; background: #fcfaf5;
}
small { display: block; margin-top: 6px; font-size: 11px; color: #56645a; }
.check { display: flex; gap: 9px; align-items: center; margin: 20px 0; }
.check input { width: 18px; height: 18px; accent-color: #244c3d; }
button {
  padding: 14px 20px; border: 0; border-radius: 3px;
  font: inherit; font-size: 14px; color: #fffdf6; background: #254f41; cursor: pointer;
}
button[type="submit"] { width: 100%; display: flex; justify-content: space-between; }
button:disabled { background: #5b6c5e; cursor: wait; }
:focus-visible { outline: 3px solid #ad4d28; outline-offset: 4px; }
[aria-invalid="true"] { border: 2px solid #9d3327; }
.error { color: #963024; font-size: 12px; margin: 5px 0; }
.error:empty { display: none; }
#progress, #message { font-size: 14px; overflow-wrap: anywhere; }
#result { margin-top: 20px; border-top: 1px solid #c9cebf; padding-top: 12px; }
#result h3 { font-size: 15px; margin: 0 0 8px; }
#records article { border-top: 1px solid #c9cebf; overflow-wrap: anywhere; padding: 12px 0; }
@media (max-width: 800px) { .pair { grid-template-columns: 1fr; gap: 0; } }
@media (prefers-reduced-motion: reduce) { * { scroll-behavior: auto !important; } }
CSS

Вернитесь в Studio, обновите и используйте рабочую форму. Введите Morgan Vale, morgan@example.test, выберите Clay, slowly / 10:00 через C, помощь через Space, затем A seat near the entrance. Перейдите Tab к отправке и один раз нажмите Enter. Дождитесь настоящего подтверждения готового обработчика. Первая работа предоставляет его; вы реализовали семантику, ограничения и оформление вокруг него. Следующая объясняет и создаёт запросы и обратную связь.

Откройте Studio records, найдите те же имя, почту, время и номер. Сохраните Existing Visitor и Avery Reed. Их записи независимы от новой; удалять их ради свободного места нельзя. Вместимость обеспечивает сервер, не отключённая кнопка. Затем выберите Back to signup. Сохранённая запись остаётся в этой работе, даже если обновление очистит неотправленные поля.

Сузьте браузер или Studio примерно до 390 пикселей, проверьте и планшетные 768. Горизонтальной прокрутки быть не должно; подписи и помощь видимы, имя/почта располагаются вертикально. Обойдите элементы через Tab: каждый сфокусированный элемент требует видимого индикатора. Верните широкую область и проверьте две колонки. Не прячьте трудное поле, чтобы уместить форму.

Если макет остался прежним, проверьте запись именно form.css в /home/labex/project/stillspoke, не base.css, и обновите. Неправильный путь не требует сброса VM. Самопроверка: вся форма читается и работает на узком и широком экранах, настоящая запись видна в списке, старые посетители сохранены. Проверка читает реальные записи и запускает неизменённую копию файлов с временными изолированными данными; она никогда не отправляет вашу настоящую форму за вас.

Резюме

Вы связали видимые подписи, встроенные ограничения и помощь с реальными элементами, сделали заметку условной без потери ввода и построили адаптивный макет с видимым фокусом. После независимого примера вы создали настоящую рабочую запись и сопоставили подтверждение с принятыми данными. Следующая независимая работа создаёт обработчик запросов и сообщений.