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

Я люблю помогать фронтендерам больше узнать о 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)