Framework-agnostische CSS-in-JS mit Unterstützung für serverseitiges Rendering, Browser-Präfixen und Mindest-CSS-Generierung.
Unterstützung für das Colocieren Ihrer Stile mit Ihrer JavaScript -Komponente.
:hover
,: :active
usw., ohne Schwebeplätze oder aktiven Zustand in Komponenten zu speichern. :visited
funktioniert auch gut.@font-face
.Aphrodite wird über NPM verteilt:
npm install --save aphrodite
Wenn Sie sich lieber Einführungsvideos ansehen möchten, finden Sie sie hier.
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' ,
}
}
} ) ;
HINWEIS: Wenn Sie Stile verwenden möchten, wird dies einfach über:
const className = css (
shouldBeRed ( ) ? styles . red : styles . blue ,
shouldBeResponsive ( ) && styles . small ,
shouldBeHoverable ( ) && styles . hover
)
< div className = { className } > Hi < / div>
Dies ist möglich, weil falsche Argumente ignoriert werden.
Um Stile zu kombinieren, übergeben Sie mehrere Stile oder Arrays von Stilen in css()
. Dies ist üblich, wenn Sie Stile einer Eigentümerkomponente kombinieren:
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'
}
} ) ;
Die reset
-Funktion kann verwendet werden, um das HTML -Style -Tag, das Injektionspuffer und den injizierten Cache zurückzusetzen. Nützlich, wenn Aphrodite abgerissen und wieder aufgestellt werden muss.
import { reset } from 'aphrodite' ;
reset ( ) ;
Während die Funktion resetInjectedStyle
verwendet werden kann, um den injizierten Cache für einen einzelnen Schlüssel zurückzusetzen (normalerweise der Klassenname).
import { resetInjectedStyle } from 'aphrodite' ;
resetInjectedStyle ( 'class_1sAs8jg' ) ;
Um das serverseitige Rendering durchzuführen, rufen Sie einen Anruf bei StyleSheetServer.renderStatic
an, das einen Rückruf enthält. Machen Sie Ihr Rendering im Rückruf und geben Sie die generierte HTML zurück. Alle Anrufe bei css()
innerhalb des Rückrufs werden gesammelt, und die generierten CSS sowie die generierte HTML werden zurückgegeben.
Durch Rehydrating informiert sich Aphrodite, welche Stile bereits in die Seite eingefügt wurden. Wenn Sie nicht rehydrieren, kann Aphrodite der Seite doppelte Stile hinzufügen.
Um eine Rehydration durchzuführen, rufen Sie StyleSheet.rehydrate
mit der Liste der generierten Klassennamen auf, die Ihnen von StyleSheetServer.renderStatic
an Sie zurückgegeben wurden.
Hinweis: Wenn Sie aphrodite/no-important
in Ihrem Projekt verwenden und es auf der Serverseite rendern möchten, importieren Sie StyleSheetServer
von aphrodite/no-important
sonst machen Sie einen Fehler.
Als Beispiel:
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
Standardmäßig wird Aphrodite für Stildefinitionen angehängt !important
Dies soll die Integration in eine bereits bestehende Codebasis erleichtern. Wenn Sie dieses Verhalten vermeiden möchten, importieren Sie aphrodite/no-important
, anstatt aphrodite
zu importieren. Ansonsten ist die Verwendung gleich:
import { StyleSheet , css } from 'aphrodite/no-important' ;
Standardmäßig wird Aphrodite die Stilnamen in der Produktion zu ihren Hashes ( process.env.NODE_ENV === 'production'
) minimieren. Sie können dieses Verhalten überschreiben, indem Sie minify
mit true
oder false
anrufen, bevor Sie StyleSheet.create
aufrufen.
Dies ist nützlich, wenn Sie beispielsweise das Debuggen in der Produktion erleichtern möchten.
import { StyleSheet , minify } from 'aphrodite' ;
// Always keep the full style names
minify ( false ) ;
// ... proceed to use StyleSheet.create etc.
Das Erstellen benutzerdefinierter Schrift Gesichter ist ein Sonderfall. Normalerweise müssen Sie eine globale @font-face
-Regel definieren. Bei Aphrodite möchten wir diese Regel nur einfügen, wenn sie tatsächlich von einer Klasse auf der Seite verwiesen wird. Wir haben es so gemacht, dass die Eigenschaft fontFamily
ein Schriftart Objekt (entweder direkt oder in einem Array) akzeptieren kann. Eine globale @font-face
-Regel wird dann basierend auf der Schriftdefinition generiert.
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 stellt sicher, dass die globale @font-face
Regel für diese Schriftart nur einmal eingefügt wird, egal wie oft sie verwiesen wird.
Ähnlich wie bei der Schriftart unterstützt Aphrodite Keyframe -Animationen, wird jedoch als Sonderfall behandelt. Sobald wir eine Instanz der Animation gefunden haben, die verwiesen wird, wird eine globale @keyframes
-Regel erstellt und auf die Seite angehängt.
Animationen werden als Objekte bereitgestellt, die die Animation in typischer @keyframes
-Mode beschreiben. Mit der Eigenschaft animationName
können Sie ein einzelnes Animationsobjekt oder eine Reihe von Animationsobjekten angeben. Andere Animationseigenschaften wie animationDuration
können als Zeichenfolgen bereitgestellt werden.
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 stellt sicher, dass @keyframes
-Regeln niemals dupliziert werden, egal wie oft eine bestimmte Regel verwiesen wird.
Aphrodite wurde unter Berücksichtigung von React gebaut, hängt jedoch nicht von React ab. Hier sehen Sie, dass es mit Webkomponenten verwendet wird:
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 versucht automatisch, im <head>
des Dokuments ein <style>
-Tag zu erstellen, um seine generierten Stile einzugeben. Aphrodite generiert nur ein <style>
-Tag und fügt dieser Zeit im Laufe der Zeit neue Stile hinzu. Wenn Sie steuern möchten, welches Stil-Tag-Aphrodite verwendet wird, erstellen Sie selbst ein Stil-Tag mit dem data-aphrodite
-Attribut, und Aphrodite verwendet dies, anstatt eines für Sie zu erstellen.
Um die Injektion von Stilen zu beschleunigen, wird Aphrodite automatisch versucht, zu diesem <style>
-T -Tag zu puffern, damit die Anzahl der DOM -Modifikationen minimale DOM -Modifikationen erfolgen.
Aphrodite verwendet ASAP, um das Spülen des Puffers zu planen. Wenn Sie die Abmessungen von DOM -Elementen in componentDidMount
oder componentDidUpdate
messen, können Sie setTimeout
oder flushToStyleTag
verwenden, um sicherzustellen, dass alle Stile injiziert werden.
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 ,
} ,
} ) ;
Bei der Zuweisung einer Zeichenfolge der content
sind doppelte oder einzelne Zitate in CSS erforderlich. Daher müssen Sie mit Aphrodite auch die Zitate innerhalb der Wertzeichenfolge bereitstellen, damit content
in CSS übereinstimmen, wie sie in CSS dargestellt werden.
Als Beispiel:
const styles = StyleSheet . create ( {
large : {
':after' : {
content : '"Aphrodite"' ,
} ,
} ,
} ,
small : {
':before' : {
content : "'Aphrodite'" ,
} ,
} ,
} ) ;
Das erzeugte CSS wird sein:
. large_im3wl1 : after {
content : "Aphrodite" !important ;
}
. small_ffd5jf : before {
content : 'Aphrodite' !important ;
}
Bei der Kombination mehrerer Aphroditstile wird dringend empfohlen, alle Ihre Stile in einen einzigen Aufruf an css()
zusammenzuführen und sollten nicht die generierten Klassennamen kombinieren, die Aphrodite ausgibt (über String -Verkettung, classnames
usw.). Wenn Sie beispielsweise einen Grundstil von foo
haben, den Sie mit bar
überschreiben möchten:
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 ) ;
Warum ist es wichtig? Obwohl der zweite einen gültigen Klassennamen erzeugt, kann er nicht garantieren, dass die bar
die foo
überschreiben. Die Art und Weise, wie das CSS funktioniert, ist nicht der Klassenname, der zu einem Element kommt , das wichtig ist, sondern Spezifität. Wenn wir uns die generierten CSS ansehen, stellen wir fest, dass alle Klassennamen die gleiche Spezifität haben, da sie alle ein einzelner Klassenname sind:
. foo_im3wl1 {
color : red;
}
. bar_hxfs3d {
color : blue;
}
In dem Fall, in dem die Spezifität gleich ist, ist die Reihenfolge, in der die Stile im Stylesheet erscheinen . Das heißt, wenn das generierte Stylesheet wie aussieht
. foo_im3wl1 {
color : red;
}
. bar_hxfs3d {
color : blue;
}
Dann erhalten Sie den entsprechenden Effekt der bar
, die die foo
-Überschreibung überschreiben, aber wenn das Stylesheet wie aussieht
. bar_hxfs3d {
color : blue;
}
. foo_im3wl1 {
color : red;
}
Dann haben wir den gegenteiligen Effekt, mit foo
Overried bar
! Die Art und Weise, dies zu lösen, besteht darin, beide Stile in css()
Call von Aphrodite zu übergeben. Dann erzeugt es einen einzelnen Klassennamen, wie foo_im3wl1-o_O-bar_hxfs3d
, mit den korrekten überschriebenen Stilen, wodurch das Problem gelöst wird:
. foo_im3wl1-o_O-bar_hxfs3d {
color : blue;
}
Wenn Stiles in Aphrodite angegeben werden, hängt die Reihenfolge, die sie im tatsächlichen Stylesheet erscheinen, von der Reihenfolge ab, dass Schlüssel aus den Objekten abgerufen werden. Diese Bestellung wird durch die JavaScript -Engine bestimmt, mit der die Stile rendern. Manchmal ist die Reihenfolge, die die Stile in der Stylesheet -Angelegenheit für die Semantik des CSS erscheinen. Zum Beispiel abhängig vom Motor die Stile, aus denen erzeugt wird
const styles = StyleSheet . create ( {
ordered : {
margin : 0 ,
marginLeft : 15 ,
} ,
} ) ;
css ( styles . ordered ) ;
Sie können erwarten, dass das folgende CSS generiert wird:
margin : 0 px ;
margin-left : 15 px ;
Aber abhängig von der Bestellung der Schlüssel im Stilobjekt könnten das CSS als erscheinen
margin-left : 15 px ;
margin : 0 px ;
Das ist semantisch anders, denn der Stil, der später erscheint, wird den Stil vor ihm außer Kraft setzen.
Dies kann sich auch als Problem beim serverseitigen Rendering manifestieren, wenn die generierten Stile in einer anderen Reihenfolge auf dem Client und auf dem Server angezeigt werden.
Wenn Sie dieses Problem erleben, in dem Stile in der erzeugten CSS nicht in der Reihenfolge angezeigt werden, die in Ihren Objekten angezeigt wird, gibt es zwei Lösungen:
Verwenden Sie keine Kurzeigenschaften. Zum Beispiel kann im obigen Margenbeispiel durch die Verwendung einer Abkürzungseigenschaft und eine Langhandeigenschaft in denselben Stilen auf nur Langhandeigenschaften umgewandelt werden, das Problem vermieden werden.
const styles = StyleSheet . create ( {
ordered : {
marginTop : 0 ,
marginRight : 0 ,
marginBottom : 0 ,
marginLeft : 15 ,
} ,
} ) ;
Geben Sie die Bestellung Ihrer Stile an, indem Sie sie mit einer Map
angeben. Da Map
S ihre Einfügungsreihenfolge bewahrt, kann Aphrodite Ihre Stile in der richtigen Reihenfolge platzieren.
const styles = StyleSheet . create ( {
ordered : new Map ( [
[ "margin" , 0 ] ,
[ "marginLeft" , 15 ] ,
] ) ,
} ) ;
Beachten Sie, dass Map
s in allen Browsern nicht vollständig unterstützt werden. Es kann durch die Verwendung eines Pakets wie ES6-Shim polyfillt werden.
Aphrodite können zusätzliche Funktionen unter Verwendung von Erweiterungen hinzugefügt werden.
Um APhrodite Erweiterungen hinzuzufügen, rufen Sie StyleSheet.extend
auf. Verwechseln Sie mit den Erweiterungen, die Sie hinzufügen. Das Ergebnis wird ein Objekt sein, das die üblichen Exporte von Aphrodite ( css
, StyleSheet
usw.) enthält, die Ihre Erweiterungen enthalten. Zum Beispiel:
// 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 ( {
...
} ) ;
Hinweis : Die Verwendung von Erweiterungen kann dazu führen, dass die Stile von Aphrodite nicht richtig funktionieren. Einfaches Aphrodit stellt bei ordnungsgemäß sicher, dass die richtigen Stile immer auf Elemente angewendet werden. Aufgrund von CSS -Spezifitätsregeln können Sie in Erweiterungen möglicherweise Stile generieren, die miteinander in Konflikt stehen, wodurch falsche Stile angezeigt werden. Sehen Sie sich die globale Erweiterung unten an, um zu sehen, was schief gehen könnte.
Derzeit ist nur eine Art von Erweiterung verfügbar: Selektorhandler. Mit dieser Art von Erweiterungen können Sie die Selektoren betrachten, die jemand angibt und neue Selektoren basierend darauf generieren. Sie werden verwendet, um Pseudo-Stile und Medienabfragen innerhalb von Aphrodite zu bewältigen. Informationen zum Erstellen einer Selektorhandlerfunktion finden Sie in den Dokumenten für defaultSelectorHandlers
.
Um Ihre Erweiterung zu verwenden, erstellen Sie ein Objekt, das einen Schlüssel der Art der Erweiterung enthält, die Sie erstellt haben, und übergeben Sie diese an StyleSheet.extend()
:
const mySelectorHandler = ... ;
const myExtension = { selectorHandler : mySelectorHandler } ;
const { StyleSheet : newStyleSheet , css : newCss } = StyleSheet . extend ( [ myExtension ] ) ;
Als Beispiel könnten Sie eine Erweiterung schreiben, die globale Stile erzeugt wie
const globalSelectorHandler = ( selector , _ , generateSubtreeStyles ) => {
if ( selector [ 0 ] !== "*" ) {
return null ;
}
return generateSubtreeStyles ( selector . slice ( 1 ) ) ;
} ;
const globalExtension = { selectorHandler : globalSelectorHandler } ;
Dies kann zu Problemen führen, wenn zwei Orte versuchen, Stile für denselben globalen Selektor zu generieren! Zum Beispiel nach
const styles = StyleSheet . create ( {
globals : {
'*div' : {
color : 'red' ,
} ,
}
} ) ;
const styles2 = StyleSheet . create ( {
globals : {
'*div' : {
color : 'blue' ,
} ,
} ,
} ) ;
css ( styles . globals ) ;
css ( styles2 . globals ) ;
Es ist nicht bestimmt, ob Divs rot oder blau sein werden.
Klassennamen minifieren, indem Sie den process.env.NODE_ENV
einstellen production
StyleSheet.create
und das generierte CSS sehenCopyright (C) 2016 Khan Academy