MyTetra Share
Делитесь знаниями!
Странности CSS, о которых полезно знать
Время создания: 26.04.2018 09:49
Автор: https://habr.com/users/ru_vds/
Текстовые метки: css tricks
Раздел: CSS

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


image


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


Что станет с элементом, если назначить ему свойство 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, полезных, но не получивших широкой известности?

 
MyTetra Share v.0.53
Яндекс индекс цитирования