Перейти к основному содержимому
Блокчейн39ГЛАВА 39CSS: как страница получает видwidthpadding · border200 → 250border-box

CSS: как страница получает вид

Прочитано0%
Квизы0/4
Тренажёрыне пройден0/1
Уровень 1 · Новичок

Зачем это нужно​

Разметка описала, что на странице есть. Браузер уже показал это — своими стилями: Times, поля восемь точек, заголовок тридцать два пикселя. Выглядит как документ из девяностых.

Язык оформления отвечает на второй вопрос: как это должно выглядеть. Размеры, цвета, расположение, поведение при сужении экрана.

Учить его целиком не нужно — свойств несколько сотен, и большинство ищут по мере надобности. Нужно понять четыре механизма, из-за которых оформление ведёт себя «непонятно»: приоритет правил, наследование, счёт ширины и единицы измерения. Все четыре разобраны здесь прогонами.

Правило: кому и что​

.card {
padding: 16px;
border-radius: 12px;
background: #16181d;
}
Нажми на часть выражения

Подключают оформление тремя способами, и они не равны:

<link rel="stylesheet" href="style.css"> <!-- отдельный файл: так и делают -->
<style> .card { … } </style> <!-- внутри страницы: для мелочей -->
<div style="padding: 16px"> <!-- прямо в теге: почти никогда -->

Третий способ выглядит удобным и создаёт проблему: такое правило почти нечем перебить. Через две секции будет видно, чем именно.

Селекторы: кого выбираем​

записького выбирает
pвсе абзацы
.cardвсе элементы с классом card
#totalэлемент с таким идентификатором
.card pабзацы внутри карточки, на любой глубине
.card > pабзацы, лежащие прямо в карточке
.card, .panelи то, и другое: два независимых селектора
input[type="number"]поля с таким атрибутом
button:hoverкнопка под курсором
button:disabledвыключенная кнопка
li:nth-child(2n)каждый второй пункт списка

Практика простая: основной инструмент — класс. Теги выбирают для общих правил вроде сброса, идентификаторы в оформлении почти не используют (причина — в следующей секции), а остальное берут по мере надобности.

Кто побеждает, когда правил несколько​

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

── что победило при разном наборе признаков ──
подходит только p {…} rgb(1, 1, 1) p {…}
подходят p, .c и p.c rgb(3, 3, 3) p.c — два признака против одного
плюс #i rgb(4, 4, 4) #i — идентификатор весомее классов
плюс style="" и !important rgb(9, 9, 9) !important — сильнее даже style
КТО ПОБЕЖДАЕТ, КОГДА ПРАВИЛ НЕСКОЛЬКОp { … }rgb(1,1,1)один признак: тегp.c { … }rgb(3,3,3)два признака — перевесил .c с одним#i { … }rgb(4,4,4)идентификатор весомее любых классов… !importantrgb(9,9,9)сильнее даже записи прямо в тегепри равном весе побеждает то правило, что записано ниже: порядок решает только ничью!important и идентификаторы ломают эту логику — потом их нечем перебить, кроме такого же
Чем больше признаков в селекторе, тем он весомее; идентификатор перебивает любое число классов

Правило веса читается так: считают сколько чего в селекторе.

  1. Больше идентификаторов — весомее.
  2. При равенстве смотрят классы, атрибуты и состояния вроде «под курсором».
  3. При равенстве и тут — имена тегов.
  4. Запись прямо в теге весомее любого селектора.
  5. Пометка «важно» сильнее всего.

При полном равенстве побеждает то, что записано ниже. Порядок решает только ничью — не более того. Отсюда частая ошибка: «я дописал правило в конец, а оно не применилось». Значит, вес прежнего выше, и порядок ни при чём.

Важно

Идентификаторы и пометку «важно» в оформлении стараются не использовать вовсе. Причина простая: перебить их потом нечем, кроме такого же. Один раз написанная пометка тянет за собой вторую, третью — и через день никто не может поменять цвет кнопки.

Отвечено вопросов: 0 из 2
Дописали правило в самый конец файла, а оно не применилось. Причина?
Почему идентификаторы и !important стараются не использовать в оформлении?
Отвечено верно: 0 из 2

Наследование: что достаётся потомкам даром​

Родителю задано семь свойств. Потомку — ни одного. Прогон смотрит, что у потомка получилось:

── что потомок получил сам, без единого правила ──
color rgb(7, 7, 7) ← унаследовал
fontFamily Georgia ← унаследовал
fontSize 20px ← унаследовал
textAlign center ← унаследовал
borderTopWidth 0px ← нет
paddingTop 0px ← нет

Правило простое и не требует запоминания списка: наследуется то, что про текст — цвет, шрифт, размер, выравнивание, межстрочное расстояние. Не наследуется то, что про коробку — рамки, отступы, фон, размеры.

Логика очевидна, если задуматься: рамка вокруг карточки, повторённая у каждого потомка, выглядела бы дико. А цвет текста, наоборот, должен распространяться вглубь.

Из этого следует приём, которым пользуются постоянно: шрифт и цвет задают один раз на теле документа, и дальше они действуют везде.

Коробка: почему 200 не равно 200​

Самая частая причина «вёрстка съехала» — в том, как считается ширина.

.b { width: 200px; padding: 20px; border: 5px solid; margin: 10px; }
── одна и та же запись, два способа считать ──
свойство content-box border-box
width в CSS 200px 200px
место под текст 200px 150px
видимая ширина 250px 200px
занято с полями 270px 220px
ОДНА ЗАПИСЬ width:200px, ДВЕ РАЗНЫЕ ШИРИНЫbox-sizing: content-box (по умолчанию)200px текствидимая ширина 250px200 + отступы 20×2 + рамка 5×2box-sizing: border-box150px текствидимая ширина 200pxотступы и рамка съели место у текстапо умолчанию 200 означает «текст 200, а всего сколько получится» — отсюда съехавшие колонкипоэтому первой строкой оформления почти всегда пишут второй способ счёта для всего сразу
По умолчанию 200 — это ширина текста, а не элемента: отступы и рамка прибавляются сверху

По умолчанию запись width: 200px означает «двести точек под содержимое». Отступы по двадцать с каждой стороны и рамка по пять прибавляются сверху — получается 250. Внешние поля добавляют ещё двадцать: элемент занимает 270.

Отсюда классическая беда: две колонки по 50 % с отступами не помещаются в строку, потому что каждая на самом деле шире половины.

Второй способ счёта меняет смысл: 200 становится шириной всего элемента, а отступы и рамка съедают место у содержимого. Именно это обычно и имеют в виду.

*, *::before, *::after { box-sizing: border-box; }
Совет

Эта строка стоит первой почти в любом файле оформления последних десяти лет. Дальше width: 50% действительно означает половину, и колонки складываются как ожидается.

Единицы: от чего считается число​

── от чего считаются единицы ──
родитель: font-size 20px, ширина 400px; корень документа: 16px
1.5rem font-size 24px width 200px
1.5em font-size 30px width 200px
25% font-size 20px width 100px
ОТ ЧЕГО СЧИТАЮТСЯ ЕДИНИЦЫродитель: размер шрифта 20px, ширина 400px · корень документа: 16px1.5rem24px1.5 × 16 — от корня документа1.5em30px1.5 × 20 — от родителя, а он может быть любым25%100px0.25 × 400 — от ширины родителяразмеры шрифта берут в rem: он считается от одного места и не накапливается по вложенностиem внутри em умножается: три уровня по 1.5 дают не 1.5, а 3.375 от исходного
rem считается от корня документа, em — от родителя, проценты — от родителя по ширине

Точки (px) — абсолютный размер. Подходит для рамок, мелких отступов, теней.

rem — от размера шрифта корня документа, по умолчанию 16. 1.5rem = 24 всегда, где бы элемент ни лежал.

em — от размера шрифта родителя. Здесь 1.5 × 20 = 30. И это ловушка: em внутри em умножается. Три уровня вложенности по 1.5 дают не полтора, а 3,375 от исходного — текст разрастается непонятно почему.

Проценты — от родителя, причём для ширины от ширины, а для отступов тоже от ширины (не от высоты, как ожидают).

vh и vw — сотые доли высоты и ширины окна. 100vh — ровно экран.

Практическое правило: размеры шрифта и крупные отступы — в rem, мелкие детали — в точках, ширины — в процентах или долях сетки.

Отвечено вопросов: 0 из 2
width: 200px, padding: 20px, border: 5px. Какой ширины будет элемент по умолчанию?
Чем rem отличается от em?
Отвечено верно: 0 из 2

Схлопывание полей: 40 плюс 30 равно 40​

── два поля между блоками: 40px снизу и 30px сверху ──
сумма на бумаге : 70px
реальный зазор : 40px

Вертикальные внешние поля соседних блоков не складываются: берётся большее. Это не ошибка браузера, а правило, придуманное для текста — чтобы абзацы не расползались вдвое.

Знать про него надо по одной причине: иначе зазор между блоками невозможно объяснить. Вы поставили 30, получили 40 — и ищете лишнее правило, которого нет.

Три способа не встретиться с этим:

  • задавать отступ только с одной стороны — например, всегда снизу;
  • использовать расстояние между элементами сетки — там схлопывания нет вовсе;
  • изменить способ размещения родителя так, чтобы поля потомков не выходили наружу.

Первый способ проще всего и решает девять случаев из десяти.

Сброс: с чего начинают файл​

── что меняет сброс ──
без сброса: высота блока с заголовком и абзацем 77px
со сбросом: 56px
поля body при этом остаются: 8px — их сбрасывают отдельно

Двадцать одна точка разницы на двух элементах — это те самые отступы браузера из прошлой главы. На настоящей странице их десятки, и все они спорят с вашей сеткой.

Начало файла оформления, которое имеет смысл набрать наизусть:

*, *::before, *::after { box-sizing: border-box; }

body {
margin: 0;
font-family: system-ui, sans-serif;
font-size: 16px;
line-height: 1.5;
color: #e8e8ea;
background: #0e1013;
}

h1, h2, h3, p, ul { margin: 0 0 1rem; }
ul { padding-left: 1.25rem; }
img { max-width: 100%; height: auto; display: block; }
Нажми на часть выражения

Типичные ошибки​

Забыли второй способ счёта ширины. Колонки по 50 % не помещаются в строку. Лечится одной строкой в начале файла.

Правило не применилось, дописали «важно». Работает ровно один раз, дальше начинается война пометок. Правильно — посмотреть, какое правило победило, и исправить вес.

Между блоками зазор больше заданного. Схлопывание вертикальных полей.

Размер шрифта в em на нескольких уровнях. Текст растёт сам по себе.

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

Потеряли точку с запятой. Строка и следующая за ней пропадают молча — сообщения об ошибке в оформлении не бывает вовсе.

Оформление прямо в теге. Перебивается только пометкой «важно». В интерфейсе, который меняется, это тупик.

Отвечено вопросов: 0 из 2
Зачем в сбросе пишут line-height: 1.5 без единиц?
Пропала строка оформления вместе со следующей, ошибок нет. Что проверить?
Отвечено верно: 0 из 2

Слова главы​

  • Правило — селектор и блок объявлений «свойство: значение».
  • Селектор — кому применить; основной инструмент — класс.
  • Вес селектора — сколько в нём идентификаторов, классов и тегов; порядок решает только ничью.
  • Наследование — свойства про текст переходят потомкам, свойства про коробку — нет.
  • Модель коробки — по умолчанию ширина считается по содержимому, а не по элементу.
  • rem и em — от корня документа и от родителя; второе умножается при вложенности.
  • Схлопывание полей — вертикальные поля соседей не складываются, берётся большее.
  • Сброс — обнуление стилей браузера и единый способ счёта ширины в начале файла.

Тренажёр: набрать вслепую​

Цель: скорость ≥ 95 зн/мин, точность ≥ 88%

*, *::before, *::after { box-sizing: border-box; }

На чемпионате​

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

Классы, а не идентификаторы. Интерфейс на чемпионате переделывают по ходу, и оформление должно поддаваться правке.

Цвета и размеры — в переменных. Одна строка сверху, дальше они по имени; менять тему потом придётся, и лучше в одном месте:

:root { --accent: #7cf; --bg: #0e1013; --radius: 12px; }
.card { background: var(--bg); border-radius: var(--radius); }

Проверяйте на узком экране сразу. Не в конце: переделывать готовую вёрстку под телефон дороже, чем сразу не ломать.

И про время: оформление — та часть, где легко потерять час на мелочи. Сначала пусть всё работает и читается, потом красота.

Куда углубиться​

  • Переменные оформления — объявление, область действия, смена темы одной строкой.
  • Состояния элементов — под курсором, в фокусе, выключен, с ошибкой; для формы это обязательное.
  • Единицы, зависящие от окна — и почему 100vh на телефоне ведёт себя не так, как ожидается.
  • Слои каскада — современный способ управлять весом без пометок «важно».
  • Инструменты браузера — панель, в которой видно, какое правило победило и почему.

Сводная проверка по всей главе: 8 вопросов, 5:00 на всё, без подсказок по ходу. Вопросы показываются по одному, ответ изменить нельзя. Если время выйдет — экзамен завершится с тем, что успел ответить. Пересдавать можно сколько угодно раз.

Куда дальше: проверенные ресурсы​

Видео по теме

Видео1. CSS для начинающих. Введение. Подключение, базовые концепции: каскад, специфичность, наследованиеАлександр Ламков — Friendly Frontend
Видео2. Гайд по CSS-селекторам, расчёт специфичности в CSS. Приоритет и вес стилейАлександр Ламков — Friendly Frontend
Видео3. Блочная модель в CSS — свойства display, width, height, padding, margin, border и box-sizingАлександр Ламков — Friendly Frontend
Видеоbox sizing border box что это? и как его использоватьОт 0 до 1
ВидеоНаследование, специфичность и каскадность в CSSАртём - dozen web

Комментарии

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