CSS-in-JS à framework-agnostique avec prise en charge du rendu côté serveur, préfixation du navigateur et génération CSS minimale.
Prise en charge du colocalisation de vos styles avec votre composant JavaScript.
:hover
, :active
, etc. sans avoir besoin de stocker un état de survol ou un état actif dans les composants. :visited
fonctionne très bien aussi.@font-face
.Aphrodite est distribué via NPM:
npm install --save aphrodite
Si vous préférez regarder des vidéos d'introduction, vous pouvez les trouver ici.
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' ,
}
}
} ) ;
Remarque: si vous souhaitez utiliser conditionnellement les styles, qui est simplement accompli via:
const className = css (
shouldBeRed ( ) ? styles . red : styles . blue ,
shouldBeResponsive ( ) && styles . small ,
shouldBeHoverable ( ) && styles . hover
)
< div className = { className } > Hi < / div>
Ceci est possible car tous les arguments de fausses seront ignorés.
Pour combiner des styles, transmettez plusieurs styles ou tableaux de styles dans css()
. Ceci est courant lors de la combinaison des styles d'un composant propriétaire:
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 fonction reset
peut être utilisée pour réinitialiser l'étiquette de style HTML, le tampon d'injection et le cache injecté. Utile lorsque Aphrodite doit être démolie et reculer.
import { reset } from 'aphrodite' ;
reset ( ) ;
Tandis que la fonction resetInjectedStyle
peut être utilisée pour réinitialiser le cache injecté pour une seule clé (généralement le nom de classe).
import { resetInjectedStyle } from 'aphrodite' ;
resetInjectedStyle ( 'class_1sAs8jg' ) ;
Pour effectuer un rendu côté serveur, appelez à StyleSheetServer.renderStatic
, qui prend un rappel. Faites votre rendu à l'intérieur du rappel et renvoyez le HTML généré. Tous les appels à css()
à l'intérieur du rappel seront collectés et le CSS généré ainsi que le HTML généré seront retournés.
La réhydratation permet à Aphrodite de savoir quels styles ont déjà été insérés dans la page. Si vous ne réhydratez pas, Aphrodite peut ajouter des styles en double à la page.
Pour effectuer une réhydratation, appelez StyleSheet.rehydrate
avec la liste des noms de classe générés qui vous sont renvoyés par StyleSheetServer.renderStatic
.
Remarque: Si vous utilisez aphrodite/no-important
dans votre projet et que vous souhaitez le rendre côté serveur, assurez-vous d'importer StyleSheetServer
à partir aphrodite/no-important
sinon vous allez obtenir une erreur.
Par exemple:
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
Par défaut, Aphrodite ajoutera !important
pour les définitions de style. Ceci est destiné à faciliter l'intégration avec une base de code préexistante. Si vous souhaitez éviter ce comportement, au lieu d'importer aphrodite
, importez aphrodite/no-important
. Sinon, l'utilisation est la même:
import { StyleSheet , css } from 'aphrodite/no-important' ;
Par défaut, Aphrodite réduira les noms de style à leurs hachages en production ( process.env.NODE_ENV === 'production'
). Vous pouvez remplacer ce comportement en appelant minify
avec true
ou false
avant d'appeler StyleSheet.create
.
Ceci est utile si vous souhaitez faciliter le débogage de la production par exemple.
import { StyleSheet , minify } from 'aphrodite' ;
// Always keep the full style names
minify ( false ) ;
// ... proceed to use StyleSheet.create etc.
La création de visages de police personnalisés est un cas spécial. En règle générale, vous devez définir une règle globale @font-face
. Dans le cas d'Aphrodite, nous voulons insérer cette règle que s'il est réellement référencé par une classe qui se trouve dans la page. Nous avons fait en sorte que la propriété fontFamily
puisse accepter un objet de police (directement ou à l'intérieur d'un tableau). Une règle globale @font-face
est ensuite générée en fonction de la définition de la police.
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 garantira que la règle Global @font-face
pour cette police n'est insérée qu'une seule fois, peu importe le nombre de fois où il est référencé.
Semblable aux faces de police, Aphrodite prend en charge les animations de l'image clé, mais elle est traitée comme un cas spécial. Une fois que nous trouvons une instance de l'animation référencée, une règle globale @keyframes
est créée et annexée sur la page.
Les animations sont fournies comme des objets décrivant l'animation, de manière typique @keyframes
. À l'aide de la propriété animationName
, vous pouvez fournir un seul objet d'animation ou un tableau d'objets d'animation. D'autres propriétés d'animation comme animationDuration
peuvent être fournies sous forme de chaînes.
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 garantira que les règles @keyframes
ne sont jamais dupliquées, peu importe le nombre de fois qu'une règle donnée est référencée.
Aphrodite a été construit avec React à l'esprit mais ne dépend pas de React. Ici, vous pouvez le voir utilisé avec les composants 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 tentera automatiquement de créer une balise <style>
dans l'élément <head>
du document pour mettre ses styles générés. APHRODITE ne générera qu'une seule balise <style>
et ajoutera de nouveaux styles à cela au fil du temps. Si vous souhaitez contrôler le style TAG UPHRODITE, Créez vous-même une balise de style avec l'attribut data-aphrodite
et Aphrodite l'utilisera au lieu d'en créer un pour vous.
Pour accélérer l'injection de styles, Aphrodite essaiera automatiquement de tamponner les écritures à cette balise <style>
afin que le nombre minimum de modifications DOM se produise.
Aphrodite utilise dès que possible pour planifier le rinçage du tampon. Si vous mesurez les dimensions de Dom Elements dans componentDidMount
ou componentDidUpdate
, vous pouvez utiliser setTimeout
ou flushToStyleTag
pour vous assurer que tous les styles sont injectés.
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 ,
} ,
} ) ;
Lors de l'attribution d'une chaîne à la propriété content
, il nécessite des devis doubles ou simples dans CSS. Par conséquent, avec Aphrodite, vous devez également fournir les devis dans la chaîne de valeur pour que content
correspond à la façon dont il sera représenté dans CSS.
Par exemple:
const styles = StyleSheet . create ( {
large : {
':after' : {
content : '"Aphrodite"' ,
} ,
} ,
} ,
small : {
':before' : {
content : "'Aphrodite'" ,
} ,
} ,
} ) ;
Le CSS généré sera:
. large_im3wl1 : after {
content : "Aphrodite" !important ;
}
. small_ffd5jf : before {
content : 'Aphrodite' !important ;
}
Lors de la combinaison de plusieurs styles aphrodites, vous êtes fortement recommandé de fusionner tous vos styles en un seul appel à css()
, et ne devez pas combiner les noms de classe générés que les sorties aphrodites (via la concaténation des chaînes, classnames
, etc.). Par exemple, si vous avez un style de base de foo
que vous essayez de remplacer avec 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 ) ;
Pourquoi est-ce important? Bien que le second produira un nom de classe valide, il ne peut garantir que les styles bar
remplaceront les foo
. La façon dont le CSS fonctionne, ce n'est pas le nom de classe qui vient en dernier sur un élément qui compte, c'est la spécificité. Cependant, lorsque nous regardons le CSS généré, nous constatons que tous les noms de classe ont la même spécificité, car ils sont tous un nom de classe unique:
. foo_im3wl1 {
color : red;
}
. bar_hxfs3d {
color : blue;
}
Dans le cas où la spécificité est la même, ce qui compte, c'est l'ordre dans lequel les styles apparaissent dans la feuille de style . C'est-à-dire si la feuille de style générée ressemble à
. foo_im3wl1 {
color : red;
}
. bar_hxfs3d {
color : blue;
}
Ensuite, vous obtiendrez l'effet approprié des styles bar
en remplace les foo
, mais si la feuille de style ressemble à
. bar_hxfs3d {
color : blue;
}
. foo_im3wl1 {
color : red;
}
Ensuite, nous nous retrouvons avec l'effet inverse, avec bar
primordiale foo
! La façon de résoudre ce problème est de passer les deux styles dans l'appel css()
d'Aphrodite. Ensuite, il produira un nom de classe unique, comme foo_im3wl1-o_O-bar_hxfs3d
, avec les styles correctement remplacés, résolvant ainsi le problème:
. foo_im3wl1-o_O-bar_hxfs3d {
color : blue;
}
Lorsque les styles sont spécifiés dans Aphrodite, l'ordre dans lequel ils apparaissent dans la feuille de style réelle dépend de l'ordre où les clés sont récupérées des objets. Cette commande est déterminée par le moteur JavaScript qui est utilisé pour rendre les styles. Parfois, l'ordre dans lequel les styles apparaissent dans la feuille de style pour la sémantique du CSS. Par exemple, selon le moteur, les styles générés à partir de
const styles = StyleSheet . create ( {
ordered : {
margin : 0 ,
marginLeft : 15 ,
} ,
} ) ;
css ( styles . ordered ) ;
Vous pourriez vous attendre à ce que le CSS suivant soit généré:
margin : 0 px ;
margin-left : 15 px ;
Mais selon l'ordre des clés dans l'objet de style, le CSS peut apparaître comme
margin-left : 15 px ;
margin : 0 px ;
Ce qui est sémantiquement différent, car le style qui apparaît plus tard remplacera le style avant.
Cela peut également se manifester comme un problème lors du rendu côté serveur, si les styles générés apparaissent dans un ordre différent sur le client et sur le serveur.
Si vous rencontrez ce problème où les styles n'apparaissent pas dans le CSS généré dans l'ordre où ils apparaissent dans vos objets, il existe deux solutions:
N'utilisez pas les propriétés des sténographies. Par exemple, dans l'exemple de marge ci-dessus, en passant de l'utilisation d'une propriété raccourci et d'une propriété à la main dans les mêmes styles pour utiliser uniquement les propriétés à la main, le problème pourrait être évité.
const styles = StyleSheet . create ( {
ordered : {
marginTop : 0 ,
marginRight : 0 ,
marginBottom : 0 ,
marginLeft : 15 ,
} ,
} ) ;
Spécifiez la commande de vos styles en les spécifiant à l'aide d'une Map
. Étant donné que Map
S préserve leur ordre d'insertion, Aphrodite est capable de placer vos styles dans le bon ordre.
const styles = StyleSheet . create ( {
ordered : new Map ( [
[ "margin" , 0 ] ,
[ "marginLeft" , 15 ] ,
] ) ,
} ) ;
Notez que Map
ne sont pas entièrement prises en charge dans tous les navigateurs. Il peut être polyvalé en utilisant un package comme ES6-SHIM.
Des fonctionnalités supplémentaires peuvent être ajoutées à Aphrodite à l'aide d'extensions.
Pour ajouter des extensions à Aphrodite, appelez StyleSheet.extend
avec les extensions que vous ajoutez. Le résultat sera un objet contenant les exportations habituelles d'Aphrodite ( css
, StyleSheet
, etc.) qui auront vos extensions incluses. Par exemple:
// 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 ( {
...
} ) ;
Remarque : L'utilisation d'extensions peut entraîner que les styles d'Aphrodite ne fonctionnent pas correctement. L'aphrodite simple, lorsqu'il est utilisé correctement, garantit que les styles corrects seront toujours appliqués aux éléments. En raison des règles de spécificité CSS, les extensions pourraient vous permettre de générer des styles qui entrent en conflit les uns avec les autres, ce qui fait afficher des styles incorrects. Voir l'extension globale ci-dessous pour voir ce qui pourrait mal tourner.
Actuellement, il n'y a qu'un seul type d'extension disponible: les gestionnaires de sélecteur. Ces types d'extensions vous permettent de regarder les sélecteurs que quelqu'un spécifie et génèrez de nouveaux sélecteurs en fonction d'eux. Ils sont utilisés pour gérer les pseudo-styles et les requêtes multimédias à l'intérieur d'Aphrodite. Voir les documents defaultSelectorHandlers
pour savoir comment créer une fonction de gestionnaire de sélecteur.
Pour utiliser votre extension, créez un objet contenant une clé du type d'extension que vous avez créé et passez-le dans StyleSheet.extend()
:
const mySelectorHandler = ... ;
const myExtension = { selectorHandler : mySelectorHandler } ;
const { StyleSheet : newStyleSheet , css : newCss } = StyleSheet . extend ( [ myExtension ] ) ;
Par exemple, vous pouvez écrire une extension qui génère des styles globaux comme
const globalSelectorHandler = ( selector , _ , generateSubtreeStyles ) => {
if ( selector [ 0 ] !== "*" ) {
return null ;
}
return generateSubtreeStyles ( selector . slice ( 1 ) ) ;
} ;
const globalExtension = { selectorHandler : globalSelectorHandler } ;
Cela peut causer des problèmes lorsque deux endroits essaient de générer des styles pour le même sélecteur mondial! Par exemple, après
const styles = StyleSheet . create ( {
globals : {
'*div' : {
color : 'red' ,
} ,
}
} ) ;
const styles2 = StyleSheet . create ( {
globals : {
'*div' : {
color : 'blue' ,
} ,
} ,
} ) ;
css ( styles . globals ) ;
css ( styles2 . globals ) ;
Il n'est pas déterminé si les Divs seront rouges ou bleus.
Noms de classe Minify en définissant la variable d'environnement process.env.NODE_ENV
sur la production
de valeur de chaîne.
StyleSheet.create
et voyez le CSS généréCopyright (C) 2016 Khan Academy