Основы

Краткое введение в glamorous

Мотивация

Зачем нужен glamorous?

Проблема

Вы любите CSS в JS, но вам не нравится необходимость создавать функции компонента лишь для стилизации. Вы не хотите придумывать имя для чего-то, относящегося только к стилям. Всё это очень раздражает: создание отдельных стилей, присваивание className и связанные с props'ами "танцы с бубном".

Пример, как сделать с помощью glamor (или aphrodite или чего-то подобного):

const styles = glamor.css({
  fontSize: 20,
  textAlign: 'center',
})
function MyStyledDiv({className = '', ...rest}) {
  return (
    <div
      className={`${styles} ${className}`}
      {...rest}
    />
  )
}

Решение

С glamorous то, что выше, будет выглядеть просто как:

const MyStyledDiv = glamorous.div({
  fontSize: 20,
  textAlign: 'center',
})

Фактически, можно сделать это ещё лучше, благодаря множеству возможностей составления компонетов друг с другом!

Да, а что если вы не позаботились об имени для MyStyledDiv? Если вы просто хотите div, который стилизуется с помощью glamor? Вы можете сделать так тоже:

const { Div } = glamorous

function App() {
  return (
    <Div
      fontSize={20}
      textAlign="center"
    >
      Hello world!
    </Div>
  )
}

Попробовать в браузере здесь!

Итак, это основы решения glamorous... Продолжим знакомиться с деталями!

Установка

Этот модуль распространяется через npm, предоставляемый node и должен быть установлен, как одна из зависимостей проекта:

npm install --save glamorous

Также, вам необходимо добавить react и glamor в ваш проект(если их там ещё нет):

npm install --save react glamor

Внимание: Если вы используете React v15.5 или выше, вам также необходимо установить prop-types: npm install --save prop-types

Затем вы сможете использовать один из форматов модуля:

  • main: dist/glamorous.cjs.js - экспортируется как CommonJS модуль
  • global: dist/glamorous.umd.js и dist/glamorous.umd.min.js - экспортируются как umd модуль, который употребим в нескольких контекстах, наиболее значимый из которых - глобальный.
  • jsnext:main и модуль: dist/glamorous.es.js - экспортируются с использованием ES modules спецификации, вам будет нужно настроить webpack, чтобы использовать этот файл, с помощью resolve.mainFields свойства.

Наиболее распространённый способ использования этого модуля через CommonJS:

const glamorous = require('glamorous')
const {ThemeProvider} = glamorous
// итд.

Если вы используете transpiling(и/или используете jsnext:main):

import glamorous, {ThemeProvider} from 'glamorous'

// вы можете импортировать нужный Glamorous Компонент (подробнее в разделе "Встроенные компоненты")
import {Div, H2} from 'glamorous'

// тэги с тем же именем, что и встроенные объекты JavaScript, импортируются с Tag суффиксом.
// Имя тэга, содержащее тире, нужно писать в CamelCase
import {MapTag, ColorProfile} from 'glamorous'

Если вы хотите использовать глобально:

<!-- Загрузка зависимостей -->
<script src="https://unpkg.com/react/dist/react.js"></script>
<script src="https://unpkg.com/prop-types/prop-types.js"></script>
<script src="https://unpkg.com/glamor/umd/index.js"></script>
<!-- загрузка библиотеки -->
<script src="https://unpkg.com/glamorous/dist/glamorous.umd.js"></script>
<script>
// Используй window.glamorous здесь...
const glamorous = window.glamorous
const {ThemeProvider} = glamorous
</script>

Getting Started

Для этого раздела нет перевода. Вы можете помочь перевести его?

start using glamorous

Video Screenshot

Here is a basic example that shows you how to get started making component with css-in-js magic.

const { Div } = glamorous

function App() {
	return (
		<Div
			fontSize={20}
			textAlign="center"
		>
			Hello Glamorous!
		</Div>
	)
}

render(<App/>)
Hello Glamorous!

Ключевые концепции

glamorous

Функция glamorous это дефолтный экспорт. Она позволяет создавать glamorous-компоненты, которые рендерят стили в компонент, которому вы их дали. Это сделано путём отправки className prop в компонент, который вы указали ему отрендерить. Но прежде чем мы приступим к способам оборачивания компонентов, давайте рассмотрим встроенные DOM-элементы.

встроенные DOM фабрики компонентов

Для каждого DOM элемента, существует ассоциированная glamorous фабрика компонента, прикреплённая к glamorous функции. Так же, как выше, у вас есть доступ к этим фабрикам, таким как: glamorous.div, glamorous.a, glamorous.article, и т.д.

const MyStyledSection = glamorous.section({ margin: 1 })

<MyStyledSection>содержимое</MyStyledSection>
// rendered output: <section class="<glamor-generated-class>">содержимое</section>
// styles applied: {margin: 1}

GlamorousComponent

GlamorousComponent это то, что возвращает glamorousComponentFactory. Их работа - собрать все стили вместе, получить className (из glamor) и перенаправить это в ваш компонент.

встроенные GlamorousComponents

Часто бывает, что вы хотите стилизовать что-то без присваивания этому имени (потому что именование это трудно). Так glamorous предоставляет предсозданные GlamorousComponent для каждого типа узлов DOM. Покажем на примере ниже:

const { Div, Span, A, Img } = glamorous

function MyUserInterface({name, tagline, imageUrl, homepage, size}) {
  const nameSize = size
  const taglineSize = size * 0.5
  return (
    <Div display="flex" flexDirection="column" justifyContent="center">
      <A href={homepage} textDecoration="underline" color="#336479">
        <Img borderRadius="50%" height={180} src={imageUrl} />
        <Div fontSize={nameSize} fontWeight="bold">{name}</Div>
      </A>
      <Span fontSize={taglineSize} color="#767676">
        {tagline}
      </Span>
    </Div>
  )
}

Поробовать в браузере здесь!

Именовать всё и вся - может быть трудной задачей, а имея все эти компоненты по умолчанию - очень удобно. Другая удобная вещь - то, что props сами являются стилями для этих компонентов. Заметим, что glamorous умеет отличать props для стилизации, от props, которые имеют семантическое значение (например как с Img и A компонентами, которые используют src и href props).

Сss prop может быть использовано, чтобы передать стили в качестве объекта.

import glamorous, {withTheme} from 'glamorous'
const { Div, Span } = glamorous

const predefinedStyle = {
  color: '#767676',
  fontSize: 18,
}

const MyUserInterface = withTheme(function ({tagline, theme}) {
  return (
    <Div
      css={{
        display: 'flex',
        flexDirection: 'column',
        justifyContent: 'center',
        [theme.mq.tablet]: {
          flexDirection: 'row'
        }
      }}
     >
      <Span css={predefinedStyle}>
        {tagline}
      </Span>
    </Div>
  )
})

Ещё один совет... Это отлично работает:

<glamorous.Div color="blue">
  JSX это весело!
</glamorous.Div>

Переопределение стилей компонента

Распространённый сценарий использования props - это переопределение стиля существующего компонента(созданного glamorous'ом или нет). Это может быть достигнуто использованием props className, css и theme или просто композицией компонента с glamorous() функцией.

Если вы хотите больше узнать об использовании theme prop, смотрите раздел Тематизация, для более детальных объяснений. В этом разделе мы расскажем как использовать className, css и композицию для переопределения стилей компонента.

Давайте посмотрим, что может быть сделано в примере ниже.

Попробовать в браузере здесь!

Мы будем использовать это, как наш GlamorousComponent:

const MyStyledDiv = glamorous.div({margin: 1, fontSize: 1, padding: 1})
использование className

Для каждого className, которое вы передаёте, GlamorousComponent проверяет наличие glamor генерируемого className (взятого из glamor или glamorous, не важно). Если оно есть, компонент использует исходные стили, которые были использованы при создании этого className и объединит их со стилями для элемента, который рендерится, так что в случае конфликта выиграет стиль, который вы передаёте как className.

Любой classNames, не генерируемый glamor'ом, просто будет объединён с тем что уже существует.

const myCustomGlamorStyles = glamor.css({fontSize: 2})
<MyStyledDiv className={`${myCustomGlamorStyles} custom-class`} />
// применённые стили:
// {margin: 1, fontSize: 2, padding: 1}
// так же как любые применённые кастомно-классовые стили 
использование css

Это может быть css того же типа, что и любой из переданных стилей (как в glamorous.div(...styles)). Если он указан, то будет объединён со стилем этого компонента и получит высший приоритет среди всех предопределённых стилей компонента.

const myCustomGlamorStyles = glamor.css({fontSize: 2, padding: 2})
<MyStyledDiv
  className={`${myCustomGlamorStyles} custom-class`}
  css={{padding: 3}}
/>
// применённые стили:
// {margin: 1, fontSize: 2, padding: 3}
// так же как любые применённые кастомно-классовые стили
использование glamorous() композиции

Если мы просто хотим расширить стили существующего компонента, это может быть сделано с использованием glamorous() функции.

const MyComposedStyledDiv = glamorous(MyStyledDiv)({fontSize: 4, padding: 4})
<MyComposedStyledDiv />
// применённые стили:
// {margin: 1, fontSize: 4, padding: 4}

Фактически, встроенные фабрики DOM компонентов, всего лишь абстракции этой функции, так что glamorous.div может быть записан как glamorous('div').

Динамические Стили + Статические Стили

Одно из достоинств glamorous - это то, что он позволяет вам проводить чёткое разделение между динамическими и статическими стилями, принуждая вас выбирать между объектом и функцией. Ниже приведён пример, имеющий оба - статический и динамический стили:

const MyLink = glamorous.a(
	{
		color: 'blue',
		textDecoration: 'none',
	},
	({size = 'small'}) => ({
		fontSize: size === 'big' ? 24 : 16,
	})
	// можно продолжить передавать любое количество
	// аргументов и `glamor` будет объединять их.
	// В случае конфликта стилей, последний получит
	// приоритет.
)

render(
	<div>
		<MyLink href="#">Default is small</MyLink>
		<br />
		<MyLink href="#" size="big">size="big"</MyLink>
	</div>
)

Попробовать в браузере здесь!

Можно использовать массив для объединения стилей

Анимация

Для того, чтобы создавать анимацию с glamorous, вы можете использовать обычный CSS transitions - для простых вещей, а для продвинутых - keyframes из glamor'овского css.keyframes API.

// import * as glamor from 'glamor'

// Задайте стили анимации
const animationStyles = props => {
	const bounce = glamor.css.keyframes({
		'0%': { transform: `scale(1.01)` },
		'100%': { transform: `scale(0.99)` }
	})
	return {animation: `${bounce} 0.2s infinite ease-in-out alternate`}
}

// Создайте элемент
const AnimatedDiv = glamorous.div(animationStyles)

render(
	<AnimatedDiv>
		Bounce.
	</AnimatedDiv>
)
Bounce.
CodeSandbox

glamorous-native

React Native

glamorous предоставляет версию для проектов на React Native, называемую glamorous-native.

npm install glamorous-native --save

Вы можете узнать больше на проект glamorous-native.

Контрибьюторы:

kentcdodds's GitHub avatar