Вложенность (nesting)
Что такое вложенность
Nesting — запись CSS-правил внутри других правил.
.card {
padding: 20px;
.title {
font-size: 20px;
}
.text {
color: gray;
}
}
Компилируется в:
.card { padding: 20px; }
.card .title { font-size: 20px; }
.card .text { color: gray; }
Что даёт: CSS повторяет структуру HTML.
Вложенность селекторов
Без вложенности:
.nav ul { list-style: none; }
.nav ul li { display: inline; }
.nav ul li a { color: black; }
С вложенностью:
.nav {
ul {
list-style: none;
li {
display: inline;
a {
color: black;
}
}
}
}
Что даёт: видно структуру.
& — родительский селектор
& — ссылка на родителя.
.button {
background: blue;
&:hover {
background: darkblue;
}
&.active {
background: green;
}
&:focus-visible {
outline: 2px solid blue;
}
}
Компилируется в:
.button { background: blue; }
.button:hover { background: darkblue; }
.button.active { background: green; }
.button:focus-visible { outline: 2px solid blue; }
Правило: & без пробела — приклеивает к родителю. С пробелом — потомок.
& в BEM
BEM-модификаторы:
.button {
padding: 10px 20px;
&--large {
padding: 16px 32px;
font-size: 18px;
}
&--primary {
background: blue;
}
&--danger {
background: red;
}
}
Компилируется в:
.button { padding: 10px 20px; }
.button--large { padding: 16px 32px; font-size: 18px; }
.button--primary { background: blue; }
.button--danger { background: red; }
Правило: &--modifier — стандарт для BEM.
&__element
.card {
padding: 20px;
&__title {
font-size: 20px;
}
&__text {
color: gray;
}
}
Компилируется в:
.card { padding: 20px; }
.card__title { font-size: 20px; }
.card__text { color: gray; }
Что даёт: BEM-структура без длинных селекторов.
& с контекстом
Родитель + доп. класс:
.button {
&--primary {
&:hover {
background: darkblue;
}
}
}
Компилируется в:
.button--primary:hover { background: darkblue; }
& в конце
Родитель становится потомком:
.icon {
.card & {
color: red;
}
}
Компилируется в:
.card .icon { color: red; }
Что даёт: стили родителя, когда он внутри чего-то.
Правило: & можно использовать в любом месте селектора.
Комбинаторы
.card {
> .title {
font-size: 20px;
}
+ .card {
margin-top: 16px;
}
~ .card {
margin-top: 16px;
}
}
Что даёт: прямые дети, соседи.
Вложенные медиазапросы
.card {
padding: 16px;
@media (min-width: 768px) {
padding: 24px;
}
}
Компилируется в:
.card { padding: 16px; }
@media (min-width: 768px) {
.card { padding: 24px; }
}
Что даёт: медиазапрос рядом с правилом.
Правило: в SCSS медиазапросы вкладываются, в CSS — нет.
Вложенные @supports
.grid {
display: flex;
@supports (display: grid) {
display: grid;
}
}
Что даёт: прогрессивное улучшение.
@at-root
Выйти из вложенности:
.parent {
@at-root .child {
color: red;
}
}
Компилируется в:
.child { color: red; }
Когда: нужно вложить для читаемости, но получить плоский CSS.
Правило: редко нужно.
Глубина вложенности
Плохо:
.page {
.container {
.row {
.col {
.card {
.title {
.link {
color: red;
}
}
}
}
}
}
}
Компилируется в:
.page .container .row .col .card .title .link { color: red; }
Проблемы:
- Высокая специфичность.
- Тяжело переопределить.
- Медленнее.
- Хрупко.
Правило: максимум 3 уровня вложенности.
BEM + nesting
Правильно:
.card {
padding: 20px;
&__title {
font-size: 20px;
&--large {
font-size: 28px;
}
}
&__text {
color: gray;
}
&:hover {
border-color: blue;
}
}
Компилируется в плоский CSS:
.card { }
.card__title { }
.card__title--large { }
.card__text { }
.card:hover { }
Что даёт: читаемость SCSS + плоский CSS.
Практика
1. BEM-компонент:
.button {
padding: 12px 24px;
border: none;
border-radius: 8px;
cursor: pointer;
transition: background 0.15s;
&--primary {
background: #c1442e;
color: white;
&:hover {
background: #a83926;
}
}
&--secondary {
background: transparent;
border: 1px solid #e5e5e5;
&:hover {
border-color: #c1442e;
}
}
&--large {
padding: 16px 32px;
font-size: 18px;
}
}
2. Медиазапросы внутри компонента.
3. & в комбинаторах.
4. Проверьте скомпилированный CSS — плоский?
Частые ошибки
1. Слишком глубокая вложенность:
.a .b .c .d .e .f { }
Решение: BEM, плоские селекторы.
2. & с пробелом:
.button {
& :hover { } // .button :hover (не то)
}
Решение: &:hover.
3. Всё в одном месте:
body {
.button { }
.card { }
.modal { }
}
Решение: отдельные файлы.
4. Дубли стилей:
.button { }
.card .button { }
.modal .button { }
Решение: один .button, модификаторы.
5. & для всего:
.title { & { & { } } }
Решение: использовать осмысленно.
6. Забыть про специфичность:
.page .card .title { } // 0,3,0
Решение: BEM, 0,1,0.
7. Вложенность как в HTML:
Повторяет структуру один-в-один
Решение: по смыслу, не по DOM.
8. @at-root везде:
Хуже читается
Решение: только когда нужно.
Итог
- Nesting — CSS как HTML.
&— родитель.&:hover— псевдокласс.&--modifier— BEM.&__element— BEM.- Медиазапросы вкладываются.
- Максимум 3 уровня.
@at-root— редко.- BEM + nesting — читаемость + плоский CSS.
Дальше — партиалы и импорты.