Към съдържанието
wannacode

Селектори и каскада

Накратко: CSS селекторът избира елементите, за които е правилото, а каскадата решава кое правило печели при спор: произход, специфичност и ред.

Проблем

Цената не става червена

Магазинът пуска промоция: цената на хляба трябва да е червена. Колега добавя правило за .price най-долу в style.css. Цената става по-голяма и удебелена, но остава тъмносива.

HTML, CSS, JS

Конзолата е празна: CSS не дава грешки. Правилото е последно във файла и хваща цената, защото размерът и удебеляването минават. Не минава само цветът. Друго правило иска друг цвят за същия абзац, и браузърът е избрал него.

Идеята

Правило и селектор

CSS казва как изглежда всеки елемент от дървото. Казва го с правила:

.price {
color: #c0392b;
font-size: 20px;
}
  • .price е селекторът: кои елементи хваща правилото.
  • В скобите са декларациите: свойство, двоеточие, стойност и точка и запетая.

Селекторите търсят в дървото, затова са като въпроси към него:

  • p (тип): всеки <p>.
  • .price (клас): всеки елемент с class="price". Елементът може да има няколко класа: class="price sale".
  • #product (id): елементът с id="product".
  • [type="email"] (атрибут): елементите с този атрибут и тази стойност, например input[type="email"].
  • article p (наследник, с интервал): <p> някъде в <article>, на каквато и да е дълбочина.
  • nav > a (дете): <a>, който е пряко дете на <nav>.
  • .price.sale (без интервал): един елемент с двата класа.
  • h1, h2 (списък): правилото важи и за двата.

Стиловете се пишат главно с класове. Типът хваща всеки абзац на сайта, а id е за един елемент. Класът слагаш точно където трябва, и той не зависи от това как е подредено дървото.

Пробвай

Хвани точно тези

Махни подчертаването само на връзките в менюто (връзката в долната част остава подчертана) и удебели двете цени, без да удебеляваш описанията. Свойствата са text-decoration: none и font-weight: 700.

HTML, CSS, JS

Идеята

Каскадата

Цената от началото се хваща от две правила, и двете задават color. Браузърът трябва да избере едно. Това правило за избор се казва каскада. Тя сравнява на три нива и спира на първото, което реши:

  1. Произход. Браузърът има свои стилове: затова <h1> е голям, а връзката е синя и подчертана. Твоят CSS ги бие.
  2. Специфичност. Колко точен е селекторът. Тя е три числа: колко id, колко класа, колко типа. p е 0,0,1, .price е 0,1,0, #product p е 1,0,1. Атрибутите ([type="email"]) и състоянията (:hover) броят като класове. Числата се сравняват колона по колона отляво. Щом една колона е различна, решено е: 1,0,1 бие 0,1,0.
  3. Ред. При равна специфичност печели правилото, което е по-късно в кода.

Каскадата решава всяко свойство поотделно. Затова от .price минават font-size и font-weight: за тях друг кандидат няма. За color има, и той е по-силен.

Има и !important: color: #c0392b !important бие всяка обикновена декларация, каквато и да е специфичността. Работи, но после всяка промяна на цвета иска ново !important. Затова е знак, че някъде има твърде силен селектор, а не поправка.

Виж го

Виж как се избира

Четири правила и един елемент. Гледай как браузърът решава color и font-size поотделно.

/* <article id="product">
<p class="price sale">1,80 €</p>
</article> */
p { color: #555; font-size: 16px; }
.price { color: #c0392b; font-size: 20px; }
#product p { color: #222; }
.sale { font-size: 24px; }
Стъпка по стъпка, с думи
  1. Един елемент: <p> с класовете price и sale, в <article id="product">. И четирите селектора го хващат. Две от правилата искат да зададат color, а три искат font-size.
  2. Специфичността на селектора е три числа: колко id, колко класа, колко типа. #product p има едно id и един тип: 1,0,1.
  3. color: задават го три правила. Браузърът сравнява първата колона: 1 бие 0 и по-нататък не гледа. #product p печели, макар че .price е след него.
  4. font-size: пак три правила. Колоната id е равна (0). В колоната клас p отпада с 0. .price и .sale са равни и в трите колони.
  5. При равна специфичност печели правилото, което е по-късно в кода. .sale е на ред 7, след .price, затова font-size е 24px.
  6. Всяко свойство има свой победител: color от #product p, font-size от .sale. Правилото .price хваща елемента и пак губи и в двете.

Ето същият код в браузъра. Цената е тъмносива и в 24px, както в сцената. Пробвай да размениш местата на .price и .sale: размерът се сменя, а цветът не. Отвори инструментите за разработчици (F12), избери цената и виж панела Styles: загубилите декларации са зачертани.

HTML, CSS, JS

Идеята

Наследяване

Някои свойства минават от родителя към децата. Ако елементът няма свое правило за тях, той взима стойността на родителя. Това е наследяване.

  • Наследяват се свойствата на текста: color, font-family, font-size, font-weight, line-height, text-align.
  • Не се наследяват свойствата на кутията: border, padding, margin, background, width. Рамка около картата не значи рамка около всеки абзац в нея.

Наследената стойност е най-слабата. Всяко правило, което хваща елемента пряко, я бие, дори p с 0,0,1. Бутоните и полетата имат свой шрифт и цвят от браузъра, затова не наследяват. inherit иска наследяване изрично: button { font-family: inherit; }.

HTML, CSS, JS

Текстът на картата е зелен и с шрифта Georgia, но рамката е само около картата. Бутонът взе шрифта заради inherit, а цветът му е останал черен: за color такова правило няма.

Пробвай

Поправи цената

Направи цената червена (#c0392b), без !important. Описанието трябва да остане тъмносиво (#222).

HTML, CSS, JS

Пробвай

Намери грешката

Цената има класовете price и sale, но не е червена. Защо?

Избери реда с грешката.

Пробвай

Попълни

Менюто има връзки и вложен списък с още връзки. Само връзките, които са преки деца на <nav>, трябва да са без подчертаване.

nav  a {
  text-decoration: none;
}
По-точно, за любопитните

Произходът. Източниците са три: браузърът, потребителят (настройки и разширения) и авторът, тоест ти. При обикновените декларации авторът бие потребителя, а потребителят бие браузъра. При !important редът се обръща: !important на потребителя бие твоето. Така човек със слабо зрение може да наложи по-голям шрифт на всеки сайт.

style="…". Стилът в атрибута на елемента бие всеки селектор от файла. Затова и той е капан, както !important.

Колоните не преливат. 0,11,0 не е 1,1,0. Единадесет класа не бият едно id: сравнението свършва още в първата колона.

Какво не брои. * е 0,0,0. Комбинаторите (интервал, >, +, ~) не добавят нищо. Псевдоелементите (::before) броят като тип.

:is(), :not() и :where(). :is() и :not() вземат специфичността на най-силния си аргумент. :where() е винаги 0,0,0: удобно е за стилове по подразбиране, които всяко правило надвива.

Слоеве. @layer подрежда цели групи правила, и слоят решава преди специфичността. Големите библиотеки със стилове го ползват, за да не се бият с твоя CSS.

Ключовите думи. inherit взима стойността на родителя. initial е началната стойност на свойството от стандарта (за display това е inline). unset е inherit за наследяемите свойства и initial за другите. revert връща стила на браузъра.

Упражнение

Промоцията в каталога

Каталогът има три продукта, а млякото е в промоция (класът sale на картата). Целият текст в каталога е #222, а цените са удебелени. Цената на продукта в промоция е червена (#c0392b), а старата цена в нея е сива (#777). Етикетът −20% е с бял текст (#fff) на червен фон (#c0392b). Другите цени остават #222. Не ползвай !important.

HTML, CSS, JS

Тест

Провери се

1. Каква е специфичността на #cart .item a?
2. Първо е article p { color: gray; }, после .price { color: red; }. Какъв е цветът на <p class="price"> в <article>?
3. .card { color: green; border: 1px solid; }. Какво получава <p> вътре в картата, ако за него няма друго правило?
4. Защо !important е лош знак в кода?
5. Защо стиловете се пишат главно с класове, а не с id?

Създаден от Иво Гергов като част от кампанията на Evo Tech за достъпно обучение по програмиране ·