CSS-in-JS agnóstico marco con soporte para representación del lado del servidor, prefijo del navegador y generación mínima de CSS.
Soporte para colocar sus estilos con su componente JavaScript.
:hover
, :active
, etc. sin necesidad de almacenar desplazamiento o estado activo en componentes. :visited
también funciona bien.@font-face
.Afrodita se distribuye a través de NPM:
npm install --save aphrodite
Si prefiere ver videos introductorios, puede encontrarlos aquí.
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' ,
}
}
} ) ;
Nota: Si desea usar estilos condicionalmente, eso simplemente se logra a través de:
const className = css (
shouldBeRed ( ) ? styles . red : styles . blue ,
shouldBeResponsive ( ) && styles . small ,
shouldBeHoverable ( ) && styles . hover
)
< div className = { className } > Hi < / div>
Esto es posible porque se ignorará cualquier argumento de falsificación.
Para combinar estilos, pase múltiples estilos o conjuntos de estilos a css()
. Esto es común al combinar estilos de un componente del propietario:
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'
}
} ) ;
La función reset
se puede usar para restablecer la etiqueta de estilo HTML, el tampón de inyección y el caché inyectado. Útil cuando Afrodita necesita ser derribado y volver a colocar.
import { reset } from 'aphrodite' ;
reset ( ) ;
Mientras que la función resetInjectedStyle
se puede usar para restablecer el caché inyectado para una sola clave (generalmente el nombre de la clase).
import { resetInjectedStyle } from 'aphrodite' ;
resetInjectedStyle ( 'class_1sAs8jg' ) ;
Para realizar la representación del lado del servidor, haga una llamada a StyleSheetServer.renderStatic
, que requiere una devolución de llamada. Haga su representación dentro de la devolución de llamada y devuelva el HTML generado. Se recopilarán todas las llamadas a css()
dentro de la devolución de llamada y se devolverá el CSS generado, así como el HTML generado.
Rehidratación le permite saber a Afrodita qué estilos ya se han insertado en la página. Si no rehidrata, Afrodita podría agregar estilos duplicados a la página.
Para realizar la rehidratación, llame a StyleSheet.rehydrate
con la lista de nombres de clases generados que le devuelve StyleSheetServer.renderStatic
.
Nota: Si está utilizando aphrodite/no-important
en su proyecto y desea representarlo en el lado del servidor, asegúrese de importar StyleSheetServer
desde aphrodite/no-important
de lo contrario va a recibir un error.
Como ejemplo:
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
Por defecto, Afrodite agregará !important
para el estilo de definiciones. Esto está destinado a facilitar la integración con una base de código preexistente. Si desea evitar este comportamiento, entonces, en lugar de importar aphrodite
, importar aphrodite/no-important
. De lo contrario, el uso es el mismo:
import { StyleSheet , css } from 'aphrodite/no-important' ;
Por defecto, Aphrodite minificará los nombres de estilo a sus hashes en la producción ( process.env.NODE_ENV === 'production'
). Puede anular este comportamiento llamando minify
con true
o false
antes de llamar StyleSheet.create
.
Esto es útil si desea facilitar la depuración en la producción, por ejemplo.
import { StyleSheet , minify } from 'aphrodite' ;
// Always keep the full style names
minify ( false ) ;
// ... proceed to use StyleSheet.create etc.
Crear caras de fuentes personalizadas es un caso especial. Por lo general, debe definir una regla global @font-face
. En el caso de Afrodita, solo queremos insertar esa regla si realmente está siendo referenciada por una clase que está en la página. Lo hemos hecho para que la propiedad fontFamily
pueda aceptar un objeto de fuente de fuente (ya sea directamente o dentro de una matriz). Luego se genera una regla global @font-face
en función de la definición de fuentes.
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
}
} ) ;
Afrodita asegurará que la regla global @font-face
para esta fuente solo se inserta una vez, sin importar cuántas veces se haga referencia.
Similar a las caras de fuentes, Afrodite admite animaciones de fotograma clave, pero se trata como un caso especial. Una vez que encontramos una instancia de la animación que se hace referencia, se crea una regla global @keyframes
y se agrega a la página.
Las animaciones se proporcionan como objetos que describen la animación, en la típica moda @keyframes
. Usando la propiedad animationName
, puede proporcionar un solo objeto de animación o una variedad de objetos de animación. Otras propiedades de animación como animationDuration
se pueden proporcionar como cadenas.
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' ,
} ,
} ) ;
Afrodita asegurará que las reglas @keyframes
nunca se dupliquen, sin importar cuántas veces se haga referencia a una regla determinada.
Afrodita se construyó con React en mente pero no depende de React. Aquí, puede verlo utilizado con componentes 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 intentará automáticamente crear una etiqueta <style>
en el elemento <head>
del documento para colocar sus estilos generados. Afrodita solo generará una etiqueta <style>
y agregará nuevos estilos a esto con el tiempo. Si desea controlar qué etiqueta de estilo usa Afrodite, cree una etiqueta de estilo usted mismo con el atributo data-aphrodite
y Afrodita lo usará en lugar de crear una para usted.
Para acelerar la inyección de estilos, Afrodite intentará automáticamente amortiguar las escrituras en esta etiqueta <style>
para que ocurra un número mínimo de modificaciones DOM.
Afrodita usa lo antes posible para programar el enjuague del búfer. Si mide las dimensiones de los elementos DOM en componentDidMount
o componentDidUpdate
, puede usar setTimeout
o flushToStyleTag
para asegurarse de que se inyecten todos los estilos.
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 ,
} ,
} ) ;
Al asignar una cadena a la propiedad content
, requiere cotizaciones dobles o individuales en CSS. Por lo tanto, con Afrodita también debe proporcionar las cotizaciones dentro de la cadena de valor para que content
coincida con cómo se representará en CSS.
Como ejemplo:
const styles = StyleSheet . create ( {
large : {
':after' : {
content : '"Aphrodite"' ,
} ,
} ,
} ,
small : {
':before' : {
content : "'Aphrodite'" ,
} ,
} ,
} ) ;
El CSS generado será:
. large_im3wl1 : after {
content : "Aphrodite" !important ;
}
. small_ffd5jf : before {
content : 'Aphrodite' !important ;
}
Al combinar múltiples estilos de afrodita, se le recomienda fusionar todos sus estilos en una sola llamada a css()
, y no debe combinar los nombres de clases generados que las salidas de Afrodita (a través de la concatenación de cadenas, classnames
, etc.). Por ejemplo, si tiene un estilo base de foo
que está tratando de anular con 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 ) ;
¿Por qué importa? Aunque el segundo producirá un nombre de clase válido, no puede garantizar que los estilos bar
anularán los foo
. La forma en que funciona el CSS, no es el nombre de clase el que viene por último en un elemento que importa, es especificidad. Sin embargo, cuando miramos el CSS generado, encontramos que todos los nombres de clases tienen la misma especificidad, ya que todos son un nombre de clase único:
. foo_im3wl1 {
color : red;
}
. bar_hxfs3d {
color : blue;
}
En el caso de que la especificidad sea la misma, lo que importa es el orden en que los estilos aparecen en la hoja de estilo . Es decir, si la hoja de estilo generada parece
. foo_im3wl1 {
color : red;
}
. bar_hxfs3d {
color : blue;
}
Luego obtendrá el efecto apropiado de los estilos bar
que anulan los foo
, pero si se parece la hoja de estilo
. bar_hxfs3d {
color : blue;
}
. foo_im3wl1 {
color : red;
}
Luego terminamos con el efecto opuesto, ¡con bar
foo
sobre! La forma de resolver esto es pasar ambos estilos a la llamada css()
de Afrodita. Luego, producirá un nombre de clase único, como foo_im3wl1-o_O-bar_hxfs3d
, con los estilos de anulación correctamente, resolviendo así el problema:
. foo_im3wl1-o_O-bar_hxfs3d {
color : blue;
}
Cuando los estilos se especifican en Afrodita, el orden en que aparecen en la hoja de estilo real depende del orden de que las teclas se recuperen de los objetos. Este orden está determinado por el motor JavaScript que se está utilizando para representar los estilos. A veces, el orden en que los estilos aparecen en la hoja de estilo son importantes para la semántica del CSS. Por ejemplo, dependiendo del motor, los estilos generados por
const styles = StyleSheet . create ( {
ordered : {
margin : 0 ,
marginLeft : 15 ,
} ,
} ) ;
css ( styles . ordered ) ;
Puede esperar que se generen los siguientes CSS:
margin : 0 px ;
margin-left : 15 px ;
Pero dependiendo del orden de las teclas en el objeto de estilo, el CSS puede aparecer como
margin-left : 15 px ;
margin : 0 px ;
Lo cual es semánticamente diferente, porque el estilo que aparece más tarde anulará el estilo anterior.
Esto también podría manifestarse como un problema cuando la representación del lado del servidor, si los estilos generados aparecen en un orden diferente en el cliente y en el servidor.
Si experimenta este problema donde los estilos no aparecen en el CSS generado en el orden en que aparecen en sus objetos, hay dos soluciones:
No use propiedades de taquigrafía. Por ejemplo, en el ejemplo de margen anterior, al cambiar de usar una propiedad de taquigrafía y una propiedad de mano larga en los mismos estilos a usar solo propiedades de mano larga, el problema podría evitarse.
const styles = StyleSheet . create ( {
ordered : {
marginTop : 0 ,
marginRight : 0 ,
marginBottom : 0 ,
marginLeft : 15 ,
} ,
} ) ;
Especifique el pedido de sus estilos especificándolos usando un Map
. Dado que Map
S preserva su orden de inserción, Afrodite puede colocar sus estilos en el orden correcto.
const styles = StyleSheet . create ( {
ordered : new Map ( [
[ "margin" , 0 ] ,
[ "marginLeft" , 15 ] ,
] ) ,
} ) ;
Tenga en cuenta que Map
no son totalmente compatibles en todos los navegadores. Se puede polyefronizar usando un paquete como ES6-Shim.
Se pueden agregar características adicionales a Afrodita usando extensiones.
Para agregar extensiones a Afrodita, llame StyleSheet.extend
con las extensiones que está agregando. El resultado será un objeto que contenga las exportaciones habituales de afrodita ( css
, StyleSheet
, etc.) que tendrá sus extensiones incluidas. Por ejemplo:
// 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 ( {
...
} ) ;
Nota : El uso de extensiones puede hacer que los estilos de Afrodita no funcionen correctamente. La afrodita simple, cuando se usa correctamente, asegura que los estilos correctos siempre se aplicarán a los elementos. Debido a las reglas de especificidad de CSS, las extensiones pueden permitirle generar estilos que entran en conflicto entre sí, lo que hace que se muestren estilos incorrectos. Vea la extensión global a continuación para ver qué podría salir mal.
Actualmente, solo hay un tipo de extensión disponible: manejadores selectores. Este tipo de extensiones le permite mirar los selectores que alguien especifica y genere nuevos selectores basados en ellos. Se utilizan para manejar pseudo-estilos y consultas de medios dentro de Afrodita. Consulte los documentos defaultSelectorHandlers
para obtener información sobre cómo crear una función de controlador selector.
Para usar su extensión, cree un objeto que contenga una clave del tipo de extensión que creó, y pase eso a StyleSheet.extend()
::
const mySelectorHandler = ... ;
const myExtension = { selectorHandler : mySelectorHandler } ;
const { StyleSheet : newStyleSheet , css : newCss } = StyleSheet . extend ( [ myExtension ] ) ;
Como ejemplo, puede escribir una extensión que genera estilos globales como
const globalSelectorHandler = ( selector , _ , generateSubtreeStyles ) => {
if ( selector [ 0 ] !== "*" ) {
return null ;
}
return generateSubtreeStyles ( selector . slice ( 1 ) ) ;
} ;
const globalExtension = { selectorHandler : globalSelectorHandler } ;
¡Esto puede causar problemas cuando dos lugares intentan generar estilos para el mismo selector global! Por ejemplo, después
const styles = StyleSheet . create ( {
globals : {
'*div' : {
color : 'red' ,
} ,
}
} ) ;
const styles2 = StyleSheet . create ( {
globals : {
'*div' : {
color : 'blue' ,
} ,
} ,
} ) ;
css ( styles . globals ) ;
css ( styles2 . globals ) ;
No se determina si los DIV serán rojos o azules.
Minifique los nombres de clases estableciendo la variable de entorno process.env.NODE_ENV
a la production
de valor de cadena.
StyleSheet.create
y vea el CSS generadoCopyright (c) Academia Khan 2016