Kerangka kerja-agnostik-css-in-js dengan dukungan untuk rendering sisi server, awalan browser, dan generasi CSS minimum.
Dukungan untuk colocating gaya Anda dengan komponen JavaScript Anda.
:hover
, :active
, dll. Tanpa perlu menyimpan hover atau status aktif dalam komponen. :visited
juga baik -baik saja.@font-face
otomatis.Aphrodite didistribusikan melalui NPM:
npm install --save aphrodite
Jika Anda lebih suka menonton video pengantar, Anda dapat menemukannya di sini.
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' ,
}
}
} ) ;
Catatan: Jika Anda ingin menggunakan gaya secara kondisional, itu hanya dicapai melalui:
const className = css (
shouldBeRed ( ) ? styles . red : styles . blue ,
shouldBeResponsive ( ) && styles . small ,
shouldBeHoverable ( ) && styles . hover
)
< div className = { className } > Hi < / div>
Ini dimungkinkan karena setiap argumen palsu akan diabaikan.
Untuk menggabungkan gaya, lewati berbagai gaya atau array gaya ke css()
. Ini umum saat menggabungkan gaya dari komponen pemilik:
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'
}
} ) ;
Fungsi reset
dapat digunakan untuk mengatur ulang tag gaya HTML, buffer injeksi, dan cache yang disuntikkan. Berguna saat Aphrodite perlu dirobohkan dan diatur.
import { reset } from 'aphrodite' ;
reset ( ) ;
Sementara fungsi resetInjectedStyle
dapat digunakan untuk mengatur ulang cache yang disuntikkan untuk satu kunci (biasanya nama kelas).
import { resetInjectedStyle } from 'aphrodite' ;
resetInjectedStyle ( 'class_1sAs8jg' ) ;
Untuk melakukan rendering sisi server, lakukan panggilan ke StyleSheetServer.renderStatic
, yang menerima panggilan balik. Lakukan rendering Anda di dalam panggilan balik dan kembalikan HTML yang dihasilkan. Semua panggilan ke css()
di dalam panggilan balik akan dikumpulkan dan CSS yang dihasilkan serta HTML yang dihasilkan akan dikembalikan.
Rehidrasi memungkinkan Aphrodite tahu gaya mana yang telah dimasukkan ke dalam halaman. Jika Anda tidak rehidrasi, Aphrodite dapat menambahkan gaya duplikat ke halaman.
Untuk melakukan rehidrasi, hubungi StyleSheet.rehydrate
dengan daftar nama kelas yang dihasilkan dikembalikan kepada Anda oleh StyleSheetServer.renderStatic
.
Catatan: Jika Anda menggunakan aphrodite/no-important
dalam proyek Anda dan Anda ingin membuatnya di sisi server, pastikan untuk mengimpor StyleSheetServer
dari aphrodite/no-important
jika tidak Anda akan mendapatkan kesalahan.
Sebagai contoh:
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
Secara default, Aphrodite akan ditambahkan !important
untuk definisi gaya. Ini dimaksudkan untuk membuat integrasi dengan basis kode yang sudah ada sebelumnya lebih mudah. Jika Anda ingin menghindari perilaku ini, maka alih-alih mengimpor aphrodite
, impor aphrodite/no-important
. Jika tidak, penggunaannya sama:
import { StyleSheet , css } from 'aphrodite/no-important' ;
Secara default, Aphrodite akan meminifkan nama gaya hingga hash mereka dalam produksi ( process.env.NODE_ENV === 'production'
). Anda dapat mengesampingkan perilaku ini dengan menelepon minify
dengan true
atau false
sebelum menelepon StyleSheet.create
.
Ini berguna jika Anda ingin memfasilitasi debugging dalam produksi misalnya.
import { StyleSheet , minify } from 'aphrodite' ;
// Always keep the full style names
minify ( false ) ;
// ... proceed to use StyleSheet.create etc.
Membuat wajah font khusus adalah kasus khusus. Biasanya Anda perlu mendefinisikan aturan global @font-face
. Dalam kasus Aphrodite kami hanya ingin memasukkan aturan itu jika itu benar -benar dirujuk oleh kelas yang ada di halaman. Kami telah membuatnya sehingga properti fontFamily
dapat menerima objek wajah font (baik secara langsung atau di dalam array). Aturan global @font-face
kemudian dihasilkan berdasarkan definisi font.
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 akan memastikan bahwa aturan global @font-face
untuk font ini hanya dimasukkan sekali, tidak peduli berapa kali itu dirujuk.
Mirip dengan wajah font, Aphrodite mendukung animasi bingkai kunci, tetapi diperlakukan sebagai kasus khusus. Setelah kami menemukan contoh animasi yang direferensikan, aturan @keyframes
global dibuat dan ditambahkan ke halaman.
Animasi disediakan sebagai objek yang menggambarkan animasi, dengan cara @keyframes
yang khas. Menggunakan properti animationName
, Anda dapat menyediakan objek animasi tunggal, atau array objek animasi. Properti animasi lain seperti animationDuration
dapat disediakan sebagai string.
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 akan memastikan bahwa aturan @keyframes
tidak pernah diduplikasi, tidak peduli berapa kali aturan yang diberikan dirujuk.
Aphrodite dibangun dengan reaksi tetapi tidak bergantung pada reaksi. Di sini, Anda dapat melihatnya digunakan dengan komponen 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 akan secara otomatis mencoba untuk membuat tag <style>
di elemen <head>
dokumen untuk memasukkan gaya yang dihasilkan. Aphrodite hanya akan menghasilkan satu tag <style>
dan akan menambahkan gaya baru untuk ini dari waktu ke waktu. Jika Anda ingin mengontrol tag gaya mana yang digunakan Aphrodite, buat tag gaya sendiri dengan atribut data-aphrodite
dan Aphrodite akan menggunakannya alih-alih membuatnya untuk Anda.
Untuk mempercepat injeksi gaya, Aphrodite akan secara otomatis mencoba untuk buffer menulis ke tag <style>
ini sehingga jumlah minimum modifikasi DOM terjadi.
Aphrodite menggunakan ASAP untuk menjadwalkan pembilasan buffer. Jika Anda mengukur dimensi DOM Elements di componentDidMount
atau componentDidUpdate
, Anda dapat menggunakan setTimeout
atau flushToStyleTag
untuk memastikan semua gaya disuntikkan.
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 ,
} ,
} ) ;
Saat menetapkan string ke properti content
, ia memerlukan kutipan ganda atau tunggal di CSS. Oleh karena itu dengan aphrodite Anda juga harus memberikan kutipan dalam string nilai untuk content
agar sesuai dengan bagaimana hal itu akan diwakili dalam CSS.
Sebagai contoh:
const styles = StyleSheet . create ( {
large : {
':after' : {
content : '"Aphrodite"' ,
} ,
} ,
} ,
small : {
':before' : {
content : "'Aphrodite'" ,
} ,
} ,
} ) ;
CSS yang dihasilkan adalah:
. large_im3wl1 : after {
content : "Aphrodite" !important ;
}
. small_ffd5jf : before {
content : 'Aphrodite' !important ;
}
Saat menggabungkan beberapa gaya Aphrodite, Anda sangat disarankan untuk menggabungkan semua gaya Anda menjadi satu panggilan ke css()
, dan tidak boleh menggabungkan nama kelas yang dihasilkan yang output Aphrodite (melalui gabungan string, classnames
, dll.). Misalnya, jika Anda memiliki gaya dasar foo
yang Anda coba timpa dengan 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 ) ;
Mengapa itu penting? Meskipun yang kedua akan menghasilkan nama kelas yang valid, ia tidak dapat menjamin bahwa gaya bar
akan mengesampingkan yang foo
. Cara CSS bekerja, bukan nama kelas yang datang terakhir pada elemen yang penting, itu adalah spesifisitas. Ketika kita melihat CSS yang dihasilkan, kita menemukan bahwa semua nama kelas memiliki kekhususan yang sama, karena mereka semua adalah nama kelas tunggal:
. foo_im3wl1 {
color : red;
}
. bar_hxfs3d {
color : blue;
}
Dalam kasus di mana spesifisitasnya sama, yang penting adalah urutan gaya yang muncul di stylesheet . Seperti itu, jika stylesheet yang dihasilkan terlihat seperti
. foo_im3wl1 {
color : red;
}
. bar_hxfs3d {
color : blue;
}
maka Anda akan mendapatkan efek yang tepat dari gaya bar
yang mengimpung yang foo
, tetapi jika stylesheet terlihat seperti
. bar_hxfs3d {
color : blue;
}
. foo_im3wl1 {
color : red;
}
Lalu kita berakhir dengan efek yang berlawanan, dengan foo
Overriding bar
! Cara untuk menyelesaikan ini adalah dengan meneruskan kedua gaya ke dalam panggilan css()
Aphrodite. Kemudian, itu akan menghasilkan nama kelas tunggal, seperti foo_im3wl1-o_O-bar_hxfs3d
, dengan gaya yang ditimpa dengan benar, sehingga menyelesaikan masalah:
. foo_im3wl1-o_O-bar_hxfs3d {
color : blue;
}
Ketika gaya ditentukan dalam Aphrodite, urutan yang muncul dalam stylesheet yang sebenarnya tergantung pada urutan yang dikeluarkan oleh kunci dari objek. Pemesanan ini ditentukan oleh mesin JavaScript yang digunakan untuk membuat gaya. Terkadang, urutan gaya muncul di stylesheet materi untuk semantik CSS. Misalnya, tergantung pada mesin, gaya yang dihasilkan dari
const styles = StyleSheet . create ( {
ordered : {
margin : 0 ,
marginLeft : 15 ,
} ,
} ) ;
css ( styles . ordered ) ;
Anda mungkin mengharapkan CSS berikut akan dihasilkan:
margin : 0 px ;
margin-left : 15 px ;
Tetapi tergantung pada pemesanan kunci dalam objek gaya, CSS mungkin muncul sebagai
margin-left : 15 px ;
margin : 0 px ;
Yang berbeda secara semantik, karena gaya yang muncul kemudian akan mengesampingkan gaya sebelumnya.
Ini mungkin juga bermanifestasi sebagai masalah ketika rendering sisi server, jika gaya yang dihasilkan muncul dalam urutan yang berbeda pada klien dan di server.
Jika Anda mengalami masalah ini di mana gaya tidak muncul di CSS yang dihasilkan dalam urutan yang muncul di objek Anda, ada dua solusi:
Jangan gunakan properti steno. Misalnya, dalam contoh margin di atas, dengan beralih dari menggunakan properti steno dan properti panjang dalam gaya yang sama untuk hanya menggunakan properti panjang, masalah ini dapat dihindari.
const styles = StyleSheet . create ( {
ordered : {
marginTop : 0 ,
marginRight : 0 ,
marginBottom : 0 ,
marginLeft : 15 ,
} ,
} ) ;
Tentukan pemesanan gaya Anda dengan menentukannya menggunakan Map
. Karena Map
s lestarikan urutan penyisipan mereka, Aphrodite dapat menempatkan gaya Anda dalam urutan yang benar.
const styles = StyleSheet . create ( {
ordered : new Map ( [
[ "margin" , 0 ] ,
[ "marginLeft" , 15 ] ,
] ) ,
} ) ;
Perhatikan bahwa Map
tidak sepenuhnya didukung di semua browser. Ini dapat dipoles dengan menggunakan paket seperti ES6-shim.
Fitur tambahan dapat ditambahkan ke Aphrodite menggunakan ekstensi.
Untuk menambahkan ekstensi ke Aphrodite, call StyleSheet.extend
dengan ekstensi yang Anda tambahkan. Hasilnya akan menjadi objek yang berisi ekspor Aphrodite ( css
, StyleSheet
, dll.) Yang biasa yang akan disertakan ekstensi Anda. Misalnya:
// 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 ( {
...
} ) ;
Catatan : Menggunakan ekstensi dapat menyebabkan gaya Aphrodite tidak berfungsi dengan baik. Aphrodite polos, bila digunakan dengan benar, memastikan bahwa gaya yang benar akan selalu diterapkan pada elemen. Karena aturan spesifisitas CSS, ekstensi mungkin memungkinkan Anda untuk menghasilkan gaya yang saling bertentangan, menyebabkan gaya yang salah ditampilkan. Lihat ekstensi global di bawah ini untuk melihat apa yang bisa salah.
Saat ini, hanya ada satu jenis ekstensi yang tersedia: penangan pemilih. Jenis ekstensi ini memungkinkan Anda melihat pemilih yang ditentukan seseorang dan menghasilkan pemilih baru berdasarkan mereka. Mereka digunakan untuk menangani gaya semu dan kueri media di dalam Aphrodite. Lihat dokumen defaultSelectorHandlers
untuk informasi tentang cara membuat fungsi penangan pemilih.
Untuk menggunakan ekstensi Anda, buat objek yang berisi kunci dari jenis ekstensi yang Anda buat, dan meneruskannya ke StyleSheet.extend()
::
const mySelectorHandler = ... ;
const myExtension = { selectorHandler : mySelectorHandler } ;
const { StyleSheet : newStyleSheet , css : newCss } = StyleSheet . extend ( [ myExtension ] ) ;
Sebagai contoh, Anda bisa menulis ekstensi yang menghasilkan gaya global seperti
const globalSelectorHandler = ( selector , _ , generateSubtreeStyles ) => {
if ( selector [ 0 ] !== "*" ) {
return null ;
}
return generateSubtreeStyles ( selector . slice ( 1 ) ) ;
} ;
const globalExtension = { selectorHandler : globalSelectorHandler } ;
Ini dapat menyebabkan masalah ketika dua tempat mencoba menghasilkan gaya untuk pemilih global yang sama! Misalnya, setelahnya
const styles = StyleSheet . create ( {
globals : {
'*div' : {
color : 'red' ,
} ,
}
} ) ;
const styles2 = StyleSheet . create ( {
globals : {
'*div' : {
color : 'blue' ,
} ,
} ,
} ) ;
css ( styles . globals ) ;
css ( styles2 . globals ) ;
Tidak menentukan apakah div akan merah atau biru.
Minify Class Names dengan mengatur variabel production
process.env.NODE_ENV
StyleSheet.create
dan lihat CSS yang dihasilkanHak Cipta (C) 2016 Khan Academy