Лекция 2. Основы CSS

Веб-программирование

Лекция 2 Основы CSS

Веб-программирование · лекция 2 из 16

На прошлой лекции

🧱HTMLструктура — разобрали
🎨CSSпредставление — сегодня
⚙️JavaScriptповедение — лекция 6

Три кита, на которых стоит любая страница. Первого прошли.

Ваша страница из ЛР 1

Валидная разметка. Правильная семантика. Заголовки по уровням, списки списками, у каждой картинки alt.

И выглядит она как документ из 1996 года.

Чего ей
не хватает?

Ответ: в разметке — ничего

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

Не хватает второго языка. Того, который отвечает на вопрос как показать.

Сегодня за 90 минут

Часть 1 · 9 минут Откуда взялся
CSS

1994 → сегодня

Вернёмся в ретро-уголок

<p><font color="red" size="4" face="Arial">Внимание!</font></p>
<p><font color="red" size="4" face="Arial">Ещё внимание!</font></p>
<center><font color="red" size="4" face="Arial">И тут</font></center>

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

Сайт из ста страниц.
Как перекрасить
все заголовки?

Открыть
сто файлов Другого ответа в той эпохе не было

1994

Хокон Виум Ли предлагает стили

Норвежский программист, работавший в ЦЕРН рядом с Бернерсом-Ли, публикует предложение Cascading HTML Style Sheets. Вместе с Бертом Босом он доводит идею до стандарта.

Оригинал предложения, 10 октября 1994

Cascading
Style Sheets Главное слово — первое. Стилей много, и нужен закон, кто кого перебивает

CSS был не один такой

DSSSLстили для SGML, мощный и неподъёмный
Violaсвои стили в раннем браузере
JSSSстили на JavaScript, от Netscape

Идея висела в воздухе. Победил вариант, который проще всех читался и не падал от незнакомой строчки.

JSSS проиграл в 1996-м

// Netscape предлагал писать стили так
document.tags.H1.color = "blue";
document.tags.P.fontSize = "12pt";

Запомните этот слайд. Идея «стили на JavaScript» вернётся через двадцать лет под именем CSS-in-JS — поговорим о ней в лекции 5.

1996

CSS1: стандарт принят

Декабрь 1996 — рекомендация W3C. Цвета, шрифты, отступы, выравнивание. Через полтора года, в мае 1998, выходит CSS2.

Браузеры поддерживают это криво, частично и по-разному. Впереди пять лет боли.

Box
model war

Главный конфликт эпохи

Один вопрос: что такое width?

Internet Explorer 5

width — это вся коробка целиком, вместе с рамкой и полями.

Спецификация

width — это только содержимое. Рамка и поля идут сверху.

Один и тот же макет разъезжался в двух браузерах. Верстальщики писали два набора стилей и подсовывали их хаками.

Чем это кончилось

Формально победила спецификация. Практически победил здравый смысл: считать ширину вместе с рамкой оказалось удобнее, и спустя пятнадцать лет в язык добавили box-sizing: border-box.

Сегодня это правило ставят первым почти в каждом проекте. Вернёмся к нему в части 5.

2003

CSS Zen Garden

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

csszengarden.com — сад жив до сих пор

Разметка не изменилась
ни на символ

Ещё одно мигание, которое не выжило

.important {
    text-decoration: blink;
}

У CSS было своё мигание — и это единственное свойство, которое спецификация прямо разрешила браузерам игнорировать. Они и перестали, все до одного. <blink> из прошлой лекции умер не в одиночку.

А какой сейчас CSS?

Никакой. После CSS2.1 единого номера версии больше нет: язык растёт модулями. У селекторов свой уровень, у цвета свой, у сеток свой — и своя готовность в браузерах.

Поэтому «поддерживается ли это» — вопрос не к версии, а к конкретному свойству. Проверяют на caniuse.com.

Часть 2 · 10 минут Как подключить
и как написать

Три способа и одно правило

Способ 1: отдельный файл

<head>
  <link rel="stylesheet" href="style.css">
</head>

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

Способ 2: блок в документе

<head>
  <style>
    h1 { color: teal; }
  </style>
</head>

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

Способ 3: прямо на элементе

<h1 style="color: teal">Заголовок</h1>

Работает, но переиспользовать нечего, читать тяжело, а перебить потом почти невозможно.

Запомните его отдельно: у атрибута style особая роль в каскаде, вернёмся к нему в части 4.

Анатомия правила

h1 {
    color: teal;
    font-size: 32px;
}
h1селектор — кого оформляем
{ ... }блок объявлений — как оформляем

Объявление — это пара

    color: teal;
colorсвойство
:двоеточие между
tealзначение

Точка с запятой в конце. У последнего объявления её можно не ставить — но ставьте: завтра допишете строку и забудете.

Комментарии

/* Заголовки статей */
h1 {
    color: teal;
}

/* color: crimson; — временно отключено */

Только такие. Двойного слэша в CSS нет: строка после // не комментарий, а мусор, который сломает правило.

Что будет,
если написать
чепуху?

HTML, как мы помним, просто молчит

CSS тоже молчит — но точечно

p {
    color: blue;
    font-sizee: 20px;   ← свойства такого нет
    background: pink;
}
Цвет и фон применятся. Непонятную строку браузер выбросит и прочитает дальше. Правило не падает целиком, страница не ломается.

Это не небрежность, а решение

Страница, использующая свойство из будущего, остаётся читаемой в старом браузере: новое он пропустит, старое применит.

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

У браузера есть свои стили

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

В DevTools такие правила подписаны user agent stylesheet. Это нижний слой каскада.

Отсюда reset и normalize

Reset

Сносит стили браузера подчистую. Дальше всё рисуете сами, с нуля.

Normalize

Не сносит, а выравнивает: чинит расхождения между браузерами, разумное оставляет.

Сегодня чаще пишут короткий собственный набор из нескольких правил. Одно из них разберём в части 5.

DevTools

Главный инструмент на весь оставшийся семестр

Что показывает вкладка Styles

Открывается по F12 или правой кнопкой → «Просмотреть код».

Часть 3 · 19 минут Селекторы

Как выбрать нужные элементы

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

К каким элементам на странице применить этот блок объявлений?

Всё остальное в правиле — уже подробности оформления.

По имени тега

p { line-height: 1.6; }
a { color: teal; }
h1, h2, h3 { font-family: Georgia, serif; }

Выбирает все такие элементы на странице. Годится для базовой типографики — и плохо годится почти для всего остального.

Класс — рабочая лошадка CSS

<div class="card">...</div>
<div class="card featured">...</div>
.card { padding: 20px; }
.featured { border: 2px solid gold; }

Один класс — на многих элементах. Несколько классов — на одном элементе, через пробел.

Имя класса — про смысл, не про вид

🙅
.red — доживёт ровно до дня, когда дизайнер попросит сделать предупреждения оранжевыми
👉
.warning — переживёт любой редизайн

Идентификатор: работает, но не надо

🙅
#header { ... } — в стилях
👉
.header { ... } — в стилях

Правило курса: id — для якорей и JavaScript, классы — для стилей.

Почему id в стилях — ловушка

Насколько именно тяжёлый — посчитаем в части 4.

Уточняем и группируем

h1, h2, h3 { margin-top: 0; }   /* одно правило — трём тегам */

p.lead { font-size: 20px; }     /* и тег, и класс сразу */

* { box-sizing: border-box; }   /* вообще всем */

Между p и .lead нет пробела — это один и тот же элемент. Пробел поменял бы смысл целиком.

Пробел — это оператор

Комбинаторы

nav a      { }   /* любая ссылка внутри nav, на любой глубине */
nav > a    { }   /* только прямые дети nav */
h2 + p     { }   /* абзац сразу после заголовка */
h2 ~ p     { }   /* все абзацы после заголовка, на том же уровне */

Разница между пробелом и > — место, где путаются чаще всего. Сейчас посмотрим её вживую.

Выбор по атрибуту

[type="checkbox"] { }   /* точное совпадение */
[href^="https"]   { }   /* начинается с https */
[href$=".pdf"]    { }   /* заканчивается на .pdf */
[class*="card"]   { }   /* содержит подстроку card */

Прямая связка с формами из прошлой лекции: разные input type оформляются по-разному, а класс дописывать не надо.

:hoverПсевдокласс — элемент прямо сейчас в таком состоянии

Состояния

a:hover      { }   /* курсор над элементом */
a:active     { }   /* прямо сейчас нажат */
a:visited    { }   /* по ссылке уже ходили */
input:focus  { }   /* поле в фокусе */
input:checked   { }   /* галка стоит */
input:disabled  { }   /* элемент выключен */

Ни одной строчки JavaScript. Состояние знает сам браузер.

:focus убирать
нельзя

Почему это не придирка

Так делать нельзя

button:focus {
    outline: none;
}

Так можно

button:focus {
    outline: 3px solid teal;
    outline-offset: 2px;
}

Тот, кто ходит по странице клавишей Tab, без видимого фокуса теряет место и не может пользоваться формой вообще.

Та же история, что с alt

В прошлой лекции договорились: alt — не формальность, а единственный способ для незрячего понять картинку.

outline — ровно то же самое для тех, кто не пользуется мышью. Убрали рамку, не дав замены, — сломали страницу, просто не для себя.

Позиция в родителе

li:first-child   { }   /* первый среди соседей */
li:last-child    { }   /* последний */
li:nth-child(3)  { }   /* третий */
li:nth-child(odd)  { }   /* нечётные: 1, 3, 5... */
tr:nth-child(2n)   { }   /* каждый второй */

Полосатая таблица — и ни одного лишнего класса в разметке.

Отрицание

p:not(.lead) { color: gray; }

li:not(:last-child) { margin-bottom: 8px; }

Второй пример — частый приём: отступ между пунктами есть, а лишнего отступа под последним нет.

Псевдоэлементы

blockquote::before {
    content: "«";
}

.external::after {
    content: " ↗";
}

Рисуют то, чего в разметке нет. Без свойства content не появятся вообще — даже пустого.

Почему двоеточий два

Псевдокласс

:hoverсостояние существующего элемента

Псевдоэлемент

::beforeновый кусок, которого в DOM нет

В CSS2 писали одно двоеточие для всего. Потом их развели по записи, а старую оставили ради совместимости — поэтому :before тоже работает.

Проверим себя

.card p { color: red; }

Сколько абзацев покрасится?

<div class="card">
  <p>первый</p>
  <blockquote><p>второй</p></blockquote>
</div>
<p>третий</p>

Проверяем

Два. Пробел означает «любой потомок на любой глубине», поэтому абзац внутри blockquote тоже попадает. Третий лежит вне карточки — мимо.

С .card > p покрасился бы только первый.

Ещё одна

li:nth-child(odd) { background: #eee; }

Список из пяти пунктов. Сколько закрасится и какие?

Проверяем

Три: первый, третий и пятый. Счёт идёт от единицы, а не от нуля, — это тот редкий случай в программировании, где нумерация человеческая.

Часть 4 · 20 минут Каскад

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

Четыре правила метят в один заголовок

h1          { color: teal; }
.title      { color: crimson; }
h1.title    { color: navy; }
#main-title { color: green; }

Какой цвет
победит?

Браузер задаёт три вопроса

1️⃣Важность и источникоткуда правило пришло
2️⃣Специфичностьнасколько точно оно метит
3️⃣Порядоккто ниже в файле

Строго по порядку. Следующий вопрос задаётся, только если предыдущий не дал ответа.

Вопрос 1: откуда правило

Вопрос 2: специфичность

Вес селектора — это тройка чисел. Сколько идентификаторов, сколько классов, сколько тегов.

Что в какой разряд

Первый#id
Второй.class, [attr], :hover
Третийdiv, ::before

Универсальный * и комбинаторы >, +, ~ не весят ничего.

Считаем вместе

nav ul li a       →  0-0-4   четыре тега

.menu .item       →  0-2-0   два класса

#sidebar          →  1-0-0   один идентификатор

ul li.active      →  0-1-2   класс и два тега

a:hover           →  0-1-1   псевдокласс и тег

Specificity Wars

Давным-давно, в 2005 году,
Эндрю Кларк расписал вес селекторов
как расстановку сил в далёкой галактике.
Аналогия пережила все браузеры той эпохи.

Andy Clarke, «CSS Specificity Wars»

Три ранга, три разряда

Тег рядовой штурмовик — их много, и каждый лёгкий 0-0-1
Класс рыцарь — тяжелее любого числа штурмовиков 0-1-0
Идентификатор тёмный лорд — в своём разряде один 1-0-0

Одиннадцать рыцарей против лорда

.a .b .c .d
.e .f .g .h
.i .j .k
0110
VS
#sidebar
100

Сравниваем слева направо: в первом разряде 1 против 0 — дальше незачем.

Раунд 1

nav ul li a
???
VS
.menu .item
???

Раунд 1 — ответ

nav ul li a
004
VS
.menu .item
020
Победили классы. Второй разряд важнее третьего, и четыре тега там не помогают совсем.

Раунд 2

a:hover
???
VS
nav a
???

Раунд 2 — ответ

a:hover
011
VS
nav a
002
Псевдокласс идёт во второй разряд — наравне с классом. Поэтому a:hover тяжелее, чем два тега.

Раунд 3

.btn.primary
???
VS
.primary.btn
???

Раунд 3 — ответ

.btn.primary
020
=
.primary.btn
020
Ничья. Специфичность ничего не решила — и тогда браузер задаёт третий вопрос: кто ниже в файле. Побеждает он.

История одного файла

.btn { background: gray } понедельник, всё хорошо
.btn { background: blue !important } вторник: «почему-то не применяется»
#page .btn { background: green !important } среда: «у меня опять не применяется»
#page .btn.btn { background: red !important } четверг: уже никто не понимает, какого цвета кнопка

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

!important — это
долговая расписка

Когда всё-таки можно

Оба случая — про лекцию 5, где будем разбирать методологии. Пока правило простое: не нужен.

Часть 4, продолжениеНаследование

Что течёт вниз по дереву

Свойство задали одному — получили многие

body {
    color: #333;
    font-family: Georgia, serif;
}

Два правила на body — и весь текст на странице сменил цвет и шрифт. Это наследование: значение спускается к потомкам.

Но не всё и не всегда

Течёт вниз

  • color
  • font-family, font-size
  • line-height
  • text-align
  • list-style

Не течёт

  • border
  • padding, margin
  • background
  • width, height

Наследуется то,
что про текст.
Не наследуется то,
что про коробку.

Наследованием можно управлять

.child { color: inherit; }   /* взять у родителя принудительно */
.child { color: initial; }   /* сбросить к значению по умолчанию */
.child { color: unset; }     /* наследуемое — наследовать,
                                остальное — сбросить */

Самый частый случай

button, input, textarea {
    font: inherit;
}

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

Итог части: алгоритм целиком

1. Важность!important бьёт всё
2. Источникбраузер → файл → style
3. Специфичностьтройка, слева направо
4. Порядоккто ниже в файле

Если правило не применилось — дело в одном из четырёх пунктов. И DevTools покажет, в каком.

Часть 5 · 16 минут Box model

Из чего состоит любой блок

Каждый элемент
на странице —
коробка

Четыре зоны

margin
border
padding
content

padding и margin

padding

Воздух внутри коробки, между рамкой и содержимым. Фон элемента заходит сюда.

margin

Расстояние снаружи, до соседей. Фон сюда не заходит — здесь уже не элемент.

Простой способ запомнить: покрасьте блок и посмотрите, докуда достаёт цвет.

Сокращённая запись

padding: 20px;                /* все четыре стороны */
padding: 10px 20px;           /* верх-низ | лево-право */
padding: 10px 20px 30px;      /* верх | лево-право | низ */
padding: 10px 20px 30px 40px; /* верх | право | низ | лево */

Четыре значения читаются по часовой стрелке, начиная сверху. margin устроен точно так же.

border — три вещи в одной строке

border: 1px solid #ccc;
/*      ↑     ↑     ↑
    толщина  стиль  цвет  */

border: 3px dashed crimson;
border-radius: 8px;

И запомните главное: рамка занимает место. Это подводка к следующему слайду.

Знаменитая кружка

CSS IS
AWESOME

Это не картинка — это живой блок с width: 300px. Слово не влезло и честно вылезло наружу.

Браузер не виноват

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

Браузер делает ровно то, что написано. Всегда. Даже когда это выглядит глупо.

width: 300px
padding: 20px
border: 5px

Сколько места блок займёт на экране?

350px 300 + 20 + 20 + 5 + 5 — поля и рамка прибавились снаружи

Тот самый спор из 1998 года

Помните box model war из первой части? Вот он и есть. По умолчанию width — это только содержимое, как и решила спецификация.

Удобно это ровно никогда: вы задаёте ширину, а получаете другую.

box-sizing решает вопрос

content-box

По умолчанию. width — содержимое, рамка и поля прибавляются снаружи.

border-box

width — вся коробка. Рамка и поля укладываются внутрь.

Поэтому почти в каждом проекте есть это

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

Первое правило в файле. Смысл простой: что написал — то и получил.

margin-bottom: 20px
margin-top: 40px

Сколько пикселей окажется между блоками?

Проверяем

верхний блок · margin-bottom: 20px
нижний блок · margin-top: 40px
40не 60

Схлопывание отступов

Соседние вертикальные margin не складываются, а берут больший из двух.

То же самое происходит между родителем и его первым ребёнком — и вот откуда берётся «дыра сверху, которую ничем не убрать».

Когда не схлопывается

Флексы и гриды — лекция 3. Пока просто знайте, что там это поведение исчезает.

Размеры

width: 300px;       /* ровно столько, хоть тресни */
max-width: 300px;   /* не шире, но может быть уже */
height: 200px;
min-height: 200px;  /* не ниже, но может вырасти */

max-width обычно полезнее: на узком экране блок сожмётся сам, и ничего никуда не вылезет.

Про единицы — пока только px

Есть ещё em, rem, проценты, vw и vh. Каждая со своей логикой, и разбирать их наспех — только путать.

Займёмся ими в лекции 3, вместе с вёрсткой. Сегодня везде пиксели.

Часть 6 · 8 минут Базовый набор

Чем уже можно оформить страницу

Цвет: четыре способа записать одно и то же

teal
#008080
#088
rgb(0 128 128)

Короткий #rgb — сокращение, где каждая цифра удваивается. В rgb() можно добавить прозрачность: rgb(0 128 128 / 50%).

Цвет и фон

.note {
    color: #333;              /* цвет текста */
    background-color: #fdf6ec; /* цвет фона */
}

color наследуется, background-color — нет. Разница из части 4 работает прямо здесь.

Один цвет стоит отдельно

Среди именованных цветов CSS есть rebeccapurple — он попал в стандарт в 2014 году.

Эрик Мейер, по чьим книгам училось верстать целое поколение, потерял дочь Ребекку. Ей было шесть. Её любимый цвет рабочая группа W3C внесла в язык.

color: rebeccapurple

Eric Meyer, «Rebecca Purple»

Шрифт: всегда список

body {
    font-family: Georgia, 'Times New Roman', serif;
}

Браузер идёт слева направо и берёт первый шрифт, который есть в системе. В конце — обязательно общее семейство: serif, sans-serif или monospace.

Текст

font-size: 18px;
font-weight: bold;        /* или 400, 700 — числом */
font-style: italic;
line-height: 1.6;         /* без единиц — это множитель */
text-align: center;
text-decoration: none;

line-height без единиц — не случайность, а рекомендация: такой множитель правильно пересчитается у потомков.

Рамки и скругления

border: 1px solid #ddd;
border-radius: 8px;

border-radius: 50%;   /* круг, если блок квадратный */

Аватарки во всех соцсетях — это ровно вот эта последняя строка.

Ссылки и списки

a {
    color: teal;
    text-decoration: none;
    border-bottom: 2px solid rgb(0 128 128 / 35%);
}

a:hover { border-bottom-color: teal; }
nav ul  { list-style: none; padding-left: 0; }

Подчёркивание через border-bottom — потому что им можно управлять: цвет, толщина, расстояние.

Колонка по центру

.container {
    max-width: 800px;
    margin: 0 auto;
}

auto слева и справа означает «поделить свободное место поровну». Блок встаёт по центру.

«Как отцентрировать div»

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

По горизонтали

margin: 0 auto — вот, готово

По вертикали

Приходите на лекцию 3

Двадцать строк CSS

Было

Веб-программирование

Разметка отвечает на вопрос, что это за содержимое.

Стили — на другой: как это показать.

Читать дальше

Стало

Веб-программирование

Разметка отвечает на вопрос, что это за содержимое.

Стили — на другой: как это показать.

Читать дальше

Разметка одна и та же — ровно то, что показал Zen Garden.

Весь справочник свойств — здесь

Свойств в CSS сотни, и держать их в голове не нужно. Нужно знать, где смотреть, — и уметь читать, что написано.

Дока — справочник на русском, с примерами и живыми песочницами.

QR-код со ссылкой на раздел CSS справочника «Дока» doka.guide/css Справочник по CSS

Часть 7 · 4 минутыЧто дальше

Что сегодня было

Что почитать

doka.guide/cssсправочник на русском, с примерами
developer.mozilla.orgMDN — первоисточник по любому свойству
web.dev/learn/cssбесплатный курс от команды Chrome
csszengarden.comтот самый сад, он до сих пор жив

Лекция 3: вёрстка средствами CSS

После неё — ЛР 2 по итогам обеих лекций.

Вопросы?

Слайды и все демо — в репозитории курса