CSS-JS-JS-AGNOSTIC Framework com suporte para renderização do servidor, prefixo do navegador e geração mínima de CSS.
Suporte para colocar seus estilos com seu componente JavaScript.
:hover
, :active
, etc. sem precisar armazenar pairar ou estado ativo nos componentes. :visited
funciona muito bem também.@font-face
.Afrodite é distribuído via NPM:
npm install --save aphrodite
Se você preferir assistir a vídeos introdutórios, poderá encontrá -los aqui.
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: Se você deseja usar condicionalmente estilos, isso é simplesmente realizado via:
const className = css (
shouldBeRed ( ) ? styles . red : styles . blue ,
shouldBeResponsive ( ) && styles . small ,
shouldBeHoverable ( ) && styles . hover
)
< div className = { className } > Hi < / div>
Isso é possível porque quaisquer argumentos falsos serão ignorados.
Para combinar estilos, passe vários estilos ou matrizes de estilos em css()
. Isso é comum ao combinar estilos de um componente do proprietário:
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'
}
} ) ;
A função reset
pode ser usada para redefinir a etiqueta de estilo HTML, o buffer de injeção e o cache injetado. Útil quando Afrodite precisa ser rasgado e recuado.
import { reset } from 'aphrodite' ;
reset ( ) ;
Enquanto a função resetInjectedStyle
pode ser usada para redefinir o cache injetado para uma única chave (geralmente o nome da classe).
import { resetInjectedStyle } from 'aphrodite' ;
resetInjectedStyle ( 'class_1sAs8jg' ) ;
Para executar a renderização do lado do servidor, faça uma chamada para o StyleSheetServer.renderStatic
, que requer um retorno de chamada. Faça sua renderização dentro do retorno de chamada e retorne o HTML gerado. Todas as chamadas para css()
dentro do retorno de chamada serão coletadas e o CSS gerado, bem como o HTML gerado, será retornado.
A reidratação permite que Afrodite saiba quais estilos já foram inseridos na página. Se você não reidratar, Afrodite pode adicionar estilos duplicados à página.
Para realizar a reidratação, ligue para StyleSheet.rehydrate
com a lista de nomes de classe gerados devolvidos a você pelo StyleSheetServer.renderStatic
.
NOTA: Se você estiver usando aphrodite/no-important
em seu projeto e desejar renderizá-lo no lado do servidor, não se esqueça de importar StyleSheetServer
do aphrodite/no-important
caso contrário você receberá um erro.
Como exemplo:
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 padrão, o Aphrodite anexará !important
para definições de estilo. Isso pretende facilitar a integração com uma base de código pré-existente. Se você deseja evitar esse comportamento, em vez de importar aphrodite
, importe aphrodite/no-important
. Caso contrário, o uso é o mesmo:
import { StyleSheet , css } from 'aphrodite/no-important' ;
Por padrão, o Aphrodite minificará os nomes de estilo até seus hashes na produção ( process.env.NODE_ENV === 'production'
). Você pode substituir esse comportamento ligando para minify
com true
ou false
antes de ligar para StyleSheet.create
.
Isso é útil se você deseja facilitar a depuração na produção, por exemplo.
import { StyleSheet , minify } from 'aphrodite' ;
// Always keep the full style names
minify ( false ) ;
// ... proceed to use StyleSheet.create etc.
Criar faces de fontes personalizados é um caso especial. Normalmente, você precisa definir uma regra global @font-face
. No caso de Afrodite, queremos apenas inserir essa regra se ela estiver sendo realmente referenciada por uma classe que está na página. Fizemos isso para que a propriedade fontFamily
possa aceitar um objeto de face da fonte (diretamente ou dentro de uma matriz). Uma regra global @font-face
é então gerada com base na definição da fonte.
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
}
} ) ;
Afrodite garantirá que a regra global @font-face
para essa fonte seja inserida apenas uma vez, não importa quantas vezes seja referenciada.
Semelhante aos rostos de fontes, o Afrodite suporta animações de quadro -chave, mas é tratado como um caso especial. Depois que encontramos uma instância da animação que está sendo referenciada, uma regra global @keyframes
é criada e anexada à página.
As animações são fornecidas como objetos que descrevem a animação, na moda típica @keyframes
. Usando a propriedade animationName
, você pode fornecer um único objeto de animação ou uma matriz de objetos de animação. Outras propriedades de animação, como animationDuration
podem ser fornecidas como strings.
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' ,
} ,
} ) ;
Afrodite garantirá que as regras @keyframes
nunca sejam duplicadas, não importa quantas vezes uma determinada regra seja referenciada.
Afrodite foi construído com o React em mente, mas não depende do reagir. Aqui, você pode vê -lo usado com componentes da 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 ) ;
O Afrodite tentará automaticamente criar uma tag <style>
no elemento <head>
do documento para colocar seus estilos gerados. Afrodite só gerará uma tag <style>
e adicionará novos estilos a isso com o tempo. Se você deseja controlar qual estilo a tag Afrodite usa, crie uma tag de estilo com o atributo data-aphrodite
e Afrodite usará isso em vez de criar um para você.
Para acelerar a injeção de estilos, o Afrodite tentará automaticamente o buffer gravações nesta tag <style>
para que o número mínimo de modificações DOM aconteça.
Afrodite usa o mais rápido possível para agendar a descarga de buffer. Se você medir as dimensões dos elementos do DOM no componentDidMount
ou componentDidUpdate
, poderá usar setTimeout
ou flushToStyleTag
para garantir que todos os estilos sejam injetados.
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 ,
} ,
} ) ;
Ao atribuir uma string à propriedade content
, é necessário cotações duplas ou únicas no CSS. Portanto, com o Afrodite, você também deve fornecer as cotações dentro da sequência de valores para content
para corresponder como ela será representada no CSS.
Como exemplo:
const styles = StyleSheet . create ( {
large : {
':after' : {
content : '"Aphrodite"' ,
} ,
} ,
} ,
small : {
':before' : {
content : "'Aphrodite'" ,
} ,
} ,
} ) ;
O CSS gerado será:
. large_im3wl1 : after {
content : "Aphrodite" !important ;
}
. small_ffd5jf : before {
content : 'Aphrodite' !important ;
}
Ao combinar vários estilos de Afrodite, você é fortemente recomendado para mesclar todos os seus estilos em uma única chamada para css()
e não deve combinar os nomes de classe gerados que as saídas de Afrodite (via concatenação de string, classnames
etc.). Por exemplo, se você tem um estilo base de foo
que está tentando substituir com 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 que isso importa? Embora o segundo produza um nome de classe válido, ele não pode garantir que os estilos bar
substituam os foo
. A maneira como o CSS funciona, não é o nome da classe que vem por último em um elemento que importa, é especificidade. Quando olhamos para o CSS gerado, descobrimos que todos os nomes das classes têm a mesma especificidade, pois todos são um nome de classe única:
. foo_im3wl1 {
color : red;
}
. bar_hxfs3d {
color : blue;
}
No caso em que a especificidade é a mesma, o que importa é a ordem que os estilos aparecem na folha de estilo . Isto é, se a folha de estilo gerada se parece
. foo_im3wl1 {
color : red;
}
. bar_hxfs3d {
color : blue;
}
Então você terá o efeito apropriado dos estilos bar
substituindo os foo
, mas se a folha de estilo parece
. bar_hxfs3d {
color : blue;
}
. foo_im3wl1 {
color : red;
}
Então acabamos com o efeito oposto, com foo
SUPLIDINGS bar
! A maneira de resolver isso é passar os dois estilos para a chamada css()
da Afrodite. Em seguida, ele produzirá um nome de classe única, como foo_im3wl1-o_O-bar_hxfs3d
, com os estilos substituídos corretamente, resolvendo assim o problema:
. foo_im3wl1-o_O-bar_hxfs3d {
color : blue;
}
Quando os estilos são especificados em Afrodite, a ordem que eles aparecem na folha de estilo real depende da ordem em que as chaves são recuperadas dos objetos. Essa ordem é determinada pelo mecanismo JavaScript que está sendo usado para renderizar os estilos. Às vezes, a ordem em que os estilos aparecem na matéria da folha de estilo para a semântica do CSS. Por exemplo, dependendo do motor, os estilos gerados a partir de
const styles = StyleSheet . create ( {
ordered : {
margin : 0 ,
marginLeft : 15 ,
} ,
} ) ;
css ( styles . ordered ) ;
Você pode esperar que o seguinte CSS seja gerado:
margin : 0 px ;
margin-left : 15 px ;
Mas, dependendo da ordem das chaves no objeto de estilo, o CSS pode aparecer como
margin-left : 15 px ;
margin : 0 px ;
que é semanticamente diferente, porque o estilo que aparece mais tarde substituirá o estilo antes dele.
Isso também pode se manifestar como um problema ao renderização do lado do servidor, se os estilos gerados aparecerem em um pedido diferente no cliente e no servidor.
Se você tiver esse problema em que os estilos não aparecem no CSS gerado na ordem em que eles aparecem em seus objetos, existem duas soluções:
Não use propriedades abreviadas. Por exemplo, no exemplo de margem acima, passando do uso de uma propriedade abreviada e uma propriedade longa nos mesmos estilos para usar apenas propriedades de longa e, o problema poderia ser evitado.
const styles = StyleSheet . create ( {
ordered : {
marginTop : 0 ,
marginRight : 0 ,
marginBottom : 0 ,
marginLeft : 15 ,
} ,
} ) ;
Especifique a ordem de seus estilos especificando -os usando um Map
. Como Map
s preserva sua ordem de inserção, o Aphrodite é capaz de colocar seus estilos na ordem correta.
const styles = StyleSheet . create ( {
ordered : new Map ( [
[ "margin" , 0 ] ,
[ "marginLeft" , 15 ] ,
] ) ,
} ) ;
Observe que Map
não são totalmente suportados em todos os navegadores. Pode ser poli-preenchido usando um pacote como ES6-Shim.
Recursos extras podem ser adicionados ao Afrodite usando extensões.
Para adicionar extensões ao Afrodite, ligue para StyleSheet.extend
com as extensões que você está adicionando. O resultado será um objeto que contém as exportações usuais de Afrodite ( css
, StyleSheet
etc.) que terão suas extensões incluídas. Por exemplo:
// 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 : O uso de extensões pode fazer com que os estilos da Afrodite não funcionem corretamente. Afrodita simples, quando usada corretamente, garante que os estilos corretos sempre sejam aplicados aos elementos. Devido às regras de especificidade do CSS, as extensões podem permitir que você gere estilos que conflitam entre si, fazendo com que os estilos incorretos sejam mostrados. Veja a extensão global abaixo para ver o que poderia dar errado.
Atualmente, existe apenas um tipo de extensão disponível: manipuladores de seletor. Esses tipos de extensões permitem olhar para os seletores que alguém especifica e gerar novos seletores com base neles. Eles são usados para lidar com pseudo-estilos e consultas de mídia dentro de Afrodite. Consulte os documentos defaultSelectorHandlers
para obter informações sobre como criar uma função de manipulador de seletor.
Para usar sua extensão, crie um objeto que contenha uma chave do tipo de extensão que você criou e passe isso para o StyleSheet.extend()
:
const mySelectorHandler = ... ;
const myExtension = { selectorHandler : mySelectorHandler } ;
const { StyleSheet : newStyleSheet , css : newCss } = StyleSheet . extend ( [ myExtension ] ) ;
Como exemplo, você pode escrever uma extensão que gera estilos globais como
const globalSelectorHandler = ( selector , _ , generateSubtreeStyles ) => {
if ( selector [ 0 ] !== "*" ) {
return null ;
}
return generateSubtreeStyles ( selector . slice ( 1 ) ) ;
} ;
const globalExtension = { selectorHandler : globalSelectorHandler } ;
No entanto, isso pode causar problemas quando dois lugares tentam gerar estilos para o mesmo seletor global! Por exemplo, depois
const styles = StyleSheet . create ( {
globals : {
'*div' : {
color : 'red' ,
} ,
}
} ) ;
const styles2 = StyleSheet . create ( {
globals : {
'*div' : {
color : 'blue' ,
} ,
} ,
} ) ;
css ( styles . globals ) ;
css ( styles2 . globals ) ;
Não está determinado se as divs serão vermelhas ou azuis.
Minify Nomes de classe Configurando a variável de ambiente process.env.NODE_ENV
para a production
do valor da string.
StyleSheet.create
e veja o CSS geradoCopyright (c) 2016 Khan Academy