В наших публикациях регулярно появляются статьи о CSS. Среди них — материал об истории CSS, рассказ о подборе имён для CSS-сущностей, статья о CSS-стилях для печати, о которых многие забывают. Мы писали о том, как работают CSS-селекторы, сравнивая происходящее с автосалоном, о сравнительно новой технологии CSS Grid Layout, и о том, что CSS — это не чёрная магия. Сегодня предлагаем вашему вниманию перевод материала, который посвящён странностям CSS, о которых, как полагает автор этого материала, мало кто знает.
Что станет с элементом, если назначить ему свойство
Вот пример, подготовленный средствами CodePen. Такие примеры вы найдёте и во многих других разделах этого материала.
Вышесказанное справедливо и для нижнего поля, задаваемого свойством
Расстояние между следующими элементами будет
→ Пример
Однако так бывает не всегда. Отступы не схлопываются при работе со следующими элементами:
Предположим, что имеются три элемента
→ Пример
Подробности о том, почему это происходит, можно найти здесь.
Используя SASS или LESS, можно решить, что кастомные свойства и переменные CSS эквивалентны возможностям, доступным в этих препроцессорах. Однако, тут имеются несколько отличий, на которые стоит обратить внимание.
Сначала рассмотрим основы:
Кастомные свойства, кроме того, наследуемы, то есть, если переназначить локальную переменную, это подействует на все элементы-потомки, и, в отличие от препроцессора, браузер, когда подобное происходит, пересчитывает все выражения, где применяются такие переменные.
При применении кастомных свойств резервные значения можно перечислить через запятую. В список резервных значений могут входить и другие переменные.
Это приводит нас к основной разнице с препроцессорами: переменные CSS знают о структуре DOM и об изменениях, которые там происходят.
В отличие от первого примера, демонстрирующего наследование, этот пример полагается на резервные значения, на которые влияет то, было ли задано кастомное свойство в родительском элементе DOM или нет.
→ Пример
Более того, их легко можно менять, используя средства JavaScript:
Эта возможность поддерживается начиная с Edge 15.
Конструкция
То, о чём мы говорили в предыдущем разделе, справедливо и для свойства
Показанный здесь элемент
Стили идентификаторов переопределяют стили, заданные на уровне классов. Происходит это из-за того, что id-селекторы точнее, чем селекторы классов. Так, например, правило, заданное для
Средствами CSS можно выбирать элементы на основе конкретных атрибутов и их содержимого. Например, это может быть содержимое атрибутов
Этот приём может оказаться полезным при отладке, например, для выделения всех элементов
Если вы используете Angular, этот подход, кроме того, может быть полезен для выбора элементов, которые содержат
→ Пример
Когда задают некие значения, имеющие отношения к горизонтальной и вертикальной осям, первое число обычно задаёт вертикальное значение, а второе — горизонтальное. Например, в выражении
Одному и тому же элементу можно назначать несколько фоновых изображений, разделив их запятой. При этом каждое из них можно по-разному настраивать, например — позиционировать.
Эта возможность поддерживается начиная с IE11.
Так же, как и при работе с фонами, можно накладывать друг на друга CSS-анимации:
Добавление трансформации
→ Пример
Псевдо-класс
Выделение таких элементов может оказаться полезным для тех посетителей сайта, которые попали на страницу по внешней ссылке вроде
→ Пример
Атрибуты данных можно использовать для динамического CSS-содержимого. Например:
→ Пример
Этот приём может оказаться полезным, если, например, нужно перевести текст псевдо-класса (скажем, используя его для всплывающих подсказок). Сейчас с помощью
Данную конструкцию можно использовать для многих видов данных (изображения, звуки, видео). Например:
→ Пример
Однако если из DOM в CSS надо передавать произвольные данные, придётся обратиться к вышеописанным кастомным свойствам:
Конструкцию
→ Пример
Свойство
Если говорить о кавычках, то скомбинировав этот приём с ранее упомянутым выбором атрибутов данных, можно даже использовать CSS для задания специфического локализованного стиля кавычек, основанного на языке сайта, с применением одного лишь свойства
Свойство
Директиву
Использование двоеточий в именах классов может оказаться полезным для создания более понятных имён, которые, при чтении, легче делить на части. Так, например, некоторые CSS UI-фреймворки (вроде Tailwind) используют следующие соглашения по именованию:
Задавать специфические классы для стилей, применяемых к элементам, над которыми находится указатель мыши, возможно, в большинстве случаев не особенно полезно, но такой подход позволяет чётко отличать соответствующие состояния от других, что улучшает читаемость кода.
Для использования двоеточий в CSS их нужно экранировать:
Все, кто читают этот материал, должны знать о CSS-селекторе, состоящем из трёх элементов, который обычно называют «lobotomized owl selector». Вот как он выглядит:
Он придётся кстати в ситуациях, когда имеется множество элементов одного вида, между которыми должен быть отступ, причём, после последнего элемента такого списка отступ не нужен:
Раз уж мы заговорили о необычных селекторах — вспомним и о методике вертикального выравнивания, называемой «douchebag vertical align»:
Шрифты OpenType поддерживают настройку свойств. Эту особенность можно использовать для подгонки шрифта под нужды конкретного проекта благодаря свойству font-feature-settings.
Один из вариантов применения этой возможности открывается в ситуации, когда нужен красивый шрифт, не являющийся моноширинным, для таймера обратного отсчёта. Без специальной настройки ширина последовательности цифр будет постоянно меняться. Выглядит это непрофессионально. Вот решение этой проблемы:
Тут всё предельно просто:
→ Пример
Мы рассмотрели некоторые малоизвестные возможности CSS, которые, надеемся, пригодятся веб-разработчикам. Кстати, вот ещё одна интересная штука, не относящаяся, правда, к CSS. Это — HTML-элемент wbr, который позволяет отмечать места разрывов слов.
Уважаемые читатели! Знаете ли вы о каких-нибудь возможностях CSS, полезных, но не получивших широкой известности?
Вертикальные поля
Что станет с элементом, если назначить ему свойство
padding-top: 50%
? Интуитивно понятно, что подобное свойство устанавливает размер поля от верхнего края содержимого элемента, размер которого составляет 50%… От чего берутся эти 50%? Собственно говоря, в определённый момент интуиция при разборе особенностей этого свойства оказывается бесполезной. Дело в том, что эти вот 50% берутся от ширины родительского элемента того элемента, которому назначают верхнее поле.Вот пример, подготовленный средствами 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>
→ Пример
Однако так бывает не всегда. Отступы не схлопываются при работе со следующими элементами:
- Плавающие элементы.
- Абсолютно позиционированные элементы.
- Строчно-блочные (inline-block) элементы.
- Элементы с параметром
overflow
, установленным в любое значение кромеvisible
(они не схлопывают отступы со своими элементами-потомками). - Элементы, к которым применено правило
clear
(их верхние отступы не схлопываются с нижними отступами их родительских блоков). - Корневой элемент дерева документа.
Уровень прозрачности и порядок наложения элементов
Предположим, что имеются три элемента
<div>
, каждый из них позиционирован абсолютно. Они содержат другие элементы, которым назначено свойство z-index
со значениями от 1 до 3. Каждый следующий такой элемент выводится поверх предыдущего. Если теперь назначить z-index: 10
самому нижнему элементу, он будет выведен поверх двух других, порядок расположения которых не изменится. Пока всё выглядит так, как и ожидается. Если теперь назначить первому элементу <div>
, тому, который теперь находится выше других, свойство opacity: 0.99
, то он окажется под двумя другими.→ Пример
Подробности о том, почему это происходит, можно найти здесь.
Кастомные свойства и переменные 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 или нет.
→ Пример
Более того, их легко можно менять, используя средства 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
.→ Пример
О порядке следования свойств при указании значений параметров по горизонтали и вертикали
Когда задают некие значения, имеющие отношения к горизонтальной и вертикальной осям, первое число обычно задаёт вертикальное значение, а второе — горизонтальное. Например, в выражении
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;
приводит к выравниванию элемента относительно контейнера, а не относительно окна.→ Пример
Стилизация элементов, на которые осуществляется переход по адресам, содержащим символ решётки (/#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
. При таком подходе браузер прокрутит страницу к нужному элементу и этот элемент окажется выделенным. В наши дни так поступают редко, но этот приём способен улучшить впечатления пользователей от работы с сайтом.→ Пример
Малоизвестные возможности content: ‘foo’;
▍Атрибуты данных
Атрибуты данных можно использовать для динамического CSS-содержимого. Например:
<div data-text="foo"></div>
div:before {
content: attr(data-text);
}
→ Пример
Этот приём может оказаться полезным, если, например, нужно перевести текст псевдо-класса (скажем, используя его для всплывающих подсказок). Сейчас с помощью
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>
→ Пример
▍Открывающие и закрывающие кавычки
Свойство
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
Директиву
@supports
можно использовать для проверки того, поддерживает ли браузер возможности, интересующие разработчика. Скажем, если display:flex
планируется использовать только в том случае, если есть уверенность в поддержке этой возможности браузером, можно применить следующую конструкцию:@supports (display: flex) {
div {
display: flex;
}
}
Двоеточия в именах классов
Использование двоеточий в именах классов может оказаться полезным для создания более понятных имён, которые, при чтении, легче делить на части. Так, например, некоторые CSS UI-фреймворки (вроде Tailwind) используют следующие соглашения по именованию:
<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». Вот как он выглядит:
* + * {
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.
Один из вариантов применения этой возможности открывается в ситуации, когда нужен красивый шрифт, не являющийся моноширинным, для таймера обратного отсчёта. Без специальной настройки ширина последовательности цифр будет постоянно меняться. Выглядит это непрофессионально. Вот решение этой проблемы:
font-feature-settings: "tnum";
font-variant-numeric: tabular-nums;
Обрезка текста с добавлением окончания в виде многоточия, "…"
Тут всё предельно просто:
p {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
→ Пример
Итоги
Мы рассмотрели некоторые малоизвестные возможности CSS, которые, надеемся, пригодятся веб-разработчикам. Кстати, вот ещё одна интересная штука, не относящаяся, правда, к CSS. Это — HTML-элемент wbr, который позволяет отмечать места разрывов слов.
Уважаемые читатели! Знаете ли вы о каких-нибудь возможностях CSS, полезных, но не получивших широкой известности?