Ось твій урок у стилі CS50! 🚀
🎨 Тема: Стилі в Angular (CSS, SCSS та View Encapsulation)
Привіт, друзі! Мене звати [Твоє Ім'я], і це... CS50 Angular Edition.
Сьогодні ми поговоримо про те, що робить наші додатки не лише функціональними, а й красивими. Але, що важливіше, ми розберемося, як зробити так, щоб ця краса не перетворила ваш код на пекло. Ми говоримо про стилі та інкапсуляцію.
1. 🔥 Вступ: Чому CSS — це небезпечно?
Уявіть собі ситуацію. Ви будуєте величезний хмарочос (ваш веб-додаток). У вас є сотні кімнат (компонентів).
Ви заходите в одну кімнату — скажімо, "Кухню" (компонент KitchenComponent) — і вирішуєте пофарбувати стіни в червоний колір. Ви пишете правило: стіна { колір: червоний; }.
Виходите в коридор... і бачите жах. УСІ стіни в усьому хмарочосі — у спальні, у ванній, у холі — стали червоними! 😱
Питання до вас: Чому так сталося?
Тому що стандартний CSS (Cascading Style Sheets) — він глобальний. За замовчуванням, клас .title діє на всю сторінку.
У великих проектах це катастрофа. Ви змінюєте кнопку в "Кошику", а ламається верстка в "Профілі користувача".
Як цього уникнути? Нам потрібна ізоляція. Нам потрібно, щоб те, що відбувається у Вегасі... тобто в компоненті, залишалося в компоненті.
В Angular це називається View Encapsulation (Інкапсуляція вигляду). І це працює магічно. Давайте зазирнемо під капот!
2. 🧠 Теоретична база: Магія під капотом
В Angular кожен компонент — це маленький самодостатній всесвіт. Він має три файли:
1. .ts (Логіка — мозок)
2. .html (Шаблон — скелет)
3. .scss/.css (Стилі — шкіра)
📌 Що треба зрозуміти залізно:
Angular бере ваші стилі й "обманює" браузер, щоб вони застосовувалися тільки до поточного компонента.
Є три режими цієї "магії" (стратегії інкапсуляції):
-
Emulated (За замовчуванням і найважливіше!) 🏆 Angular не використовує справжній Shadow DOM браузера (це складна технологія). Натомість він діє хитріше.
- Він бере ваш HTML і додає до кожного елемента унікальний атрибут, наприклад
_ngcontent-c12. - Він бере ваш CSS і переписує його:
h1 { color: red; }➡️h1[_ngcontent-c12] { color: red; } - Результат: Ваші стилі діють тільки на елементи з цим унікальним атрибутом. Сусідній компонент матиме атрибут
_ngcontent-c13, і ваші стилі його не чіпатимуть.
- Він бере ваш HTML і додає до кожного елемента унікальний атрибут, наприклад
-
None ☠️ Ніякої ізоляції. Ваші стилі стають глобальними (додаються в
<head>). Якщо ви напишете тутh1 { color: red }, всі заголовки на сайті почервоніють. Використовуйте це дуже обережно (а краще — ніколи). -
ShadowDom 🛡️ Використовує нативний API браузера для ізоляції. Це "справжня" ізоляція, але старі браузери можуть її не підтримувати, і глобальні стилі (наприклад, Bootstrap) туди не проникнуть взагалі.
🎨 CSS чи SCSS?
Angular "з коробки" підтримує SCSS (Sass). Це той самий CSS, але на стероїдах.
* Вкладеність (Nesting): Можна писати стилі один в одному, як структуру HTML.
* Змінні: $primary-color: blue;.
* У підсумку Angular все одно перетворить (скомпілює) SCSS у звичайний CSS, який розуміє браузер.
3. 🧪 Приклади: Від простого до "Ой, зламалося"
Приклад 1: Базова ізоляція
У нас є UserComponent.
user.component.scss:
h1 {
color: blue;
border-bottom: 2px solid grey;
}
user.component.html:
<h1>Привіт, я юзер!</h1>
Що ви очікуєте побачити у браузері, якщо натиснете "Inspect Element"?
Ви не побачите просто <h1>.
Реальність:
<h1 _ngcontent-ng-c42>Привіт, я юзер!</h1>
А в стилях браузера буде:
h1[_ngcontent-ng-c42] {
color: blue;
border-bottom: 2px solid grey;
}
Саме цей дивний атрибут _ngcontent... гарантує, що h1 в AdminComponent не стане синім.
Приклад 2: Використання SCSS та :host
Часто нам треба стилізувати сам компонент (його тег, наприклад <app-user>), а не те, що всередині нього. Для цього є псевдоклас :host.
user.component.scss:
:host {
display: block;
border: 1px solid black;
padding: 20px;
// SCSS Nesting: стилізуємо h1, який знаходиться всередині host
h1 {
color: green;
}
}
Це означає: "Я, компонент app-user, матиму рамку. А мої заголовки будуть зеленими".
Приклад 3: Проблема "Батьки і Діти" (і ::ng-deep)
Уявіть, що у вас є CardComponent, і ви використовуєте його всередині PageComponent.
page.component.html:
<div class="page">
<app-card></app-card> <!-- Це дитина -->
</div>
Ви хочете з батька (Page) змінити колір тексту в дитині (Card).
page.component.scss:
app-card {
.card-title { // Клас знаходиться всередині шаблону app-card
color: purple;
}
}
Питання: Чи спрацює це? Відповідь: НІ! ❌
Чому? Тому що Angular додасть атрибут батька (_ngcontent-page) до селектора. Але HTML дитини має атрибут дитини (_ngcontent-card). Вони не збігаються! Angular захищає дитину від впливу батька.
Рішення (але обережне!): ::ng-deep
app-card {
::ng-deep .card-title {
color: purple;
}
}
::ng-deep каже Angular: "Ігноруй інкапсуляцію для цього селектора!". Стиль проникне всередину дочірнього компонента.
⚠️ Увага: Використовуйте
::ng-deepТІЛЬКИ разом із:hostабо класом батька, інакше цей стиль стане глобальним для всього проекту!
4. 🛠 Практична частина
Час забруднити руки кодом! Відкрийте свій IDE.
Завдання 1: "Детектив" 🕵️♂️
- Створіть два компоненти:
HeaderComponentіFooterComponent. - В обох додайте тег
<p>Текст</p>. - У
header.component.scssзадайтеp { color: red; }. - Запустіть додаток (
ng serve). - Місія: Відкрийте DevTools (F12), знайдіть тег
<p>у Header і Footer. Подивіться на атрибути_ngcontent. Переконайтеся, що вони різні, і що Footer не червоний.
Завдання 2: "SCSS Майстер" 🎨
У app.component.scss використайте змінну та вкладеність:
$main-color: #3f51b5;
.container {
background-color: #eee;
button {
background-color: $main-color;
color: white;
&:hover {
background-color: darken($main-color, 10%);
}
}
}
Перевірте, чи працює ховер ефект.
Завдання 3: "Порушник правил" 😈
- У
HeaderComponent(.ts файл) додайте у декоратор:encapsulation: ViewEncapsulation.None. - Залиште стилі
p { color: red; }. - Подивіться на сторінку. Чи став текст у
FooterComponentчервоним? (Спойлер: Так). - Висновок: Поверніть як було, негайно!
Завдання 4: "Виклик" 🧠
Спробуйте стилізувати компонент так, щоб він мав рамку, тільки якщо у нього є клас active.
Підказка: Вам знадобиться конструкція :host(.active).
5. 💡 Мислення як у розробника
Як думають сеньйори, коли пишуть стилі в Angular?
- Компонент — це фортеця. Я пишу стилі так, ніби інших компонентів не існує. Я не боюся використовувати прості назви класів типу
.titleчи.card, бо знаю, що Angular їх ізолює. Мені не треба писати.user-profile-page-header-title. - Глобальні стилі — для глобальних речей. Шрифти, кольори бренду, скидання відступів (
reset.css) я кладу вstyles.scss(глобальний файл). Все інше — в компоненти. - Уникайте
::ng-deepяк вогню. Якщо вам доводиться його використовувати, це сигнал: "Можливо, архітектура мого компонента неправильна?". Краще передати налаштування через@Input()(наприклад,color="primary"), ніж "ламати" стилі ззовні. - Не пишіть логіку в CSS. Якщо кнопка має зникнути, використовуйте
*ngIf, а неdisplay: none, якщо це можливо з точки зору безпеки та логіки.
6. 🧩 Підсумок
Сьогодні ми зрозуміли, що:
* CSS в Angular локальний завдяки Emulated View Encapsulation.
* _ngcontent-xyz — це ті "мітки", які Angular розставляє, щоб розрізняти компоненти.
* :host дозволяє стилізувати сам контейнер компонента.
* SCSS допомагає писати чистіший код завдяки вкладеності.
Тепер ви можете фарбувати стіни у своїй "кімнаті", не боячись, що сусіди викличуть поліцію!
Що далі?
Тепер, коли наші компоненти виглядають стильно, час змусити їх змінюватись динамічно. На наступному уроці ми поговоримо про Структурні та Атрибутні Директиви (*ngIf, *ngFor, [ngClass]). Це буде як навчити наш будинок перебудовувати кімнати прямо на льоту!
А поки що — щасти вам з кодом! 👋