Привет, Хабр!

Во фронтенде изменения происходят постоянно. Только разобрался с одним инструментом, он уже считается устаревшим. Плюс на смену ему появляются новые. В JavaScript регулярно добавляются новые методы и API, а HTML и CSS, разумеется, не отстают.

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

Давайте посмотрим, что я вам подготовил.

Атрибут form

По моему опыту, при ревью проектов формы — место, где всегда находится много ошибок. У меня был случай, когда разработчик не использовал элемент button внутри элемента form. Да, визуально форма была хитрая, но я знал, что всё реализуемо. В общем, я добавил ошибку в отчёт.

После этого разработчик стал спорить, что это не ошибка. Просто он не может использовать элемент button. Я ему стал объяснять решение, но он не хотел менять разметку.

В целом он хотел тупо забить на эту ошибку. Тогда я сказал: «Слушай, давай просто свяжем твою кнопку с формой через атрибут form». Видели бы вы его реакцию. Он очень сильно удивился!

Честно, я понимаю, почему так произошло. Я всегда вкладывал кнопку в форму, поэтому вообще не мог столкнуться с атрибутом form. И только спустя значительное время я прочитал статью, где рассказывали про него. Удивился я так же, как мой коллега.

В общем, атрибут form связывает элемент form с элементами button, fieldset, input, objectoutputselect и textarea, которые находятся вне его. Например, я вынес элемент button за пределы элемента form.

<body>
  <form id="login-form">
    <div class="field">
      <label class="field__label" for="login">Логин</label>
      <input class="field__input" id="login" type="email" required>
    </div>		
    <div class="field">
      <label class="field__label" for="password">Пароль</label>
      <input class="field__input" id="password" type="password" minlength="4" required>
      <span class="field__hint">Пароль должен быть больше 3 символов</span>
    </div>
  </form>
  <button form="login-form" type="submit">Войти</button>
</body>

Если вы скопируете код и вставите в песочницу, то увидите, что форма отправляется как обычно. Так, как будто элемент button находится внутри элемента form.

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

Атрибуты novalidate и formnovalidate

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

Многие для этого используют JavaScript. Хотя можно сделать всё проще. Если добавить атрибут novalidate к элементу form, то отключится встроенная валидация. Соответственно, сообщения тоже пропадут.

<body>
  <form id="login-form" novalidate>
    <div class="field">
      <label class="field__label" for="login">Логин</label>
      <input class="field__input" id="login" type="email" required>
    </div>		
    <div class="field">
      <label class="field__label" for="password">Пароль</label>
      <input class="field__input" id="password" type="password" minlength="4" required>
      <span class="field__hint">Пароль должен быть больше 3 символов</span>
    </div>
    <button type="submit">Войти</button>
  </form>
</body>

Дополнительно встроенную валидацию можно отключить атрибутом formnovalidate. Его только нужно уже объявить для элемента button, у которого установлен атрибут type со значением submit.

<body>
  <form id="login-form">
    <div class="field">
      <label class="field__label" for="login">Логин</label>
      <input class="field__input" id="login" type="email" required>
    </div>		
    <div class="field">
      <label class="field__label" for="password">Пароль</label>
      <input class="field__input" id="password" type="password" minlength="4" required>
      <span class="field__hint">Пароль должен быть больше 3 символов</span>
    </div>
    <button formnovalidate type="submit">Войти</button>
  </form>
</body>

Важный нюанс заключается в том, что в этом случае псевдо-классы :valid, :invalid, :user-valid и :user-invalid продолжают работать. Следовательно мы можем писать стили с их использованием.

:user-valid {
  background-color: green;
}

В общем, если вам нужно отключить встроенную валидацию в браузерах, то у вас есть целых два атрибута: novalidate и formnovalidate. Надеюсь, вам их хватит. Только, пожалуйста, убедитесь в том, что ваша реализация валидации работает хорошо.

Псевдо-класс :lang()

Есть проекты, в которых нужно вставлять слова на иностранном языке. Обычно их ещё нужно по-особенному стилизовать. И многие фронтендеры для этого используют отдельные классы или вообще инлайн-стили.

Я нашёл пример на сайте Википедия.

Наша задача сделать текст «HyperText Markup Language» курсивом. Мы обойдёмся без использования классов, и тем более инлай��-стилей. CSS мы напишем с помощью псевдо-класса :lang().

Также для демонстрации примера я упрощу разметку. На суть примера эти изменения не повлияют.

<body>
  <p>
    HTML (от англ. <span lang="en">HyperText Markup Language</span> — «язык гипертекстовой разметки») — стандартизированный язык гипертекстовой разметки документов для просмотра веб-страниц в браузере. 
  </p>
</body>
:lang(en) {
  font-style: italic;
}

Всё работает! Правда наш код не расширяется. Если потребуется стилизовать текст на итальянском или французском, то придётся копировать селектор.

Давайте сделаем лучше. Мы перепишем селектор так, чтобы он применялся ко всем элементам, кроме тех, у которых язык отличается от основного. В этой задаче псевдо-класс :not() поможет нам.

:not(:lang(ru)) {
  font-style: italic;
}

Ещё одним классным примером применения псевдо-класса :lang() является типографика. В разных языках отличаются некоторые символы. Например, кавычки: в русском языке — «ёлочки», а в английском — «лапки».

Хороший пример я нашёл на Хабре. На русской версии сайта у них установлены «ёлочки».

:lang(ru) {
  quotes: "«" "»";
}

А если используется английский язык, то уже «лапки».

:lang(en) {
  quotes: "“" "”";
}

Вот так псевдо-класс :lang() просто позволяет написать стили для элементов, которые могут содержать текст на разных языках. Без каких-то лишних классов или инлайн-стилей.

Также если вы уже хотели написать в комментариях про способ стилизации элементов с использованием селектора по атрибуту [lang], то прочитайте, пожалуйста, другую мою статью. В ней я рассказал, в чём заключается разница между этими двумя способами.

Свойство inset

Смотря код разработчиков, я постоянно встречаю, как они используют длинный блок из свойств toprightbottom и left, у которых установлено значение 0. Вот он.

.awesome-block {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
}

Конечно, я знаю для чего этот код используется. Я не понимаю, почему не используется более короткая форма записи с помощью свойства inset.

.awesome-block {
  position: absolute;
  inset: 0;
}

Смотрите. В обоих вариантах мы говорим браузеру: «Растяни, пожалуйста, элемент по всем четырём сторонам». Да, свойство inset зависит от направления текста. Но в нашей задаче вообще не важно, какое оно. Мы же растягиваем элемент сразу со всех сторон.

Так, если у вас есть такой сниппет кода, вы можете спокойно заменить его свойством inset.

Ключевые слова e, pi, infinity, и NaN для математических функций

Я люблю использовать математику в своих проектах, и в прошлом году открыл для себя новые математические ключевые слова. В стандарте их называют <calc-keyword>. К ним относятся: epiinfinity-infinity и NaN.

Для демонстрации объявим свойство margin со значением, которое будет включать функцию calc с использованием математического ключевого слова pi.

.awesome-block {
  width: 2rem;
  height: 2rem;
  background-color: tomato;
  margin: calc(10px * pi);
}

Также важно понимать, что математические ключевые слова не являются ключевыми словами, которые можно использовать вне математических функций. Такое использование приведёт к ошибкам.

Например, мы объявим математическое ключевое слово e для свойства z-index.

.awesome-block {
  width: 2rem;
  height: 2rem;
  background-color: tomato;
  margin: calc(10px * pi);
	
  position: relative;
  z-index: e; /* браузеры не поймут значение! */
}

А если обернуть значение в функцию, всё заработает.

.awesome-block {
  width: 2rem;
  height: 2rem;
  background-color: tomato;
  margin: calc(10px * pi);
	
  position: relative;
  z-index: calc(e);
}

Математические ключевые слова epiinfinity-infinity и NaN расширяют область применения математических функций. Честно говоря, у меня не было задачи, где они были бы полезны мне. Но это может быть, потому что я плохо дружу с математикой. Поэтому я оставляю себе шанс на будущее. Уверен, что мне попадётся кейс, где математические ключевые слова мне помогут.

Заключение

Давайте подведём итог. В этой статье мы рассмотрели:

  • возможности связи элемента form с элементами button, fieldset, input, objectoutputselect и textarea, находящимися за его пределами, с использованием атрибута form;

  • атрибуты novalidate и formnovalidate, позволяющие вам отключить встроенную в браузер валидацию;

  • пользу псевдо-класса :lang() для стилизации элементов на разных языках;

  • как сократить код с одновременным использованием свойств top, left, bottom и right до одной строки благодаря свойству inset;

  • ключевые математические слова epiinfinity-infinity и NaN, предоставляющие новые возможности при работе с математическими функциями.

Если вам тоже приходилось сталкиваться с тем, что в команде коллеги упускают или просто не знают о некоторых возможностях HTML и CSS, поделитесь, пожалуйста, такими находками в комментариях. Мне будет интересно прочитать.

P. S. Помогаю больше узнать про CSS в своём ТГ-канале CSS isn't magic. Присоединяйтесь. Ссылка в профиле.

На этом всё. Спасибо за чтение!

© 2026 ООО «МТ ФИНАНС»