Способи додати CSS в JavaScript застосунок

9 хв. читання

Перед обговоренням такої неоднозначної теми як CSS в JS варто зрозуміти, що немає жорсткого правила, яке б встановлювало єдиний спосіб для обробки CSS в застосунках на React, Vue чи Angular. Кожен проєкт різний, а кожен метод має свої переваги та недоліки. Тож слід залишити всі упередження стосовно цього питання осторонь і розглянути ближче популярні варіанти додавання CSS до вашого JS-застосунку.

Які є способи

Якщо ви погуглите «Як додати CSS в [вставте сюди бажаний фреймворк]», то побачите шквал переконань та думок про те, як треба додавати стилі до проєкту. Щоб не розгубитися в такому розмаїтті, розглянемо декілька найбільш поширених методів та їх призначення детальніше.

Спосіб 1: таблиця стилів

Почнемо з найбільш знайомого підходу: таблиці стилів. Як відомо, ми можемо додати посилання на зовнішні стилі за допомогою тега <link>.

<link rel="stylesheet" href="styles.css">

Ми можемо писати звичайний та знайомий CSS і продовжувати жити нормальним життям. Нічого поганого тут немає, але якщо застосунок стане більшим та складнішим, то і підтримувати єдину таблицю стилів буде проблемніше. Обробка тисяч рядків CSS, відповідального за стилізацію всього застосунку, стане головним болем для розробників, що працюють на проєкті. До того ж можуть виникнути труднощі з підтримкою каскадності стилів. Такі інструменти як Sass або PostCSS можуть значно допомогти в такому питанні.

Можна довго використовувати можливості PostCSS для створення модульного CSS, який об'єднується за допомогою @import. Для цього треба трохи попотіти з Webpack-конфігом, аби налаштувати все правильно, але впоратись з цим можливо.

Неважливо, який компілятор ви вирішити використовувати, все одно отримаєте один CSS-файл з усіма стилями проєкту, підключений за допомогою <link>. Залежно від складності застосунку, цей файл може виявитись роздутим та важким для асинхронного завантаження, а це призведе до проблем з рендерингом.

Однак такий спосіб має свої переваги. Для маленьких застосунків або тих, де немає основного фокуса на фронтенд-частині, єдина таблиця стилів може бути хорошим варіантом. Так ми отримуємо чисте розділення бізнес-логіки та стилів застосунку. Стилі не генеруються нашим застосунком, тому вони під повним контролем розробників і можна бути впевненим в отриманому результаті. До того ж єдиний CSS файл легше кешувати браузеру, тому коли користувач повторно відкриє застосунок, йому не потрібно буде заново завантажувати файл зі стилями.

Але припустимо, що нам потрібна надійніша CSS-архітектура, що дозволила б нам використовувати усю міць інструментів. Щось, що допоможе нам досягнути більш тонкого підходу до створення застосунку. І це...

Спосіб 2: CSS-модулі

Достатньо великою проблемою у випадку з єдиною таблицею стилів є ризик регресії. Використавши селектор з іншою специфічністю, ви можете зламати стилі в зовсім іншій частині вашого застосунку. Тут на допомогу приходить підхід, який називають «стилі з обмеженою областю видимості».

Такий спосіб дозволяє нам програмно генерувати назви класів, специфічні для компонента. Так ми обмежуємо область видимості цих стилів певним компонентом, впевнившись, що назва класу буде унікальною, наприклад header__2lexd. Назва класу тут містить хешовану частину, яка є унікальною. Тож навіть якщо у вас є ще один компонент header, ви можете застосувати до нього відповідний клас, до назви якого згодом буде додано суфікс хешу: наприклад header__15qy_.

CSS-модулі пропонують різні способи контролювати генеровані назви класів — залежно від реалізації. Детальніше цей процес описаний у документації.

В підсумку ми все ще генеруємо єдиний CSS-файл, який підключається до браузера за допомогою тега <link>. Тож отримуємо ті самі потенційні недоліки (блокування рендерингу, роздування файлу тощо) та ті самі переваги (здебільшого кешування), охоплені вище. Однак цей спосіб, як видно з його назви, має одну додаткову перевагу: уникання глобальної області видимості.

Припустимо, ви хочете використати глобальний клас .screen-reader-text, який можна застосувати до будь-якого компонента в застосунку. З CSS-модулями, вам необхідно було б звернутися до псевдоселектора :global, який явно вказує, що визначені стилі є глобальними, а тому їх можуть використовувати інші компоненти застосунку. Якщо ви імпортуєте стилі, котрі мають блок :global, ви використовуєте глобальний селектор. Не дуже великий недолік, але до цього треба звикнути.

Поглянемо, який все це матиме вигляд:

// typography.css
:global {
  .aligncenter {
    text-align: center;
  }
  .alignright {
    text-align: right;
  }
  .alignleft {
    text-align: left;
  }
}

Ви можете опинитись в ситуації, коли глобальні селектори для типографії, форм і просто загальні елементи опиняться в єдиному :global-селекторі. На щастя, завдяки магії таких інструментів як PostCSS Nested чи Sass, ви можете імпортувати частини стилів одразу в селектор, щоб все стало чистіше:

// main.scss
:global {
  @import "typography";
  @import "forms";
}

Так ви можете спочатку визначити стилі без селектора :global, а потім просто імпортувати їх у вашу основну таблицю стилів.

Ще один момент, до якого варто звикнути — як посилатися на назви класів в межах вузлів DOM. Детальніше про це в документаціях Vue, React та Angular.

На невеликому прикладі подивимось, який це матиме вигляд у React-компоненті:

// ./css/Button.css

.btn {
  background-color: blanchedalmond;
  font-size: 1.4rem;
  padding: 1rem 2rem;
  text-transform: uppercase;
  transition: background-color ease 300ms, border-color ease 300ms;

  &:hover {
    background-color: #000;
    color: #fff;
  }
}

// ./Button.js

import styles from "./css/Button.css";

const Button = () => (
  <button className={styles.btn}>
    Click me!
  </button>
);

export default Button;

CSS-модулі стануть вам у пригоді, якщо ви створюєте застосунок, котрий повинен поєднувати переваги продуктивності статичного застосунку, а також стилі з обмеженою областю видимості.

Варто також зазначити, що CSS-модулі можуть використовуватись у поєднанні з вашим улюбленим CSS-препроцесором: Sass, Less, PostCSS тощо.

Але ваш застосунок може також отримати додаткові переваги, якщо додати CSS в JS. Це може бути, наприклад, отримання доступу до різних станів вашого компоненту, що дає змогу реагувати на них відповідно.

Спосіб 3: CSS-in-JS

CSS-in-JS — досить широка тема. Існують пакети, які допомагають зробити написання CSS-in-JS найменш болючим: JSS, Emotion, Styled Components тощо.

В загальних рисах принцип роботи CSS-in-JS дуже подібний до згаданих фреймворків. Ви пишете CSS, який стосується окремого компонента, а збирається все докупи на етапі збірки. Коли це відбувається, більшість фреймворків CSS-in-JS показиватимуть відповідний CSS тільки тих компонентів, які рендеряться на сторінці в певний момент. Такий CSS розташовується між тегами <style> в <head> вашого застосунку. До того ж, подібно до CSS-модулів, стилі мають обмежену область видимості, а назви класів містять хешовані значення.

Коли ви будете рухатись вашим застосунком, компоненти, які зникатимуть, також видалятимуть свої стилі з <head>, а їх місце займуть стилі нових компонентів. Так наш застосунок отримує переваги продуктивності, адже не треба робити HTTP-запит, не блокується рендеринг, а користувач точно побачить на своїй сторінці потрібний вміст з потрібними стилями.

Інша цікава можливість CSS-in-JS — можна посилатися на стан декількох компонентів та функцій, щоб рендерити різний CSS.

Оскільки CSS-in-JS — досить обговорювана тема, серед розробників склалися різні думки з приводу цього питання. Оглянемо деякі важливі для розуміння моменти в CSS-in-JS:

  • Якщо ми використовуємо CSS-in-JS, ми пишемо справжній CSS. Деякі пакети пропонують писати CSS за допомогою шаблонних літералів, натомість назви властивостей повинні бути camelCase (наприклад, padding-left перетворюється на paddingLeft).
  • Деякі CSS-in-JS-рішення вимагають писати вбудовані стилі для елементів. Синтаксис для цього, особливо у випадку зі складними компонентами, має досить брудний вигляд.
  • CSS-in-JS дає потужні можливості, які складно реалізувати за допомогою CSS-модулів чи стандартних таблиць стилю.
  • Необхідно мати можливість користуватися такими фічами CSS як вкладеність та змінні. Також треба мати змогу підключити такі додаткові інструменти як Autoprefixer, щоб покращити процес розробки.

Одразу невеликий приклад того, яким може бути компонент React з використанням Styled Components:

// ./Button.js
import styled from 'styled-components';

const StyledButton= styled.button`
  background-color: blanchedalmond;
  font-size: 1.4rem;
  padding: 1rem 2rem;
  text-transform: uppercase;
  transition: background-color ease 300ms, border-color ease 300ms;

  &:hover {
    background-color: #000;
    color: #fff;
  }
`;

const Button = () => (
  <StyledButton>
    Click Me!
  </StyledButton>
);

export default Button;

Варто також оглянути потенційні недоліки підходу CSS-in-JS. З таким підходом надзвичайно легко отримати роздутий JS-файл з сотнями рядків CSS, в якому складно знайти методи компонентів чи хоча б його HTML-структуру. Однак такий недолік можна розглядати як можливість поглянути зблизька на те, як та чому ми створюємо компоненти такими, які вони є. Якщо добре поміркувати, то недолік стає перевагою, котра змушує писати нас чистіший код і створювати більш повторно використовувані компоненти.

Варто також помітити, що з CSS-in-JS повністю стирається межа між бізнес-логікою та стилями застосунку. Однак з добре задокументованою та обдуманою архітектурою інші розробники на проєкті також вважатимуть такий підхід вдалим.

Висновок

Існує декілька способів організувати структуру CSS в застосунку. Те, що розробники мають багато варіантів для вибору — це круто, але водночас збиває з пантелику. Однак наприкінці всі доходять висновку, що кожне рішення має і переваги, і недоліки. Це все про те, як ми ретельно та обдумано реалізуємо систему, що змушує майбутніх нас та інших розробників, які працюватимуть з нашим кодом, дякувати за витрачений час на створення такої структури застосунку.

Помітили помилку? Повідомте автору, для цього достатньо виділити текст з помилкою та натиснути Ctrl+Enter
Codeguida 5.6K
Приєднався: 8 місяців тому
Коментарі (0)

    Ще немає коментарів

Щоб залишити коментар необхідно авторизуватися.

Вхід / Реєстрація