[Перевод] Чего я не знал о CSS

Рисовать сайты я учился по старинке: глядя на исходный код и пытаясь воспроизвести увиденное. Плюс взял странную книгу для невидимых вещей (типа PHP/MySQL) — и вперёд.

Это ещё в 1999 году, когда мы писали и т. д., а DHTML был модным.

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

Вот некоторые вещи, которых я не знал, но хотел бы узнать раньше.


Хотя я знал об этих свойствах, но в течение долгого времени не полностью понимал их.

Вот вкратце:

  • блочные элементы block расширяются горизонтально, чтобы занять целую строку (например, заголовок). Мы можем применить к ним вертикальные отступы.
  • встроенные элементы inline расширяются горизонтально ровно настолько, чтобы вместить содержимое (например, элементы strong или em). Мы не можем применить к ним вертикальные отступы, и они обычно должны быть помещены внутрь блочного элемента.
  • встроенные блочные элементы inline-block похожи на встроенные элементы, но к ним можно применить вертикальные отступы (что делает их полезными для таких объектов, как кнопки).


В приведённом ниже примере у блочных элементов синий контур, встроенные элементы на оранжевом фоне, а у встроенного блочного элемента красный контур.

awerl4b88wgfoih7wuwwmxcxrni.png


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

Если в вашем наборе такого нет, предлагаю добавить следующее правило:

img {
    display: block;
}


Это сделает их поведение гораздо более предсказуемым. Возможно, вы также захотите добавить max-width: 100%;, чтобы они не вырывались из своего контейнера.
По умолчанию ширина/высота контейнера (box) вычисляется путём сложения:

  • Область контента
  • Область заполнения
  • Область границы


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

Если у нас следующий CSS:

.some-class {
    width: 50%;
    padding: 2em;
    border: 0.1rem;
}


Общая расчётная ширина .some-class будет:

50% + 4em + 0.2 rem

Это происходит из-за свойства под названием box-sizing со значением по умолчанию content-box. Такое значение означает, что свойство width применяется к области контента: все остальное добавляется поверх.

Мы можем изменить это для всех элементов с помощью следующего правила:

* {
    box-sizing: border-box;
}


Возвращаясь к нашему примеру, ширина элемента теперь будет вычисляться по границе, так что общая ширина нашего элемента составит 50%.

Что происходит с границей и заполнением (padding)? Эти свойства/значения всё ещё применяются, но не влияют на общую ширину элемента: они находятся в пределах определённой области.

Посмотрите код на Codepen, чтобы увидеть это в действии:

03yxrm-o4efhtgfrc_lx5bzg-me.png

Отступы
Мы не обсуждали здесь margin, потому что отступ — это пространство между элементами, так что он никогда не является частью этого расчёта.


Если у элемента нет фона или границы, может показаться, что отступ и заполнение — одно и то же. Это не так!

  • margin — это пространство между элементами
  • padding — это пространство внутри элемента


Это делает заполнение полезным для элементов, имеющих фон. Мы часто не хотим, чтобы содержимое было близко к краю контейнера элемента, а  padding позволяет этого добиться.
Это давно раздражает новичков CSS. Рэйчел Эндрю описывает это свойство следующим образом:

«При поглощении отступы объединяются так, что пространство между двумя элементами равняется большему из двух отступов. Меньшее поле, по существу, оказывается внутри большего».


Если у нас есть два блочных элемента с margin-bottom: 1em на одном элементе и margin-top: 1.5 em на элементе непосредственно под ним, общее пространство между двумя элементами будет равно 1.5 em.

Это видно здесь:

2lgcvtxitqkcxoaw2um1b4pnz-m.png

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

Расчёты отступов сразу становятся проще. Это также может изменить наш подход к управлению отступами, и именно на данном этапе может оказаться полезным селектор Lobotomised Owl и тому подобные техники.

Примечание: отступы не поглощаются, когда родительский элемент установлен в display: grid или display: flex.


CSS означает «каскадные таблицы стилей». Поэтому неудивительно, что каскад является одним из фундаментальных понятий CSS.

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

Объявленные стили различаются в зависимости от браузера, но именно они являются причиной того, что по умолчанию:

  • У заголовков разные размеры
  • Текст черный
  • Списки маркируются точками
  • У элементов может быть любое свойство display (например, block или inline)


И многие другие вещи.

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


Использовать пиксели (px) заманчиво, потому что они просты для понимания: объявите размер шрифта 24 px, и текст будет 24 px. Но это не гарантирует удобства пользователей, особенно которые изменяют размер контента на уровне браузера или увеличивают масштаб.

Я давно начал использовать для определения размера шрифта em (а позже rem). Потребовалось гораздо больше времени, чтобы надёжно освоить em и rem для отступов, полей, интервалы между буквами и границ.

Понимание разницы между em и rem имеет решающее значение, чтобы управлять относительными единицами. Например, мы можем использовать em для запросов @media и вертикальных отступов, но rem для согласованной ширины границ.

Для полного перехода на относительные единицы требуется некоторое усилие для корректировки мышления, но оно того стоит.


Псевдоэлементы ::before и ::after требуют обязательного указания свойства content, даже если оно остаётся пустым:

.some-class::before {
    content: '';
}


Если оно отсутствует, псевдоэлемент не будет отображаться.
Единица ch (символ) полезна, в частности, для задания ширины элемента примерно по количеству символов в строке текста.

Почему примерно? Технически, ch не считает реальное количество символов в строке.

Единица ch базируется на ширине символа 0. Об этом писал Эрик Мейер:

»1ch обычно шире среднего символа обычно примерно на 20−30%».


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

Например, если мы напишем:

Heading

Paragraph text.


Мы ожидаем, что 

Heading

появится перед или над 

Paragraph text.

. Это нормальный поток.

Если элемент извлечён из нормального потока, он не появится в этом месте. Хороший пример — плавающие и абсолютно позиционированные элементы.


Я впервые узнал о псевдоселекторах :hover, :focus и :active в контексте стилизации ссылок. В то время все примеры их использования выглядели примерно так:

a {
    color: black;
}
a:hover,
a:focus,
a:active {
    color: red;
}


Однако лучше иначе оформить состояния :focus.

:focus — это состояние, когда пользователь нажимает или проводит по фокусируемым элементам на странице (например, ссылкам). Когда пользователь нажимает на него [tab], он не знает, где окажется фокус.

Кроме того, если пользователь фокусируется на уже наведённом элементе, он не будет знать, где находится фокус.

По всем этим причинам лучше всего стилизовать :focus иначе, чем :hover и :active. Например:

a:hover,
a:active {
    /* styles */
}
a:focus {
    /* styles */
}


Посмотрите такой код:

nbjhclihvmewem88_cvzhgeqtta.png

Видите, что фоном выделены нечётные строки? Хотя селектор p:nth-child(even) предполагает выделение чётных строк.

Однако селектор :nth-child() подсчитывает все родственные элементы. Указание элемента в селекторе (например, p:nth-child()) не приводит к тому, что селектор начинает отсчёт с первого элемента этого типа.

Вместо этого указание элемента в селекторе означает, что правило будет применяться только к этому типу элемента. Если мы переключим наш пример на нечётные элементы p:nth-child(odd), то увидим, что:

  • h1 не выделяется, хотя это нечётный родственный элемент
  • Отмечены элементы p, соответствующие критериям (параграфы два, четыре, шесть)


t4hriqvvdbt-1j7nmdk4rdiegiq.png

Вернёмся к первому примеру. Предположим, мы хотим выделить фоном чётные элементы p. В этом случае нам лучше вообще использовать другой псевдоселектор p:nth-of-type(even)

1mjfkmrr2vuzluurx5pasd5aldu.png

Это ключевое различие между :nth-child() и :nth-of-type(). Здесь тонкая разница, но она поможет избежать некоторой путаницы.


Легко освоить основы CSS, но решающее значение имеет понимание, как и почему всё работает именно так.

Если бы я в молодости уделил этому больше времени, то смог бы быстрее писать код, который стал бы более эффективным и устойчивым.

© Habrahabr.ru