CSS и стили в React

  • Михаил
  • 8 мин. на прочтение
  • 65
  • 27 Jun 2021
  • 27 Jun 2021

Стилизация — это отдельная тема в React. React не предлагает собственного решения для упрощения стилизации, однако появление CSS-in-JS немного встряхнуло ситуацию. Широко принята и любима одними, но горячо обсуждается другими. Благодаря CSS-in-JS стилизация компонентов также переносится в JavaScript, чтобы не нарушать парадигму разработки на основе компонентов. Но давайте начнем с основ и постепенно рассмотрим эту тему.

Стилизация с помощью атрибута style
Самый простой способ стилизовать компоненты в React — использовать styleатрибут в обычных элементах HTML. Однако он отличается от обычного HTML. Компоненты React ожидают объект в форме property: value. Само свойство должно быть объявлено в форме JavaScript (а не в его обычном аналоге CSS), что означает zIndexвместо z-index, backgroundColorвместо background-colorили marginTopвместо margin-top. Если значения принимают объявления в пикселях, необязательно явно определять pxсоответствующую единицу измерения:

<div style={{ border: '1px solid #ccc', marginBottom: 10 }}>
 A div with a grey border and a 10 pixel margin at the bottom
</div>

Значения, которые не используются с единицей измерения (например z-index, flexили fontWeight), не затрагиваются этим и могут использоваться так же, как мы привыкли. React не добавляет pxк ним.

Используя объект вместо строки, React сохраняет единый подход к работе со стилями. Свойство Regular styleэлементов DOM document.getElementById('root').styleтакже является объектом и гарантирует их безопасность путем предотвращения XSS.

Хотя использование встроенного стиля не совсем рекомендуется, иногда оно может быть полезно, если стиль элемента зависит от определенных значений в состоянии.

Использование классов CSS в JSX
Гораздо чище и приятнее использовать настоящие классы CSS в JSX, как и в обычном HTML, с той разницей, что мы объявляем классы, используя classNameвместо class:

<div className="item">...</div>

React отображает обычный синтаксис с помощью нашего HTML-эквивалента:

<div class="item">...</div>

Также довольно распространено динамическое объединение значений в classNameреквизите:

render() {
 let className = 'item';
 if (this.state.selectedItem === this.props.itemId) {
   className += ' item--selected';
 }
 return (
   <div className={className}>
     ...
   </div>
 );
}

В этом примере значение для classNameв itemкаждом случае. Если выбранный элемент является текущим элементом, он также получает класс item item--selected.

Пакет classnames стал де-факто стандартом для определения классов на основе условия. Его можно установить через CLI:

npm install classnames

или

yarn add classnames

Теперь нам нужно импортировать пакет только в те компоненты, где мы хотим его использовать:

import classNames from 'classnames';

Таким образом, мы импортируем функцию и даем ей имя. classNames.Функция ожидает произвольное количество параметров, которые могут быть строкой или объектом в форме { class: true | false }. Это работает аналогично тому, что вы уже могли ожидать: если значение в условии равно true, classNamesиспользуется класс с тем же именем свойства:

render() {
 return (
   <div className={classNames('item', {
     'item--selected': this.state.selectedId === this.props.itemId
   })}>
     ...
   </div>
 );
}

Объекты также можно использовать для работы с несколькими свойствами. Можно установить несколько классов, если условие true:

render() {
 return (
   <div className={classNames({
     'item': true,
     'item--selected': this.state.selectedId === this.props.itemId
   })}>
     ...
   </div>
 );
}

Если используются обычные классы CSS, мы также должны убедиться, что соответствующая таблица стилей также связана с HTML-документом. React обычно не заботится об этом самостоятельно.

Модульный CSS с CSS-модулями
Модули CSS являются своего рода предшественниками CSS-in-JS и сочетают в себе ряд свойств модулей CSS и JavaScript. Как уже следует из названия, CSS находится в собственных импортируемых модулях , которые, однако, содержат чистый CSS и привязаны к одному конкретному компоненту. Если бы нам нужно было разработать компонент для отображения изображения профиля в файле с именем ProfileImage.js, подход модулей CSS часто вводит другой файл с именем ProfileImage.module.css. Когда эти модули CSS импортируются, генерируется загадочное имя класса, чтобы гарантировать, что имя класса используется только в единственный компонент. Целью этого является предотвращение случайного использования имен классов двумя разными компонентами.

Модули CSS — это прежде всего всего лишь концепция, и они не диктуют конкретный подход или реализацию. Реализация достигается такими инструментами, как css-loaderWebpack.

На самом деле нет необходимости принудительно завершать файл .module.css(просто обычное .cssтоже подойдет), но это стало общепринятым во многих известных инструментах. Приложение Create React также поддерживает это соглашение «из коробки» без необходимости дальнейшей настройки с помощью ранее упомянутого css-loaderв фоновом режиме (реализованного в Webpack).

В этих файлах CSS можно найти обычный и стандартизированный CSS . Затем его можно легко импортировать в модуль JavaScript:

import css from './ProfileImage.module.css';

Мы только что вступили на новую территорию: переменная cssтеперь содержит объект со свойствами, которые относятся к именам классов в наших модулях CSS. Если в файле CSS есть класс CSS с именем image, теперь мы можем получить доступ к свойству imageобъекта CSS. Результирующее значение в визуализированной разметке представляет собой уникальную строку, например ProfileImage_image_2cvf73.

Мы можем передать эти сгенерированные имена классов нашим компонентам следующим образом:

<img src={props.imageUrl} className={css.image} />

Результатом этого кода будет следующая визуализированная разметка:

<img src="..." className="ProfileImage_image_2cvf73" />

Если бы мы использовали класс imageв другом компоненте и также импортировали файл css с imageклассом, мы бы не столкнулись с конфликтом, как это обычно происходит в обычном CSS. Сгенерированное имя класса было бы другим.

Все, что разрешено в обычном CSS, разрешено и в модулях CSS. Каскад останется нетронутым:

.imageWrapper img {
 border: 1px solid red;
}
.imageWrapper:hover img {
 border-color: green;
}

Этот фрагмент CSS будет использоваться в следующей структуре JSX:

const ProfileImage = () => {
 return (
   <div className={css.imageWrapper}>
     <img src="..." />
   </div>
 );
};

Модули CSS призваны избежать конфликтов в очень изолированных компонентах, в то же время позволяя нам писать обычный CSS в файлах CSS без каких-либо знаний JavaScript. Они являются отличным решением для команд, в которых разработка больше разделена на JavaScript и CSS и в которых есть эксперты по обоим направлениям.

CSS-in-JS — перенос стилей в JavaScript
Во введении я уже упоминал, что CSS-in-JS — довольно горячо обсуждаемая тема. Противники говорят, что пользователи CSS-in-JS просто не понимают каскада написания масштабируемого CSS. Сторонники, с другой стороны, объясняют, что каскад не является основной причиной выбора CSS-in-JS , но утверждают, что необходим более безопасный способ написания высокоизолированных компонентов. Я сам немного более дипломатичен и думаю, что есть место и причины для того и другого. CSS-in-JS определенно имеет основания для существования. Но что такое CSS-in-JS ?

Подход CSS-in-JS требует, чтобы стили, которые обычно встречаются в файлах CSS, теперь были перенесены в JavaScript. Как уже было в случае с модулями CSS , основная цель — создать высоко изолированные компоненты, свободные от конфликтов, что упрощает их повторное использование во всем приложении. Однако, в отличие от модулей CSS , стилизация в CSS-in-JS полностью выполняется в JavaScript. Синтаксис очень похож, и создается впечатление, что вы пишете обычный CSS.

CSS-in-JS — это общий термин для этой концепции, тогда как фактическая реализация достигается с помощью ряда различных библиотек. Если вы ищете отличный обзор, я предлагаю вам посетить http://michelebertoli.github.io/css-in-js/ — на этом сайте представлено более 60 различных библиотек, которые могут помочь вам реализовать ваши собственные CSS-in-js/. JS- решение.

В оставшихся частях главы я хочу сосредоточиться на стилизованных компонентах — самой популярной библиотеке, имеющей около 23 000 звезд на GitHub. Чтобы использовать его, нам нужно сначала установить его через командную строку:

npm install styled-components

или

yarn add styled-components

После установки мы готовы импортировать его и написать наш первый стилизованный компонент . Используя styledфункцию, мы определяем элемент HTML, который хотим стилизовать. Синтаксис литерала шаблона из ES2015 используется для определения CSS для нашего стилизованного компонента.

Чтобы создать черно-желтую кнопку, нам нужно написать следующее:

import React from 'react';
import ReactDOM from 'react-dom';
import styled from 'styled-components';
const Button = styled.button`
 background: yellow;
 border: 2px solid black;
 color: black;
 padding: 8px;
`;
const App = () => {
 return (
   <div>
     <h1>An example of a styled component</h1>
     <Button>A black and yellow button without any function</Button>
   </div>
 );
};
ReactDOM.render(<App />, document.getElementById('root'));

Используя нотацию const Button = styled.button компонентов, мы создаем новый Buttonкомпонент и снабжаем его свойствами CSS, которые мы определили в литералах шаблона . Внутри литералов шаблона можно использовать обычный CSS.

Если мы хотим использовать псевдоселекторы или элементы, мы можем использовать их без предыдущего селектора. Для :hoverстатуса мы можем определить следующее:

const Button = styled.button`
 background: yellow;
 border: 2px solid black;
 color: black;
 padding: 8px;
 :hover {
   background: gold;
 }
`;

Доступ к реквизитам также можно получить в стилизованных компонентах . Вызвав функцию в строке шаблона, все свойства элемента можно передать в качестве первого параметра:

const Button = styled.button`
 background: yellow;
 border: 2px solid black;
 color: black;
 cursor: ${(props) => (props.disabled ? 'not-allowed' : 'pointer')};
 padding: 8px;
 :hover {
   background: gold;
 }
`;

Значок курсора изменился бы на not-allowedсимвол, если бы у кнопки было disabledсвойство. Более того, стилизованные компоненты предлагают поддержку тем, рендеринга на стороне сервера, анимации CSS и многого другого. Для тех из вас, кто хотел бы получить подробное объяснение и обзор, я предлагаю вам ознакомиться с подробной документацией .

Основные преимущества CSS-in-JS и стилизованных компонентов в частности хорошо изложены в документации:

  • Критический CSS (то есть CSS, соответствующий текущей странице) генерируется автоматически, поскольку стилизованные компоненты знают, какие компоненты используются на каждой странице и какие стили им нужны.
  • За счет автоматической генерации имен классов риск конфликтов сводится к минимуму.
  • Поскольку весь CSS привязан к компоненту, легко обнаружить лишний CSS. Если стилизованный компонент больше не используется в приложении, CSS больше не нужен и компонент можно безопасно удалить.
  • Логика компонента и стиль компонента (CSS-in-JS) находятся в одном и том же месте, а иногда даже в одном и том же файле. Разработчикам больше не нужно тратить много времени, чтобы найти, где именно нужно изменить стиль.
  • Стилизованные компоненты автоматически генерируют CSS, содержащий префиксы поставщиков для всех браузеров.

Стилизованные компоненты — лишь одно из многих решений CSS-in-JS. Хотя он, вероятно, является наиболее известным и наиболее широко распространенным, существует ряд отличных альтернатив, которые могут помочь вам найти решение, соответствующее конкретным потребностям вашего проекта.