Неизвестно полезный CSS. Часть 3

в 13:00, , рубрики: css, ruvds_статьи, web-разработка, верстка, лайфхаки
Неизвестно полезный CSS. Часть 3 - 1

Привет. Я продолжаю рассказывать про неизвестные широкому кругу разработчиков CSS-фишки. Я отбираю их так, чтобы они были полезны в разного рода проектах. Неважно, верстаете ли вы сайт для малого бизнеса или создаёте супермодное React-приложение. Они поддерживаются большинством браузеров. Отдельно отмечу, что я не считаю IE11 современным браузером. По этой причине я не учитывал его.

Сегодня мы рассмотрим:

  • возможность задать несколько фонов с помощью свойства background;
  • свойство display, которое позволяет сделать так, что свойства элемента будут влиять через потомка;
  • как заставить псевдо-элемент nth-child выбрать элементы без привязки к позиции;
  • где будет находиться элемент с position: absolute, если для него заданы свойства grid-column и grid-row.

Больше не буду затягивать. Давайте посмотрим, что я вам подготовил.

▍ Множество фонов для свойства background

Вёрстка текста поверх изображения — обычная задача верстальщика. В ней встречается маска. По задумке дизайнеров, она мешает тексту слиться с фоном. Я создавал её с использованием псевдо-элемента.

<body>
  <div class="hero">
    <span class="hero__msg">Hey! I'm Stas Melnikov</span>
  </div>
</body>

.hero {
  /* здесь стили для позиционирования текста */

  min-height: 100dvh;	
  position: relative;
  isolation: isolate;
	
  background-repeat: no-repeat;
  background-position: 50% 50%;
  background-size: cover;	
  background-image: url("hero.webp");
}

.hero::before {
  content: "";
  inset: 0;
  position: absolute;
  background-color: rgba(15, 63, 122, 0.5);
  z-index: -1;
}

Так я делал достаточно долго. Пока однажды коллега не сказал мне, что псевдо-элемент лишний. Я сначала подумал, что он ошибается, но на всякий случай спросил: «Почему?». Он сказал, что достаточно использовать слои для свойства background. И тут у меня перед глазами всплыл момент из 2013 года.

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

Очухавшись, я попросил Влада показать его версию кода. Открыв редактор, он удалил псевдо-элемент ::before и добавил функцию linear-gradient() для свойства background-image.

.hero {
  /* здесь стили для позиционирования текста */

  min-height: 100dvh;

  background-repeat: no-repeat;
  background-position: 50% 50%;
  background-size: cover;	
  background-image: linear-gradient(to top, rgba(15, 63, 122, 0.5), rgba(15, 63, 122, 0.5)), url("hero.webp");
}

Неизвестно полезный CSS. Часть 3 - 2

Слева — вариант свёрстанный первым способом, а справа — вторым.

Что такое слои для свойства background? Очень давно свойство задавало фоновое изображение или цвет элемента. С появлением слоёв стало можно задавать множество фонов, которые располагаются друг на друге. Последний указанный фон является самым последним, а первый — самый верхний.

В моём примере url("hero.webp") — самый нижний слой, на который накладывается фон с linear-gradient(). В этом решении также интересно, почему используется градиент. Дело в том, что для свойства background-image мы не можем задать однородный цвет. По этой причине Влад использует хак с градиентом, который «изменяется» от одного цвета к такому же цвету.

display: contents «позволяет» пропустить элемент

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

Для начал создам разметку.

<body>
  <div class="intro">
    <div class="intro__container">
      <a href="cv.pdf" class="intro__download">download</a>
    </div>
  </div>
</body>

Поскольку по умолчанию у элемента <a> установлено display: inline, свойство width рассчитывается в зависимости от контента. Мне же требуется сделать так, чтобы оно было эквивалентно свойству width родительского элемента. Первым решением будет использовать display: block для элемента .intro__download.

.intro {
  display: grid;
}

.intro__download {
  /* здесь декоративные стили */

  display: block;
}

Этот код решает мою задачу, но, к сожалению, в своей задаче я не мог его использовать. У меня в проекте множество компонентов. Получилось так, что на ссылке уже было установлено свойство display со значением inline-grid. Изменять его было нельзя. Можно было добавить ещё один класс к элементам .intro__download и в нём установить display: grid.

Но меня смущало, что пришлось бы переопределять значение. Хотелось использовать возможности уже установленного display: grid. Я стал думать дальше, и мне пришло другое решение.

Поскольку у элемента с классом .intro используется display: grid, то свойство width прямого потомка, т. е. элемента с классом .intro__container, будет соответствовать свойству width родительского элемента. А это то, что я хотел сделать для ссылки. Осталось как-то сделать её прямым потомком. Тут я вспомнил про значение contents.

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

Осталось добавить его к элементу с классом .intro__container.

.intro {
  display: grid;
}

.intro__container {
  display: contents;
}

.intro__container {
  /* здесь декоративные стили */

  display: inline-grid;
}

Неизвестно полезный CSS. Часть 3 - 3

Всё! Работает как надо. А главное, не надо добавлять новые классы. Люблю я лаконичность.

Кстати, если поведение элемента с display: grid вызвало у вас вопросы, то у меня есть кое-что. Я рассказал про такие нюансы в отдельной статье. Дальше, я думаю, вы разберётесь.

▍ Можно выбрать конкретные элементы без учёта его позиции

У меня к вам вопрос. Как браузеры обработают следующий код:

:nth-child(2 of .highlight) {
  color: red;
}

Удивил?! Да, я старался. Это новое расширение of S для псевдо-класса :nth-child. Оно позволяет выбрать определённые элементы из списка селекторов без привязки к номеру в DOM. Сейчас покажу, что я имею в виду.

Для нашего примера с классом .highlight я создам следующую разметку:

<body>
  <div class="container">
    <span>1</span>
    <span class="highlight">2</span>
    <span>3</span>
    <span>4</span>
    <span class="highlight">5</span>
    <span class="highlight">6</span>
  </div>
</body> 

Неизвестно полезный CSS. Часть 3 - 4

Браузеры применят стили ко второму элементу с классом .highlight, который является пятым элементом по порядку! Другими словами, при поиске элемента не важен номер его позиции в DOM. Это главное отличие от привычного синтаксиса псевдо-класса :nth-child.

Вместо S мы можем использовать любой селектор. Например, так можно отобрать первые три элемента <span> с классом important.

.container :nth-child(-n+3 of span.important) {
  color: red;
}

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

<body>
  <div class="container">
    <span class="important">1</span>
    <span>2</span>
    <span>3</span>
    <span class="important">4</span>
    <span>5</span>
    <span class="important">6</span>
  </div>
</body>

Неизвестно полезный CSS. Часть 3 - 5

Мне лично всегда не хватало такой возможности. Вспоминаю типичную сетку из карточек товаров. И где-то в середине надо было вставить блок с рекламой, который сбивал порядок элементов. Вот и приходилось плясать с бубнами. Так что синтаксис of — весьма полезная штука.

▍ Элемент с position: absolute не всегда располагается относительно границ родительского элемента с position: relative

Я для тренировки люблю проходить собеседования — иногда это даже полезно. Встречаются интересные вопросы, которые помогают узнать что-то новое. Как раз недавно так и произошло.

Сначала мне показали фрагмент кода, где был абсолютно спозиционированный элемент внутри грид-контейнера:

.container {
  box-sizing: border-box;
  min-height: 100dvh;
  border: 1px solid currentColor;

  display: grid;
  grid-template-columns: repeat(6, 1fr);
  grid-template-rows: repeat(4, 1fr);

  position: relative;
}

.container::before {
  content: "";
  width: 5rem;
  height: 5rem;
  background-color: darkolivegreen;

  position: absolute;
  top: 0;
  left: 0;
}

Меня спросили: «Где будет располагаться псевдо-элемент ::before?». Я с уверенностью ответил, что в левом верхнем углу. Это был правильный ответ.

Неизвестно полезный CSS. Часть 3 - 6

А дальше интервьюер добавил для псевдо-элемента ::before свойства grid-column и grid-row.

.container {
  box-sizing: border-box;
  min-height: 100dvh;
  border: 1px solid currentColor;

  display: grid;
  grid-template-columns: repeat(6, 1fr);
  grid-template-rows: repeat(4, 1fr);

  position: relative;
}

.container::before {
  content: "";
  width: 5rem;
  height: 5rem;
  background-color: darkolivegreen;

  grid-column: 2 / span 2;
  grid-row: 2 / span 2;

  position: absolute;
  top: 0;
  left: 0;
}

Дальше он спросил: «Изменится ли позиция псевдо-элемента ::before?». Этот вопрос меня сбил с толку. Я думал: «Так, position: absolute выдёргивает элемент из контекста, поэтому свойства grid-column и grid-row не сработают». В итоге я ответил, что изменений не будет. Это был неправильный ответ. Оказывается, что позиция псевдо-элемента ::before изменится .

Свойства grid-column и grid-row определяют позицию дочернего элемента. А как это происходит? На деле мы задаём координаты прямоугольника, в который помещается элемент. Он же используется для отсчёта позиции элементов с position: absolute. По этой причине псевдо-элемент ::before отобразился в левом верхнем углу прямоугольника, созданного строками grid-column: 2 / span 2 и grid-row: 2 / span 2, а не родительского элемента.

Неизвестно полезный CSS. Часть 3 - 7

▍ Заключение

Давайте подведём итог. Сегодня мы можем с помощью CSS:

  • создавать маски для изображений без дополнительных элементов;
  • пропустить ближайшего потомка с помощью display: contents;
  • с помощью синтаксиса of применять стили к группе элементов без учёта их позиции в DOM;
  • расположить элемент с position: absolute относительно определённой области родительского элемента.

Оставляю ссылки на все выпуски:

Также, пожалуйста, напишите в комментариях, какие CSS-фишки вы используете, о которых другие могут не знать. Буду ждать их. Спасибо за чтение!

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

Автор: Стас Мельников

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js