- PVSM.RU - https://www.pvsm.ru -
Существует множество подходов для того, чтобы стилизовать React-компоненты, и в этой статье будут рассмотрены некоторые из них. Но, для начала, определимся с ключевыми моментами, на которых основано повествование:
Использование React предполагает, что View нашего Web-приложения разбито на компоненты, и каждый из них, так или иначе, отвечает за собственное отображение и функциональность.
Подразумевается, что будут использованы современные инструменты разработки вроде babel [1], webpack [2], browserify [3], gulp [4], post- pre- css-процессоры.
<!doctype html>
<!--[if lt IE 7]> <html class="ie6 oldie"> <![endif]-->
<!--[if IE 7]> <html class="ie7 oldie"> <![endif]-->
<!--[if IE 8]> <html class="ie8 oldie"> <![endif]-->
<!--[if gt IE 8]><!-->
<html class="">
<!--<![endif]-->
background: #1e5799; /* Old browsers */
background: -moz-linear-gradient(top, #1e5799 0%, #7db9e8 100%); /* FF3.6-15 */
background: -webkit-linear-gradient(top, #1e5799 0%,#7db9e8 100%); /* Chrome10-25,Safari5.1-6 */
background: linear-gradient(to bottom, #1e5799 0%,#7db9e8 100%); /* W3C, IE10+, FF16+, Chrome26+, Opera12+, Safari7+ */
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#1e5799', endColorstr='#7db9e8',GradientType=0 ); /* IE6-9 */
React-компоненты рендерятся в настоящий HTML, т.е. в DOMElement-ы. Существует два способа настроить отображение DOMElement-а:
Второй подход имеет множество недостатков:
Некоторые из этих недостатков могут компенсироваться комбинированием 2-го подхода с 1-ым, но не все.
Известно, что Facebook, как компания-разработчик React, несмотря на описанные выше недостатки всё равно продвигает использование Inline Styles [7]. Их можно понять, они стремятся обеспечить единообразный подход с React Native [8], ибо там только Inline Styles и имеются. Но нам от этого не легче, ведь для Web сам Facebook в плане стилизации React-компонентов ничего толкового не предлагает. Зато нашлось множество энтузиастов, которые написали свои велосипеды. Далее мы рассмотрим самые популярные из них и разберемся с основными подходами стилизации React-компонентов.
Пишем один внешний файл со стилями, подключаем его и используем в React-компонентах className со значениями имен классов из этого файла.
/* Button.js */
import React, { Component } from 'react';
export default class Button extends Component {
render() {
return (
<div className = {'button ' + (this.props.isRed ? 'button--red' : '')}>
<div className = 'button__caption'>
{this.props.caption}
</div>
</div>
);
}
}
/* Button.css */
.button {
line-height: 32px;
border: 1px solid #000;
}
.button__caption {
text-decoration: underline;
text-align: center;
}
.button--red {
background-color: red;
}
/* ScopedSelectors.js */
import styles from './ScopedSelectors.css';
import React, { Component } from 'react';
export default class ScopedSelectors extends Component {
render() {
return (
<div className = {styles.root}>
<p className = {styles.text}>
Scoped Selectors
</p>
</div>
);
}
};
/* ScopedSelectors.css */
.root {
border-width: 2px;
border-style: solid;
border-color: #777;
padding: 0 20px;
margin: 0 6px;
max-width: 400px;
}
.text {
color: #777;
font-size: 24px;
font-family: helvetica, arial, sans-serif;
font-weight: 600;
}
Использование CSS-Modules подразумевает, что имена стилей будут доступны только локально, т.е. каждый React-компонент может иметь свой стиль root, и никаких коллизий не будет — имена стилей трансформируются при сборке. Также существует возможность определить глобальные стили, которые будут доступны везде — их имена трансформироваться не будут. Для поддержки CSS-Modules со стороны Node.js существует проект css-modules-require-hook [11], либо можно использовать Webpack для компиляции серверного кода приложения (статья про компиляцию серверного кода в двух частях — 1 [12], 2 [13]).
Про все эти подходы можно добавить, что к ним успешно и легко прикручиваются autoprefixer [5] и всякие less [14], sass [15], postcss [16], stylus [17] с константами, импортами, миксинами и прочими плюшками. Также нет никаких проблем с подсветкой синтаксиса и подсказками в IDE. В рамках этого списка будет легко переключиться с одного подхода на другой.
Существует множество решений на этот счет, они очень разные и навязывают свой единственно возможный вариант их использования, со всеми вытекающими последствиями: сложность миграции на что-то другое, свой особый синтаксис, декораторы, волшебные классы, от которых нужно наследоваться — придется учить новый framework, чтобы этим пользоваться. Ряд решений не работает с серверным рендерингом или не поддерживает autoprefixer, который должен отрабатывать на этапе компиляции — не тащить же его в браузер.
Рассмотрим несколько самых известных представителей данного подхода:
Хороший проект [18], который поддерживает media queries и псевдоклассы, например, :hover. Он предлагает следующий синтаксис:
const styles = {
button: {
padding: '1em',
':hover': {
border: '1px solid black'
},
'@media (max-width: 200px)': {
width: '100%',
':hover': {
background: 'white',
}
}
},
primary: {
background: 'green'
},
warning: {
background: 'yellow'
},
};
...
<button style={[styles.button, styles.primary]}>
Confirm
</button>
Чтобы это всё работало, при объявлении компонентов нужно использовать декоратор Radium [19].
Используется такой же синтаксис, как и в стандартных Inline Styles для React, но со слегка расширенными возможностями [20].
import StyleSheet from 'react-style';
const styles = StyleSheet.create({
primary: {
background: 'green'
},
warning: {
background: 'yellow'
},
button: {
padding: '1em'
},
// media queries
'@media (max-width: 200px)': {
button: {
width: '100%'
}
}
});
...
<button styles={[styles.button, styles.primary]}>
Confirm
</button>
Как и в Radium, работают media queries, но, в отличие от него, не поддерживаются псевдоклассы и анимация средствами CSS, есть loader [21] для Webpack.
Поддерживает autoprefixer, псевдоклассы и media queries. Может использоваться с React через react-jss [22]. Также существует экспериментальный jss-loader [23] для Webpack. Пример использования:
import classNames from 'classnames';
import useSheet from 'react-jss';
const styles = {
button: {
padding: '1em'
},
'media (max-width: 200px)': {
button: {
width: '100%'
}
},
primary: {
background: 'green'
},
warning: {
background: 'yellow'
}
};
@useSheet(styles)
export default class ConfirmButton extends React.Component {
render() {
const {classes} = this.props.sheet;
return <button
className={classNames(classes.button, classes.primary)}>
Confirm
</button>;
}
}
Проект вводит свой волшебный синтаксис, не поддерживает media queries, зато есть loader [24] для Webpack.
// PrimaryButton component
<button
padding='1em'
background='green'
>Confirm</button>
Есть неплохой англоязычный обзор всех этих технологий [25].
Нельзя однозначно сказать, какое из решений лучше остальных — всё зависит от конкретных задач и ограничений. Какому-то проекту больше подойдут CSS-Modules, другому хватит БЭМ-именований для классов, третьему — что-то основанное на идее Inline Styles.
Выбор подхода для стилизации React-компонентов — это серьезное архитектурное решение, которое оставит свой след в коде всего проекта, во многом определит инструменты его разработки и повлияет на множество других факторов, связанных с поддержкой кода и скоростью работы приложения в целом. Надеюсь, данный обзор будет полезен Web-разработчикам как краткая справочная информация о разных подходах к стилизации React-компонентов и поможет оценить риски при выборе своего собственного пути.
Автор: DevExpress
Источник [26]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/javascript/120297
Ссылки в тексте:
[1] babel: https://github.com/babel/babel
[2] webpack: https://github.com/webpack/webpack
[3] browserify: https://github.com/substack/node-browserify
[4] gulp: https://github.com/gulpjs/gulp
[5] autoprefixer: https://github.com/postcss/autoprefixer
[6] Значительное увеличение размера разметки и снижение производительности : http://ctheu.com/2015/08/17/react-inline-styles-vs-css-stupid-benchmark/
[7] Inline Styles: https://facebook.github.io/react/tips/inline-styles.html
[8] React Native: https://github.com/facebook/react-native
[9] БЭМ: https://ru.bem.info/methodology/naming-convention/#Стиль-Гарри-Робертса
[10] CSS-Modules: https://css-modules.github.io/webpack-demo/
[11] css-modules-require-hook: https://github.com/css-modules/css-modules-require-hook
[12] 1: http://jlongster.com/Backend-Apps-with-Webpack--Part-I
[13] 2: http://jlongster.com/Backend-Apps-with-Webpack--Part-II
[14] less: https://github.com/less/less.js
[15] sass: https://github.com/sass/sass
[16] postcss: https://github.com/postcss/postcss
[17] stylus: https://github.com/stylus/stylus
[18] Хороший проект: https://github.com/FormidableLabs/radium
[19] Radium: https://habrahabr.ru/users/radium/
[20] расширенными возможностями: https://github.com/js-next/react-style
[21] loader: https://github.com/js-next/react-style-webpack-plugin
[22] react-jss: https://github.com/jsstyles/react-jss
[23] jss-loader: https://github.com/markdalgleish/jss-loader
[24] loader: https://github.com/petehunt/jsxstyle
[25] Есть неплохой англоязычный обзор всех этих технологий: http://survivejs.com/webpack_react/styling_react/
[26] Источник: https://habrahabr.ru/post/283314/?utm_source=habrahabr&utm_medium=rss&utm_campaign=best
Нажмите здесь для печати.