- PVSM.RU - https://www.pvsm.ru -

Странности CSS, о которых полезно знать

В наших публикациях регулярно появляются статьи о CSS. Среди них — материал об истории CSS [1], рассказ о подборе имён [2] для CSS-сущностей, статья о CSS-стилях для печати [3], о которых многие забывают. Мы писали о том, как работают CSS-селекторы [4], сравнивая происходящее с автосалоном, о сравнительно новой технологии CSS Grid Layout [5], и о том, что CSS — это не чёрная магия [6]. Сегодня предлагаем вашему вниманию перевод материала, который посвящён странностям CSS, о которых, как полагает автор этого материала, мало кто знает.

image [7]

Вертикальные поля

Что станет с элементом, если назначить ему свойство padding-top: 50%? Интуитивно понятно, что подобное свойство устанавливает размер поля от верхнего края содержимого элемента, размер которого составляет 50%… От чего берутся эти 50%? Собственно говоря, в определённый момент интуиция при разборе особенностей этого свойства оказывается бесполезной. Дело в том, что эти вот 50% берутся от ширины родительского элемента того элемента, которому назначают верхнее поле.

Вот пример [8], подготовленный средствами CodePen. Такие примеры вы найдёте и во многих других разделах этого материала.

Вышесказанное справедливо и для нижнего поля, задаваемого свойством padding-bottom. Знание этой особенности, в частности, позволяет создавать отзывчивые элементы, сохраняющие соотношение сторон:

.square {
  width: 100%;
  height: 0;
  padding-bottom: 100%;
}

О непостоянном схлопывании отступов

Расстояние между следующими элементами будет 20px, а не 40px:

<div style="margin-bottom:20px">foo</div>
<div style="margin-top:20px">foo</div>

Пример [9]

Однако так бывает не всегда. Отступы не схлопываются при работе со следующими элементами:

  • Плавающие элементы.
  • Абсолютно позиционированные элементы.
  • Строчно-блочные (inline-block) элементы.
  • Элементы с параметром overflow, установленным в любое значение кроме visible (они не схлопывают отступы со своими элементами-потомками).
  • Элементы, к которым применено правило clear (их верхние отступы не схлопываются с нижними отступами их родительских блоков).
  • Корневой элемент дерева документа.

Уровень прозрачности и порядок наложения элементов

Предположим, что имеются три элемента <div>, каждый из них позиционирован абсолютно. Они содержат другие элементы, которым назначено свойство z-index со значениями от 1 до 3. Каждый следующий такой элемент выводится поверх предыдущего. Если теперь назначить z-index: 10 самому нижнему элементу, он будет выведен поверх двух других, порядок расположения которых не изменится. Пока всё выглядит так, как и ожидается. Если теперь назначить первому элементу <div>, тому, который теперь находится выше других, свойство opacity: 0.99, то он окажется под двумя другими.

Пример [10]

Подробности о том, почему это происходит, можно найти здесь [11].

Кастомные свойства и переменные CSS

Используя SASS или LESS, можно решить, что кастомные свойства и переменные CSS эквивалентны возможностям, доступным в этих препроцессорах. Однако, тут имеются несколько отличий, на которые стоит обратить внимание.

Сначала рассмотрим основы:

// задавать и использовать кастомные свойства можно так
:root {
 --foo: #000;
}
button {
  background-color: var(--foo); //чёрный фон
}

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

При применении кастомных свойств резервные значения можно перечислить через запятую. В список резервных значений могут входить и другие переменные.

.foo {
  color: var(—-my-var, 'blue');
}

Это приводит нас к основной разнице с препроцессорами: переменные CSS знают о структуре DOM и об изменениях, которые там происходят.

::root {
  --default-color: #000000;
}
header {
 --primary-color: #ff0000;
}
a {
 color: var(--primary-color, --default-color);
}
<a href="">this is black</a>
<header>
  <a href="">this is red.</a>
</header>

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

Пример [12]

Более того, их легко можно менять, используя средства JavaScript:

// получить переменную из inline-стиля
element.style.getPropertyValue("--my-var");
// установить переменную в inline-стиле
element.style.setProperty("--my-var", jsVar + 4);

Эта возможность поддерживается начиная с Edge 15.

Конструкция vertical align: top | middle | bottom

Конструкция vertical align: top | middle | bottom работает только для inline-элементов (в том числе и для inline-block) и элементов table-cell. Этот способ не подходит для выравнивания элементов внутри их родительских элементов. Для этого нужно использовать средства flexbox-вёрстки, или то, что известно как «douchebag vertical align» (ниже мы об этом поговорим).

Свойство height: 100% может не давать ожидаемого эффекта

То, о чём мы говорили в предыдущем разделе, справедливо и для свойства height: 100%. Во многих случаях установка этого свойства не приводит к тому, чего ожидает разработчик. Причина подобного кроется в том, что не задана высота родительского элемента. Рассмотрим пример:

<html>
<body>
  <div style="height:100%;background:red;"></div>
</body>
</html>

Показанный здесь элемент <div> не закрасит всю страницу в красный цвет. Для того чтобы этого добиться, нужно установить свойство height в 100% и для элемента <body>, и для элемента <html>.

Стили идентификаторов и стили классов

Стили идентификаторов переопределяют стили, заданные на уровне классов. Происходит это из-за того, что id-селекторы точнее, чем селекторы классов. Так, например, правило, заданное для .foo.bar переопределит правила, заданные отдельно для .foo и для .bar.

#foo { color: red; } 
.bar { color: green; } 
<h1 id="foo" class="bar">this will be red not green</h1>

Выбор элементов с определённым атрибутом

Средствами CSS можно выбирать элементы на основе конкретных атрибутов и их содержимого. Например, это может быть содержимое атрибутов src или href.

// выбираем все ссылки на zip-файлы (нечувствительно к регистру)
a[href$=".zip" i] { }
// сделаем красными ссылки на google.com
[href*="google.com"] { color: red; }

Этот приём может оказаться полезным при отладке, например, для выделения всех элементов img с пустым атрибутом alt:

img:not([alt]) {
 border: 2px dashed red;
}
img[alt=""] {
 border: 2px dashed red;
}

Если вы используете Angular, этот подход, кроме того, может быть полезен для выбора элементов, которые содержат [ng-click]. Или, если надо, так можно визуально разделить ссылки на локальные ресурсы, и ссылки, которые начинаются с http или https.

Пример [13]

О порядке следования свойств при указании значений параметров по горизонтали и вертикали

Когда задают некие значения, имеющие отношения к горизонтальной и вертикальной осям, первое число обычно задаёт вертикальное значение, а второе — горизонтальное. Например, в выражении padding: 10px 20px; 10px — это верхнее и нижнее поле, 20px — это правое и левое поле. Именно так это выглядит при настройке полей, отступов, границ, в целом — это так практически для всего, за исключением свойства border-spacing в таблицах, где значения расположены с точностью до наоборот: первое число устанавливает значение по горизонтали, второе — по вертикали.

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

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

background: url(example1.png’) no-repeat center 50px, url(‘example2.jpg’) no-repeat bottom top;

Эта возможность поддерживается начиная с IE11.

Наложение CSS-анимаций

Так же, как и при работе с фонами, можно накладывать друг на друга CSS-анимации:

@keyframes foo { 
 0% { opacity: 0; } 
 100% { opacity: 1; } 
}
@keyframes bar { 
 0% { transform: translateX(-100px); } 
 100% { transform: translateX(0px); } 
}
.element {
 animation: foo 2s 0s, bar 1s 0s;
}

О странном поведении position: fixed при использовании трансформации translateZ

Добавление трансформации translateZ(0); к контейнеру, который включает в себя элемент со свойством position: fixed; приводит к выравниванию элемента относительно контейнера, а не относительно окна.

Пример [14]

Стилизация элементов, на которые осуществляется переход по адресам, содержащим символ решётки (/#foo)

Псевдо-класс :target можно использовать для стилизации элементов, на которые осуществляется переход при щелчке по ссылке с символом решётки. Так, например, щелчок по ссылке вида <a href="#foo">Go to Foo</a> прокрутит страницу до элемента <div id="foo">foo</div>. Теперь, если вы включили в CSS правило вида #foo:target { color: red; }, элемент <div> #foo будет окрашен в красный цвет.

Выделение таких элементов может оказаться полезным для тех посетителей сайта, которые попали на страницу по внешней ссылке вроде www.example.com/#foo. При таком подходе браузер прокрутит страницу к нужному элементу и этот элемент окажется выделенным. В наши дни так поступают редко, но этот приём способен улучшить впечатления пользователей от работы с сайтом.

Пример [15]

Малоизвестные возможности content: ‘foo’;

▍Атрибуты данных

Атрибуты данных можно использовать для динамического CSS-содержимого. Например:

<div data-text="foo"></div>
div:before {
 content: attr(data-text);
}

Пример [16]

Этот приём может оказаться полезным, если, например, нужно перевести текст псевдо-класса (скажем, используя его для всплывающих подсказок). Сейчас с помощью attr() можно работать лишь с контентом. Хотя не исключено появление поддержки этой конструкцией других свойств. Более того, значения, получаемые из attr() — это строки, поэтому они предназначены, в первую очередь, для контента и не могут использоваться для свойств, задающих размеры (например — font-size), или для ссылок (например, content: url()). Кстати, поговорим об этом.

▍Content: url()

Данную конструкцию можно использовать для многих видов данных (изображения, звуки, видео). Например:

<div></div>
div:before {
 content: url(image.jpg);
}

→ Пример

Однако если из DOM в CSS надо передавать произвольные данные, придётся обратиться к вышеописанным кастомным свойствам:

<div style="--background-image: url('http://via.placeholder.com/150x150');"></div>
div:after {
 content: '';
 background-image: var(--background-image);
}

▍Инкрементальный счётчик

Конструкцию content: counter() можно использовать для инкрементной нумерации псевдо-элементов:

p {
 counter-increment: myIndex;
}
p:before {
 content:counter(myIndex);
}
<p>foo</p>
<p>bar</p>

Пример [17]

▍Открывающие и закрывающие кавычки

Свойство content псевдо классов вроде :before и :after может быть использовано для добавления к элементам открывающих и закрывающих кавычек:

q:before {
 content: open-quote;
}
q:after {
 content: close-quote;
}

Если говорить о кавычках, то скомбинировав этот приём с ранее упомянутым выбором атрибутов данных, можно даже использовать CSS для задания специфического локализованного стиля кавычек, основанного на языке сайта, с применением одного лишь свойства quotes:

html[lang="fr"] q {
 Quotes: "«" "»";
}

Использование свойства font

Свойство font позволяет, в сокращённом формате, задавать параметры шрифтов:

h1 {
 font-weight: bold;
 font-style: italic;
 font-size: 1rem;
 //etc…
}
// комбинированный вариант
h1 {
 font: italic lighter 1rem/150% Verdana, Helvetica, sans-serif;
}
// синтаксис
// font: font-style font-variant font-weight font-size/line-height font-family;

Директива supports [18]

Директиву @supports можно использовать для проверки того, поддерживает ли браузер возможности, интересующие разработчика. Скажем, если display:flex планируется использовать только в том случае, если есть уверенность в поддержке этой возможности браузером, можно применить следующую конструкцию:

@supports (display: flex) {
 div {
   display: flex;
 }
}

Двоеточия в именах классов

Использование двоеточий в именах классов может оказаться полезным для создания более понятных имён, которые, при чтении, легче делить на части. Так, например, некоторые CSS UI-фреймворки (вроде Tailwind [19]) используют следующие соглашения по именованию:

<div class="justify-start sm:justify-center md:justify-end lg:justify-between xl:justify-around">
<button class="bg-blue hover:bg-blue-dark text-white hover:text-blue-light">Button</button>

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

Для использования двоеточий в CSS их нужно экранировать:

.sm:justify-center { }

Трёхэлементный селектор

Все, кто читают этот материал, должны знать о CSS-селекторе, состоящем из трёх элементов, который обычно называют «lobotomized owl selector [20]». Вот как он выглядит:

* + * {
 margin-top: 2rem;
}

Он придётся кстати в ситуациях, когда имеется множество элементов одного вида, между которыми должен быть отступ, причём, после последнего элемента такого списка отступ не нужен:

li + li {
 margin-top: 1rem;
}
// вместо
li {
 margin-bottom: 1rem;
}
li:last-of-type {
  margin-bottom: 0;
}

Вертикальное выравнивание методом «douchebag vertical align»

Раз уж мы заговорили о необычных селекторах — вспомним и о методике вертикального выравнивания, называемой «douchebag vertical align»:

.element {
 position: relative;
 top: 50%;
 transform: translateY(-50%);
}

Свойство font-feature-settings для шрифтов OpenType

Шрифты OpenType поддерживают настройку свойств. Эту особенность можно использовать для подгонки шрифта под нужды конкретного проекта благодаря свойству font-feature-settings [21].

Один из вариантов применения этой возможности открывается в ситуации [22], когда нужен красивый шрифт, не являющийся моноширинным, для таймера обратного отсчёта. Без специальной настройки ширина последовательности цифр будет постоянно меняться. Выглядит это непрофессионально. Вот решение этой проблемы:

font-feature-settings: "tnum";
font-variant-numeric: tabular-nums;

Обрезка текста с добавлением окончания в виде многоточия, "…"

Тут всё предельно просто:

p {
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

Пример [23]

Итоги

Мы рассмотрели некоторые малоизвестные возможности CSS, которые, надеемся, пригодятся веб-разработчикам. Кстати, вот ещё одна интересная штука, не относящаяся, правда, к CSS. Это — HTML-элемент , который позволяет отмечать места разрывов слов.

Уважаемые читатели! Знаете ли вы о каких-нибудь возможностях CSS, полезных, но не получивших широкой известности?

Странности CSS, о которых полезно знать - 2

Автор: ru_vds

Источник [24]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/razrabotka/274698

Ссылки в тексте:

[1] истории CSS: https://habrahabr.ru/company/ruvds/blog/341832/

[2] имён: https://habrahabr.ru/company/ruvds/blog/347194/

[3] CSS-стилях для печати: https://habrahabr.ru/company/ruvds/blog/317776/

[4] работают CSS-селекторы: https://habrahabr.ru/company/ruvds/blog/317430/

[5] CSS Grid Layout: https://habrahabr.ru/company/ruvds/blog/350166/

[6] CSS — это не чёрная магия: https://habrahabr.ru/company/ruvds/blog/333506/

[7] Image: https://habrahabr.ru/company/ruvds/blog/350658/

[8] пример: https://codepen.io/matude/pen/oEJMVP

[9] Пример: https://codepen.io/matude/pen/ddwQyV

[10] Пример: https://codepen.io/matude/pen/gvZQbj

[11] здесь: https://medium.com/@peedutuisk/lesser-known-css-quirks-oddities-and-advanced-tips-css-is-awesome-8ee3d16295bb

[12] Пример: https://codepen.io/matude/pen/XZoyGe

[13] Пример: https://codepen.io/matude/pen/jZXXjZ

[14] Пример: https://codepen.io/matude/pen/rJooBG

[15] Пример: https://codepen.io/matude/pen/OQrryP

[16] Пример: https://codepen.io/matude/pen/LQMMGX

[17] Пример: https://codepen.io/matude/pen/qxLLpv

[18] supports: https://habrahabr.ru/users/supports/

[19] Tailwind: https://tailwindcss.com/docs/what-is-tailwind/

[20] lobotomized owl selector: https://alistapart.com/article/axiomatic-css-and-lobotomized-owls

[21] font-feature-settings: https://developer.mozilla.org/en-US/docs/Web/CSS/font-feature-settings

[22] ситуации: https://twitter.com/wesbos/status/932644812582522880

[23] Пример: https://codepen.io/matude/pen/OQrrZR

[24] Источник: https://habrahabr.ru/post/350658/?utm_campaign=350658