Модуль 37

CSS у React та Angular

Ось урок, згенерований спеціально для вас у стилі CS50, але рідною мовою. Поїхали!


🎨 Тема уроку: CSS у React та Angular — Як не "заляпати фарбою" сусідню кімнату

Привіт, друзі! Радий бачити вас. Сьогодні ми розберемо одну з найбільш недооцінених, але критично важливих тем сучасної розробки. Ми говоримо про стилізацію компонентів.

1. 🔥 Вступ: проблема та мотивація

Уявіть собі таку ситуацію. Ви живете у величезному багатоквартирному будинку (це ваш веб-застосунок). Ви вирішуєте пофарбувати стіни у своїй вітальні в затишний червоний колір. Ви берете фарбу, мажете стіну, і... раптом усі вітальні в усьому будинку стають червоними!

Навіть у сусідів. Навіть у підвалі.

Звучить як магія? Або як кошмар? У веб-розробці це називається Global CSS (Глобальні стилі).

Коли ми просто підключаємо style.css у index.html, клас .button діє на всі кнопки на сайті. Але ж ми з вами будуємо сучасні інтерфейси на React та Angular. Ми мислимо компонентами.

Питання до вас:

Якщо я створюю компонент LoginButton, а мій колега створює DeleteButton, і ми обидва назвемо клас просто .btn — чия кнопка "переможе"? І чи хочемо ми взагалі думати про це і боятися конфліктів?

Звісно, ні. Нам потрібна ізоляція. Нам потрібно, щоб стиль належав компоненту так само, як його HTML і логіка.

Сьогодні ми дізнаємося, як React та Angular вирішують цю проблему по-різному, але з однією метою: зробити ваш код передбачуваним.


2. 🧠 Теоретична база (без нудних лекцій)

Давайте зазирнемо "під капот". Як фреймворки гарантують, що ваші стилі не втечуть?

🅰️ Angular: View Encapsulation (Інкапсуляція виду)

Angular — це "батарейки в комплекті". Він має вбудований механізм. Коли ви пишете CSS у файлі component.css, Angular робить хитру річ під час компіляції.

Він не змінює ваші класи. Він додає унікальний "атрибут-штрихкод" до кожного HTML-елемента компонента.

Як це виглядає: 1. Ви пишете: h1 { color: blue; } 2. Angular перетворює це на: h1[_ngcontent-c123] { color: blue; } 3. У HTML він додає: <h1 _ngcontent-c123>Привіт</h1>

Інтуїція: Це як видати кожному жителю квартири спеціальний бейдж, і охоронець (браузер) пускає стиль тільки до тих, у кого є цей бейдж.

⚛️ React: CSS Modules (та CSS-in-JS)

React — це бібліотека, тому він менш суворий. Але стандарт де-факто — це CSS Modules (або бібліотеки типу Styled Components).

CSS Modules працюють інакше. Вони не додають атрибути. Вони змінюють імена класів.

Як це виглядає: 1. Ви пишете у файлі Button.module.css: .btn { color: red; } 2. React (через збирач типу Webpack/Vite) перетворює це на унікальний хеш: .Button_btn__x9zK1 { color: red; }

Інтуїція: Це якби ви назвали свого кота "Мурчик", а паспортний стіл автоматично перейменував його на "Мурчик_ID992834", щоб у місті не було плутанини з іншими котами.

📌 Що треба запам'ятати залізно:

  • Глобальний CSS — це ризик конфліктів.
  • Angular ізолює стилі через атрибути (_ngcontent).
  • React (Modules) ізолює стилі через унікальні імена класів.

3. 🧪 Приклади (від простого до реального)

Давайте подивимось на це в дії.

Приклад 1: Проста кнопка в React

Ви очікуєте, що клас буде називатися .primary, правда? Давайте перевіримо.

Файл: Button.module.css

.primary {
  background-color: blue;
  color: white;
}

Файл: Button.jsx

import styles from './Button.module.css'; // Імпортуємо як об'єкт

export default function Button() {
  // Зверніть увагу: ми не пишемо className="primary"
  // Ми звертаємось до об'єкта styles
  return <button className={styles.primary}>Click me</button>;
}

Результат у браузері:

<button class="Button_primary__2gH5s">Click me</button>

Чому так? Тому що styles.primary — це згенерований рядок. Стиль застосувався, і він ніколи не перетнеться з іншим .primary в іншій частині програми.


Приклад 2: Картка користувача в Angular

Файл: user-card.component.ts

@Component({
  selector: 'app-user-card',
  template: `
    <div class="card">
      <h3>User Name</h3>
    </div>
  `,
  styles: [`
    .card { border: 1px solid red; padding: 10px; }
  `]
})
export class UserCardComponent {}

Питання до вас:

Якщо я створю інший компонент ProductCard і теж дам йому клас .card, але з синьою рамкою — чи стане рамка користувача фіолетовою (червоний + синій)?

Відповідь: Ні! Angular скомпілює це так:

.card[_ngcontent-ng-c45] { border: 1px solid red; ... }

А для продукту атрибут буде іншим, наприклад _ngcontent-ng-c50. Конфлікт неможливий.


4. 🛠 Практична частина

Час забруднити руки кодом! (Але не забруднити глобальний простір імен 😉).

Завдання 1: "Двійник" * (React) Створіть два компоненти: Header і Footer. * У кожному створіть CSS модуль з класом .container. * У Header зробіть фон чорним, у Footer — сірим. * Переконайтеся в інспекторі браузера, що імена класів різні.

Завдання 2: "Злом системи" (Angular) * Створіть компонент. Напишіть стиль для тегу p { color: red; }. * У файлі styles.css (глобальному) напишіть p { color: green !important; }. * Подивіться, хто переміг. Чому? (Підказка: специфічність CSS + !important).

Завдання 3: "Динаміка" * (React) Зробіть кнопку, яка стає зеленою, якщо пропс isActive дорівнює true. Використовуйте шаблонні рядки: className={`${styles.btn} ${isActive ? styles.active : ''}`}.

Завдання 4: Міні-кейс "Чужий код" * Уявіть, що ви використовуєте готову бібліотеку компонентів, і вам треба змінити колір її кнопки, але ви не маєте доступу до її коду. * (Angular) Спробуйте використати ::ng-deep (обережно, це як ядерна зброя!). * (React) Спробуйте обернути компонент у div і стилізувати через каскад.


5. 💡 Мислення як у розробника

Як відрізнити новачка від сеньйора у роботі зі стилями?

  1. Помилка новачка: Писати все в одному файлі App.css на 2000 рядків і використовувати БЕМ (BEM) вручну (block__element--modifier), коли фреймворк може зробити ізоляцію автоматично.
  2. Помилка новачка: Зловживання !important. Якщо ви пишете це слово — ви, швидше за все, програли битву зі специфічністю. Зупиніться і подумайте.

Як думає профі: * "Цей компонент має бути портативним. Якщо я скопіюю папку з компонентом в інший проєкт, він має виглядати так само без додаткових налаштувань". * Композиція: Замість одного величезного стилю для "Супер-Картки", профі створить маленькі стилізовані атоми: Avatar, Title, Badge.

Порада: Не бійтеся створювати багато маленьких CSS-файлів (по одному на компонент). Це не "сміття", це модульність.


6. 🧩 Підсумок

Отже, що ми маємо в сухому залишку?

  1. Ми більше не боїмося називати класи простими іменами типу .wrapper чи .title.
  2. Ми знаємо, що React хешує класи, а Angular маркує атрибути.
  3. Ми зрозуміли, що ізоляція стилів — це запорука спокійного сну розробника.

Тепер ви вмієте фарбувати свою "кімнату" (компонент) у будь-який колір, не боячись, що сусіди прийдуть скаржитися!

🔍 Що далі? Тепер, коли ми маємо красиві статичні компоненти, настав час оживити їх даними. На наступному уроці ми поговоримо про те, як компоненти спілкуються між собою, передаючи дані, наче естафетну паличку. Готуйтеся до теми: Props та Input/Output!

А поки що — щасти вам з кодом! 🚀