Фреймворк-агрессия CSS-In-JS с поддержкой рендеринга на стороне сервера, префикса браузера и минимальной генерации CSS.
Поддержка совместимости ваших стилей с помощью вашего компонента JavaScript.
:hover
,: :active
и т. Д., Не нуждаясь в хранении накаплива или активного состояния в компонентах. :visited
тоже отлично.@font-face
и вставку.Афродита распределяется через NPM:
npm install --save aphrodite
Если вы предпочитаете посмотреть вводные видеоролики, вы можете найти их здесь.
import React , { Component } from 'react' ;
import { StyleSheet , css } from 'aphrodite' ;
class App extends Component {
render ( ) {
return < div >
< span className = { css ( styles . red ) } >
This is red.
< / span >
< span className = { css ( styles . hover ) } >
This turns red on hover.
< / span >
< span className = { css ( styles . small ) } >
This turns red when the browser is less than 600px width.
< / span >
< span className = { css ( styles . red , styles . blue ) } >
This is blue.
< / span >
< span className = { css ( styles . blue , styles . small ) } >
This is blue and turns red when the browser is less than
600px width.
< / span >
< / div > ;
}
}
const styles = StyleSheet . create ( {
red : {
backgroundColor : 'red'
} ,
blue : {
backgroundColor : 'blue'
} ,
hover : {
':hover' : {
backgroundColor : 'red'
}
} ,
small : {
'@media (max-width: 600px)' : {
backgroundColor : 'red' ,
}
}
} ) ;
Примечание. Если вы хотите условно использовать стили, это просто выполнено через:
const className = css (
shouldBeRed ( ) ? styles . red : styles . blue ,
shouldBeResponsive ( ) && styles . small ,
shouldBeHoverable ( ) && styles . hover
)
< div className = { className } > Hi < / div>
Это возможно, потому что любые ложные аргументы будут проигнорированы.
Чтобы объединить стили, передайте несколько стилей или массивы стилей в css()
. Это часто встречается при сочетании стилей из компонента владельца:
class App extends Component {
render ( ) {
return < Marker styles = { [ styles . large , styles . red ] } / > ;
}
}
class Marker extends Component {
render ( ) {
// css() accepts styles, arrays of styles (including nested arrays),
// and falsy values including undefined.
return < div className = { css ( styles . marker , this . props . styles ) } / > ;
}
}
const styles = StyleSheet . create ( {
red : {
backgroundColor : 'red'
} ,
large : {
height : 20 ,
width : 20
} ,
marker : {
backgroundColor : 'blue'
}
} ) ;
Функция reset
может использоваться для сброса тега в стиле HTML, буфера -инъекционного буфера и впрыскиваемого кэша. Полезно, когда афродита нужно снести и настроить.
import { reset } from 'aphrodite' ;
reset ( ) ;
В то время как функция resetInjectedStyle
может использоваться для сброса впрыскиваемого кэша для одного ключа (обычно имя класса).
import { resetInjectedStyle } from 'aphrodite' ;
resetInjectedStyle ( 'class_1sAs8jg' ) ;
Чтобы выполнить рендеринг на стороне сервера, позвоните в StyleSheetServer.renderStatic
, который проводит обратный вызов. Сделайте свой рендеринг внутри обратного вызова и верните сгенерированный HTML. Все вызовы в css()
внутри обратного вызова будут собраны, и будут возвращены сгенерированные CSS, а также сгенерированный HTML.
Регулирование позволяет Афродиту знать, какие стили уже были вставлены на страницу. Если вы не регидратируете, Aphrodite может добавить дубликаты стилей на страницу.
Чтобы выполнить регидрацию, позвоните в StyleSheet.rehydrate
со списком сгенерированных имен классов, возвращенных вам StyleSheetServer.renderStatic
.
Примечание. Если вы используете aphrodite/no-important
в своем проекте, и вы хотите отобразить его на стороне сервера, обязательно импортируйте StyleSheetServer
из aphrodite/no-important
, в противном случае вы получите ошибку.
В качестве примера:
import { StyleSheetServer } from 'aphrodite' ;
// Contains the generated html, as well as the generated css and some
// rehydration data.
var { html , css } = StyleSheetServer . renderStatic ( ( ) => {
return ReactDOMServer . renderToString ( < App / > ) ;
} ) ;
// Return the base HTML, which contains your rendered HTML as well as a
// simple rehydration script.
return `
<html>
<head>
<style data-aphrodite> ${ css . content } </style>
</head>
<body>
<div id='root'> ${ html } </div>
<script src="./bundle.js"></script>
<script>
StyleSheet.rehydrate( ${ JSON . stringify ( css . renderedClassNames ) } );
ReactDOM.render(<App/>, document.getElementById('root'));
</script>
</body>
</html>
` ;
!important
По умолчанию Aphrodite добавит !important
для определений стиля. Это предназначено для облегчения интеграции с ранее существовавшей кодовой базой. Если вы хотите избежать такого поведения, то вместо импорта aphrodite
импортируйте aphrodite/no-important
. В противном случае использование одинаково:
import { StyleSheet , css } from 'aphrodite/no-important' ;
По умолчанию Aphrodite будет министерством названий стилей в их хэши в производстве ( process.env.NODE_ENV === 'production'
). Вы можете переопределить это поведение, позвонив minify
с true
или false
прежде чем вызовать StyleSheet.create
.
Это полезно, если вы хотите облегчить отладку в производстве, например.
import { StyleSheet , minify } from 'aphrodite' ;
// Always keep the full style names
minify ( false ) ;
// ... proceed to use StyleSheet.create etc.
Создание пользовательских лиц шрифтов - это особый случай. Обычно вам нужно определить правило глобального @font-face
. В случае с Афродитой мы хотим вставить это правило, только если на него на самом деле ссылается класс, который находится на странице. Мы сделали это так, чтобы свойство fontFamily
мог принять объект Font-Face (либо напрямую, либо внутри массива). Глобальное правило @font-face
генерируется на основе определения шрифта.
const coolFont = {
fontFamily : "CoolFont" ,
fontStyle : "normal" ,
fontWeight : "normal" ,
src : "url('coolfont.woff2') format('woff2')"
} ;
const styles = StyleSheet . create ( {
headingText : {
fontFamily : coolFont ,
fontSize : 20
} ,
bodyText : {
fontFamily : [ coolFont , "sans-serif" ]
fontSize : 12
}
} ) ;
Aphrodite гарантирует, что правило Global @font-face
для этого шрифта было вставлено только один раз, независимо от того, сколько раз оно упоминалось.
Подобно лицам шрифтов, Aphrodite поддерживает анимацию ключевых кафедров, но она рассматривается как особый случай. Как только мы найдем экземпляр, на которую ссылается ссылка, создается глобальное правило @keyframes
и добавлено на страницу.
Анимации предоставляются как объекты, описывающие анимацию, в типичной моде @keyframes
. Используя свойство animationName
, вы можете предоставить один объект анимации или массив анимационных объектов. Другие свойства анимации, такие как animationDuration
могут быть предоставлены в виде строк.
const translateKeyframes = {
'0%' : {
transform : 'translateX(0)' ,
} ,
'50%' : {
transform : 'translateX(100px)' ,
} ,
'100%' : {
transform : 'translateX(0)' ,
} ,
} ;
const opacityKeyframes = {
'from' : {
opacity : 0 ,
} ,
'to' : {
opacity : 1 ,
}
} ;
const styles = StyleSheet . create ( {
zippyHeader : {
animationName : [ translateKeyframes , opacityKeyframes ] ,
animationDuration : '3s, 1200ms' ,
animationIterationCount : 'infinite' ,
} ,
} ) ;
Aphrodite гарантирует, что правила @keyframes
никогда не будут дублироваться, независимо от того, сколько раз упоминается данное правило.
Афродита была построена с учетом реагирования, но не зависит от React. Здесь вы можете увидеть его используется с веб -компонентами:
import { StyleSheet , css } from 'aphrodite' ;
const styles = StyleSheet . create ( {
red : {
backgroundColor : 'red'
}
} ) ;
class App extends HTMLElement {
attachedCallback ( ) {
this . innerHTML = `
<div class=" ${ css ( styles . red ) } ">
This is red.
</div>
` ;
}
}
document . registerElement ( 'my-app' , App ) ;
Aphrodite автоматически попытается создать тег <style>
в элементе документа <head>
, чтобы поместить свои сгенерированные стили. Aphrodite будет генерировать только один тег <style>
и добавит в это новые стили с течением времени. Если вы хотите управлять тем, какой тег стиля использует Aphrodite, создайте тег стиля, а атрибут data-aphrodite
, и Aphrodite будет использовать его вместо того, чтобы создавать его для вас.
Чтобы ускорить инъекцию стилей, Aphrodite автоматически попытается буферизировать записи на этот тег <style>
, так что происходит минимальное количество модификаций DOM.
Aphrodite использует как можно скорее, чтобы запланировать промывку буфера. Если вы измеряете размеры DOM Elements в componentDidMount
или componentDidUpdate
, вы можете использовать setTimeout
или flushToStyleTag
чтобы гарантировать, что все стили вводят.
import { StyleSheet , css } from 'aphrodite' ;
class Component extends React . Component {
render ( ) {
return < div ref = "root" className = { css ( styles . div ) } / > ;
}
componentDidMount ( ) {
// At this point styles might not be injected yet.
this . refs . root . offsetHeight ; // 0 or 10
setTimeout ( ( ) => {
this . refs . root . offsetHeight ; // 10
} , 0 ) ;
}
}
const styles = StyleSheet . create ( {
div : {
height : 10 ,
} ,
} ) ;
При назначении строки Свойству content
требуются двойные или отдельные кавычки в CSS. Поэтому с Aphrodite вы также должны предоставить кавычки в строке значения для content
чтобы соответствовать тому, как он будет представлен в CSS.
В качестве примера:
const styles = StyleSheet . create ( {
large : {
':after' : {
content : '"Aphrodite"' ,
} ,
} ,
} ,
small : {
':before' : {
content : "'Aphrodite'" ,
} ,
} ,
} ) ;
Сгенерированные CSS будет:
. large_im3wl1 : after {
content : "Aphrodite" !important ;
}
. small_ffd5jf : before {
content : 'Aphrodite' !important ;
}
При объединении нескольких стилей афродита вам настоятельно рекомендуется объединить все ваши стили в один вызов с css()
, и не должны объединять сгенерированные имена классов, которые выводит Aphrodite (через строковую конкатенацию, classnames
и т. Д.). Например, если у вас есть базовый стиль foo
, который вы пытаетесь переопределить с помощью bar
:
const styles = StyleSheet . create ( {
foo : {
color : 'red'
} ,
bar : {
color : 'blue'
}
} ) ;
// ...
const className = css ( styles . foo , styles . bar ) ;
const styles = StyleSheet . create ( {
foo : {
color : 'red'
} ,
bar : {
color : 'blue'
}
} ) ;
// ...
const className = css ( styles . foo ) + " " + css ( styles . bar ) ;
Почему это имеет значение? Хотя второй будет создавать действительное имя класса, оно не может гарантировать, что стили bar
переопределят foo
. То, как работает CSS, это не имя класса, которое последним на элементе , который имеет значение, это специфичность. Когда мы смотрим на сгенерированные CSS, мы обнаруживаем, что все имена классов имеют одинаковую специфичность, поскольку все они являются единственным именем класса:
. foo_im3wl1 {
color : red;
}
. bar_hxfs3d {
color : blue;
}
В случае, когда специфика такая же, важно , чтобы стили появлялись в таблице стиля . То есть, если сгенерированная таблица стиля выглядит как
. foo_im3wl1 {
color : red;
}
. bar_hxfs3d {
color : blue;
}
Тогда вы получите соответствующий эффект от стилей bar
, переопределяющих foo
, но если таблица стиля выглядит как
. bar_hxfs3d {
color : blue;
}
. foo_im3wl1 {
color : red;
}
Тогда мы окажемся с противоположным эффектом, с foo
Aurding bar
! Способ решить это состоит в том, чтобы передать оба стиля в вызов Aphrodite css()
. Затем он будет создавать одно именем класса, например, foo_im3wl1-o_O-bar_hxfs3d
, с правильными переопределенными стилями, тем самым решая проблему:
. foo_im3wl1-o_O-bar_hxfs3d {
color : blue;
}
Когда в Aphrodite указаны стили, порядок, который они появляются в реальной таблице стилей, зависит от порядка, который клавиши извлекаются из объектов. Этот порядок определяется двигателем JavaScript, который используется для визуализации стилей. Иногда порядок, который стили появляются в таблице стилей для семантики CSS. Например, в зависимости от двигателя, стили, генерируемые из
const styles = StyleSheet . create ( {
ordered : {
margin : 0 ,
marginLeft : 15 ,
} ,
} ) ;
css ( styles . ordered ) ;
Вы можете ожидать, что следующий CSS будет сгенерирован:
margin : 0 px ;
margin-left : 15 px ;
Но в зависимости от упорядочения ключей в объекте стиля, CSS может показаться как
margin-left : 15 px ;
margin : 0 px ;
что семантически отличается, потому что стиль, который появляется позже, будет переопределять стиль перед ним.
Это также может проявляться как проблема при рендеринге на стороне сервера, если сгенерированные стили появляются в другом порядке на клиенте и на сервере.
Если вы испытаете эту проблему, где стили не появляются в сгенерированных CSS в том порядке, в котором они появляются в ваших объектах, есть два решения:
Не используйте сокращенные свойства. Например, в примере выше, переключаясь с использования свойства сокращения и свойства Longhand в тех же стилях, чтобы использовать только Longhand Properties, может быть избежать проблемы.
const styles = StyleSheet . create ( {
ordered : {
marginTop : 0 ,
marginRight : 0 ,
marginBottom : 0 ,
marginLeft : 15 ,
} ,
} ) ;
Укажите заказ ваших стилей, указав их, используя Map
. Поскольку Map
S сохраняет свой заказ внедрения, Aphrodite может разместить ваши стили в правильном порядке.
const styles = StyleSheet . create ( {
ordered : new Map ( [
[ "margin" , 0 ] ,
[ "marginLeft" , 15 ] ,
] ) ,
} ) ;
Обратите внимание, что Map
S не полностью поддерживаются во всех браузерах. Он может быть многофиксирован, используя такую пакет, как ES6-SHIM.
Дополнительные функции могут быть добавлены в Aphrodite с использованием расширений.
Чтобы добавить расширения в Aphrodite, вызовите StyleSheet.extend
с расширениями, которые вы добавляете. Результатом будет объект, содержащий обычный экспорт афродиты ( css
, StyleSheet
и т. Д.), Который будет включать ваши расширения. Например:
// my-aphrodite.js
import { StyleSheet } from "aphrodite" ;
export default StyleSheet . extend ( [ extension1 , extension2 ] ) ;
// styled.js
import { StyleSheet , css } from "my-aphrodite.js" ;
const styles = StyleSheet . create ( {
...
} ) ;
Примечание . Использование расширений может привести к тому, что стили Афродиты не работают должным образом. Простая афродита при правильном использовании гарантирует, что правильные стили всегда будут применены к элементам. Из -за правил специфичности CSS расширения могут позволить вам генерировать стили, которые противоречат друг другу, вызывая неверные стили. Посмотрите на глобальное расширение ниже, чтобы увидеть, что может пойти не так.
В настоящее время доступно только один вид расширения: обработчики селектора. Эти виды расширений позволяют вам взглянуть на селекторов, которые кто -то определяет, и генерируют новые селекторы на основе их. Они используются для обработки псевдо-стилей и медиа-запросов внутри Афродиты. См. Документы defaultSelectorHandlers
для получения информации о том, как создать функцию обработчика селектора.
Чтобы использовать ваше расширение, создайте объект, содержащий ключ из созданного вами расширения, и передайте его в StyleSheet.extend()
:
const mySelectorHandler = ... ;
const myExtension = { selectorHandler : mySelectorHandler } ;
const { StyleSheet : newStyleSheet , css : newCss } = StyleSheet . extend ( [ myExtension ] ) ;
В качестве примера вы можете написать расширение, которое генерирует глобальные стили, как
const globalSelectorHandler = ( selector , _ , generateSubtreeStyles ) => {
if ( selector [ 0 ] !== "*" ) {
return null ;
}
return generateSubtreeStyles ( selector . slice ( 1 ) ) ;
} ;
const globalExtension = { selectorHandler : globalSelectorHandler } ;
Это может вызвать проблемы, когда два места пытаются генерировать стили для одного и того же глобального селектора! Например, после
const styles = StyleSheet . create ( {
globals : {
'*div' : {
color : 'red' ,
} ,
}
} ) ;
const styles2 = StyleSheet . create ( {
globals : {
'*div' : {
color : 'blue' ,
} ,
} ,
} ) ;
css ( styles . globals ) ;
css ( styles2 . globals ) ;
Не определяется, будет ли DOV красным или синим.
Минифицируйте имена классов, установив process.env.NODE_ENV
переменной среды.env.node_env для production
строкового значения.
StyleSheet.create
и посмотрите сгенерированные CSSCopyright (C) 2016 Хан Академия