
Привет, Хабр!
Я люблю помогать фронтендерам больше узнать о HTML и CSS. Общаясь, я составил список HTML и CSS фич, которые полезные, но почему-то о них мало кто знает. В этой статье я пришёл поделиться ими.
Давайте посмотрим, что я вам подготовил.
Элемент search
Поиск — один из самых используемых элементов. Сложно найти более-менее популярный сервис, у которого нет поиска. Так что верстать его это обычная задача.
В целом хорошо в разметке использовать элемент form. В него вложить элемент input и button. Для примера я скопировал HTML со страницы популярного маркетплейса и оставил основные элементы.
<body>
  <form action="/search">
    <!-- Текст для атрибута placeholder изменён для статьи -->
    <input placeholder="Искать на сайте" type="text">
    <button type="submit" aria-label="Поиск"><!-- Здесь иконка лупы --></button>
  </form>
</body>Только в такой разметке есть проблема. Пользователи с особенностями зрения не сразу поймут, что это поиск. Для них это форма, потому что для скринридеров это так. Конечно, они не дураки. Дополнительно потыкают на элементы и потом поймут, что форма является поиском.
Несколько лет назад в стандартах появился замечательный элемент search. Его задача — показать область страницы, в которой есть элементы, связанные с поиском или фильтрацией.
Давайте добавим его в нашу разметку.
<body>
  <search>
    <form action="/search">
      <!-- Текст для атрибута placeholder изменён для статьи -->
      <input placeholder="Искать на сайте" type="text">
      <button type="submit" aria-label="Поиск"><!-- Здесь иконка лупы --></button>
    </form>
  </search>
</body>Вот теперь так лучше. Скринридеры поймут, что перед ними поиск, и сообщат пользователям.
Атрибут enterkeyhint
Как фронтендеры, мы не можем влиять на то, как будет отображена виртуальная клавиатура. Почти не можем. Одна возможность у нас всё-таки есть!
Давайте сразу перейдём к примеру. Я создал разметку для формы, состоящей из полей для ввода имени и пароля.
<body>
  <form>
    <div class="field">
      <label class="field__label" for="login">Логин</label>
      <input class="field__input" type="text" id="login">
    </div>
    <div class="field">
      <label class="field__label" for="password">Пароль</label>
      <input class="field__input" type="password" id="password">	
    </div>
    <button type="submit">Отправить</button>
  </form>
</body>Начав заполнять пароль, я увижу в правом нижнем углу кнопку. Она подписана, как «Перейти».

Я предлагаю изменить эту подпись. Поможет в этом атрибут enterkeyhint.
Мне кажется, что в моём примере лучше подходит подпись «Отправ.». Для этого укажу для поля ввода пароля атрибут со значением send.
<body>
  <form>
    <div class="field">
      <label class="field__label" for="login">Логин</label>
      <input class="field__input" type="text" id="login">
    </div>
    <div class="field">
      <label class="field__label" for="password">Пароль</label>
      <input class="field__input" type="password" id="password" enterkeyhint="send">	
    </div>
    <button type="submit">Отправить</button>
  </form>
</body>Как видите, теперь в правом нижнем углу отображается нужная подпись. А главный прикол в том, что если язык интерфейса будет английский, то подпись поменяется сама. Мы увидим «Send».

К сожалению, мы не можем использовать любую подпись. Всего есть семь предопределённых значений. Это enter, done, go, next, previous, search и send. Из них можно выбирать.
Несмотря на скромное количество доступных вариантов, я считаю этот атрибут отличным микроулучшением. Он позволяет использовать более контекстно-ориентированную подпись. Это улучшает пользовательский опыт. Что супер!
Отдельные свойства трансформации rotate, translate и scale
Представим, что перед вами стоит задача сделать анимацию. В ней требуется вращать элемент вокруг своей оси и одновременно плавно приближать и отдалять его.
Понятно, что вы будете использовать свойство animation и правило @keyframes. Но мне интересно, какими свойствами вы реализуете трансформации.
Допустим, вы выберете свойство transform с функциями rotate() и scale().
.awesome-block {
  width: 2rem;
  height: 2rem;
  background-color: tomato;
  animation: rotation 5s infinite;
}
@keyframes rotation {
  0%, 100% {
    transform: rotate(0deg) scale(0);
  }
	
  25%, 75% {
    transform: rotate(0deg) scale(1); /* на этом этапе мне нужен 0deg. Поэтому я вынужден использовать rotate(0deg). Без этого браузеры уже рассчитают другое значение */
  }
	
  50% {
    transform: rotate(360deg) scale(1); /* здесь мне нужен масштаб 1. Для этого я использую scale(1). Без этого браузеры будут рассчитывать другое значение */
  }	
}В этой реализации обязательно требуется дублировать значения rotate(0deg) и scale(0). Без этого анимация не получится, потому что переопределение значения для свойства transform сломает её.
Так что если вы до сих пор делаете так, то у меня есть кое-что новое. А именно свойства translate, rotate и scale.
Они являются полной альтернативой функциям translate(), rotate() и scale(). Таким образом длинное значение для свойства transform из предыдущего кода можно легко сократить.
.awesome-block {
  width: 2rem;
  height: 2rem;
  background-color: tomato;
  animation: rotation 5s infinite;
}
@keyframes rotation {
  0%, 100% {
    scale: 0;
  }
	
  25%, 75% {
    rotate: 0deg;
    scale: 1;
  }
	
  50% {
    rotate: 360deg;
  }	
}Как же лаконично! У меня постоянное случалась ситуация, когда значение свойства transform не умещалось в одну строку. Приходилось дробить его на несколько строк. Жутко бесило. По этой причине я быстренько перешёл на отдельные свойства трансформации. Вам тоже советую!
Значение contents
При работе с позиционированием или определением размеров элементов, я всегда мечтал о способе стилизовать дочерний элемент, игнорируя его непосредственного родителя. И мои мечты сбылись!
Для демонстрации мы разберём пример. У нас будет элемент button, который будет вложен в несколько элементов.
<body>
  <div class="intro">
    <div class="intro__container">
      <button type="button" class="intro__control">Показать</button>
    </div>
  </div>
</body>.intro {
  display: grid;
}Представим, по дизайну нужно растянуть кнопку на всю ширину элемента с классом .intro. Поскольку у него уже используется свойство display со значением grid, то его дочерние именно это и делают. Но, к сожалению, не элемент button, поскольку он не прямой потомок.
Давайте его таким сделаем!  Для этого есть значение contents для свойства display. Его применим к элементу с классом .intro__container.
.intro {
  display: grid;
}
.intro__container {
  display: contents;
}
Идеально! Работает, как задумано. Главное, в этом решении используются встроенные возможности свойства display. Я люблю такую лаконичность.
Псевдо-класс :nth-child()
За мои тринадцать лет в вёрстке я убедился, что даже в самых привычных вещах всегда найдётся что-то новое. Недавно, готовя материал о синтаксисе of S для псевдо-класса :nth-child, я снова ощутил это на собственном опыте.
Казалось бы, я работаю с этим псевдо-классом уже более десяти лет, но всё равно обнаружил для себя кое-что совершенно неожиданное. Рассмотрим пример с разметкой из нескольких элементов.
<body>
  <span class="awesome-box">1</span>
  <span class="awesome-box">2</span>
  <span class="awesome-box">3</span>
  <span class="awesome-box">4</span>
  <span class="awesome-box">5</span>
</body>У меня к вам вопрос: «Как написать стили так, чтобы они применялись от второго до четвёртого элемента?».
Ещё месяц назад мне казалось невозможным реализовать это без добавления дополнительных классов. Всегда, в течение моей карьеры, я сталкивался только с таким подходом. Но сегодня я раскрою секрет. Мы можем использовать комбинацию псевдо-классов :nth-child, создав диапазон элементов.
Для демонстрации сделаю так, чтобы свойство outline применялось, начиная со второго и заканчивая четвёртым элементом.
.awesome-box:nth-child(n+2):nth-child(-n+4) {
  outline: 4px dashed coral;
  outline-offset: 5px;
}
Первый псевдо-класс, :nth-child(n+2), устанавливает счётчик, который начинает отсчёт с 2 и увеличивается. Таким образом, мы определяем минимальное значение для нашего диапазона. 
Максимальное значение достигается благодаря второму псевдо-классу :nth-child(-n+4). Объявив -n, я сделал так, чтобы счётчик в нём работал в обратном направлении, начиная с 5.
В результате браузеры используют пересечение значений этих счётчиков для поиска нужных элементов, выделяя таким образом все элементы, начиная со второго и заканчивая четвёртым.
Свойства text-decoration и text-underline-offset
Как я заметил, многие фронтендеры знают два, три способа создать подчёркивание у ссылки. Обычно называется свойство border, а потом метод с помощью псевдо-элементов.
Потом я спрашиваю: «А можно ли использовать свойство text-decoration?». Тут у людей ступор. Они либо вообще ни разу не использовали это свойство, кроме случая сброса стандартного подчёркивания у ссылок, либо говорят, что оно ограниченное. А дальше начинается мой рассказ о том, чем свойство text-decoration полезно.
Вы чаще всего встречаете его у ссылок, когда сбрасывается подчёркивание по умолчанию с помощью значения none. Действительно, раньше это был единственный полезный кейс, потому что свойство отвечало только за вид линии.
Теперь же оно дополнительно позволяет определить толщину, стиль и цвет линии. За всё это отвечают свойства: text-decoration-line (вид), text-decoration-thickness (толщина), text-decoration-style (стиль) и text-decoration-color (цвет). Они являются частями свойства text-decoration.
a:not([class]) {
  text-decoration: underline 2px solid purple;
  /*
    свойство text-decoration разворачивается в следующие свойства:
    text-decoration-line: underline;
    text-decoration-thickness: 2px;
    text-decoration-style: solid;
    text-decoration-color: purple;
  */
}Также у свойства text-decoration есть классный напарник — свойство text-underline-offset. С помощью него мы можем задать позицию подчёркивания.
a:not([class]) {
  text-decoration: underline 2px solid purple;
  text-underline-offset: 4px;
}Данная парочка очень полезна, когда нужно сделать простое подчёркивание текста. Например, у ссылок в контентных частях страницы. Когда не нужна анимация.
Заключение
Давайте подведём итог. В этой статье мы рассмотрели:
- возможность изменения виртуальной клавиатуры с помощью атрибута - enterkeyhint,
- значение - contents, позволяющее пропустить родительский элемент,
- технику диапазонов элементов с помощью псевдо-класса - :nth-child(),
- как сделать код лаконичнее благодаря отдельным свойствам трансформации, 
- создание подчёркивания у текста свойствами - text-decoration-line,- text-decoration-thickness,- text-decoration-style,- text-decoration-colorи- text-underline-offset.
На этом всё. Спасибо за чтение!
P. S. Помогаю больше узнать про CSS в своём ТГ-канале CSS isn't magic. Присоединяйтесь. Ссылка в профиле.
Ещё посмотрите, какие странности есть в CSS, и как их избежать.
© 2025 ООО «МТ ФИНАНС»
Комментарии (0)
 - Nuri00416.09.2025 22:42- Спасибо за статью . Про <search> раньше не задумывалась, а это действительно удобно. enterkeyhint тоже полезная мелочь, попробую в проектах. 
 
           
 


sergey1998
Спасибо, про contents не знал