框架 - 敏捷的CSS-IN-JS支持服务器端渲染,浏览器前缀和最小CSS生成。
支持将样式与JavaScript组件共同关闭。
:hover
:active
等,无需将悬停或活动状态存储在组件中。 :visited
工作也很好。@font-face
检测和插入。Aphrodite通过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
,并且想在服务器端渲染它,请确保从aphrodite/no-important
中导入StyleSheetServer
,否则您将遇到错误。
例如:
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'
)。您可以通过在调用StyleSheet.create
之前用true
或false
minify
缩放来覆盖此行为。
例如,如果您想促进生产调试,这将很有用。
import { StyleSheet , minify } from 'aphrodite' ;
// Always keep the full style names
minify ( false ) ;
// ... proceed to use StyleSheet.create etc.
创建自定义字体面是一种特殊情况。通常,您需要定义全局@font-face
规则。在阿芙罗狄蒂(Aphrodite)的情况下,我们只想插入该规则,如果该规则实际上是由页面中的类实际引用的。我们已经做到了,以便fontFamily
属性可以接受字体 - 脸对象(直接或内部的数组内)。然后,基于字体定义生成全局@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将确保该字体的全局@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
规则,无论给出给定规则多少次。
阿芙罗狄蒂的构建是考虑到反应的,但不依赖于反应。在这里,您可以看到它与Web组件一起使用:
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将自动尝试在文档的<head>
元素中创建一个<style>
标签,以将其生成的样式放入中。Aphrodite只会生成一个<style>
标签,并且随着时间的推移会为此添加新样式。如果您想控制Aphrodite使用哪种样式标签,请使用data-aphrodite
属性创建样式标签,而Aphrodite将使用它而不是为您创建一个样式。
为了加快样式注入的速度,阿芙罗狄蒂将自动尝试将其写入此<style>
标签,以便发生最少数量的DOM修改。
阿芙罗狄蒂(Aphrodite)使用尽快安排缓冲液冲洗。如果您在componentDidMount
或componentDidUpdate
中测量DOM Elements的尺寸,则可以使用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的工作方式,不是最重要的元素上的class名称,而是特殊性。但是,当我们查看生成的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
Ruperriding 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属性,可以避免问题。
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之类的包装来填充它。
可以使用扩展名添加额外的功能。
要向阿芙罗狄蒂添加扩展名,请使用您要添加的扩展名调用StyleSheet.extend
。结果将是一个包含Aphrodite( 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 ( {
...
} ) ;
注意:使用扩展可能会导致阿芙罗狄蒂的样式无法正常工作。普通的阿芙罗狄蒂(Aphrodite)正确使用,可确保正确的样式始终应用于元素。由于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 ) ;
它不能确定DIV是红色还是蓝色。
通过将环境变量process.env.NODE_ENV
设置为字符串值production
来缩小类名称。
StyleSheet.create
内容,并查看生成的CSS版权(C)2016 Khan Academy