Aller au contenu

Utilitaire css ​

L’utilitaire CSS, hono/css, fournit la prise en charge intégrée de CSS dans JS(X) pour Hono.

Vous pouvez écrire du CSS dans JSX avec un littéral de gabarit JavaScript balisé par css. La valeur renvoyée par css est le nom de classe à affecter à l’attribut class. Le composant <Style /> contiendra alors le contenu CSS.

Importation ​

ts
import { Hono } from 'hono'
import { css, cx, keyframes, Style, createCssContext } from 'hono/css'

css Expérimental ​

Vous pouvez écrire du CSS dans le littéral de gabarit css. Dans cet exemple, headerClass est utilisé comme valeur de l’attribut class. N’oubliez pas d’ajouter <Style />, qui contient le contenu CSS.

ts
app.get('/', (c) => {
  const headerClass = css`
    background-color: orange;
    color: white;
    padding: 1rem;
  `
  return c.html(
    <html>
      <head>
        <Style />
      </head>
      <body>
        <h1 class={headerClass}>Hello!</h1>
      </body>
    </html>
  )
})

Vous pouvez appliquer des styles aux pseudo-classes comme :hover avec le sélecteur d’imbrication & :

ts
const buttonClass = css`
  background-color: #fff;
  &:hover {
    background-color: red;
  }
`

Extension ​

Vous pouvez étendre une définition CSS en y insérant le nom de classe.

tsx
const baseClass = css`
  color: white;
  background-color: blue;
`

const header1Class = css`
  ${baseClass}
  font-size: 3rem;
`

const header2Class = css`
  ${baseClass}
  font-size: 2rem;
`

De plus, la syntaxe ${baseClass} {} permet d’imbriquer des classes.

tsx
const headerClass = css`
  color: white;
  background-color: blue;
`
const containerClass = css`
  ${headerClass} {
    h1 {
      font-size: 3rem;
    }
  }
`
return c.render(
  <div class={containerClass}>
    <header class={headerClass}>
      <h1>Hello!</h1>
    </header>
  </div>
)

Styles globaux ​

Le pseudo-sélecteur :-hono-global permet de définir des styles globaux.

tsx
const globalClass = css`
  :-hono-global {
    html {
      font-family: Arial, Helvetica, sans-serif;
    }
  }
`

return c.render(
  <div class={globalClass}>
    <h1>Hello!</h1>
    <p>Today is a good day.</p>
  </div>
)

Vous pouvez aussi écrire du CSS dans le composant <Style /> avec le littéral css.

tsx
export const renderer = jsxRenderer(({ children, title }) => {
  return (
    <html>
      <head>
        <Style>{css`
          html {
            font-family: Arial, Helvetica, sans-serif;
          }
        `}</Style>
        <title>{title}</title>
      </head>
      <body>
        <div>{children}</div>
      </body>
    </html>
  )
})

keyframes Expérimental ​

Vous pouvez utiliser keyframes pour écrire le contenu de @keyframes. Dans cet exemple, fadeInAnimation sera le nom de l’animation.

tsx
const fadeInAnimation = keyframes`
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
`
const headerClass = css`
  animation-name: ${fadeInAnimation};
  animation-duration: 2s;
`
const Header = () => <a class={headerClass}>Hello!</a>

cx Expérimental ​

cx combine les deux noms de classe.

tsx
const buttonClass = css`
  border-radius: 10px;
`
const primaryClass = css`
  background: orange;
`
const Button = () => (
  <a class={cx(buttonClass, primaryClass)}>Click!</a>
)

Il peut également combiner des chaînes simples.

tsx
const Header = () => <a class={cx('h1', primaryClass)}>Hi</a>

Utilisation avec le middleware Secure Headers ​

Pour utiliser les utilitaires CSS avec le middleware Secure Headers, vous pouvez ajouter l’attribut nonce à <Style nonce={c.get('secureHeadersNonce')} /> afin d’éviter les violations de Content-Security-Policy causées par les utilitaires CSS.

tsx
import { secureHeaders, NONCE } from 'hono/secure-headers'

app.get(
  '*',
  secureHeaders({
    contentSecurityPolicy: {
      // Set the pre-defined nonce value to `styleSrc`:
      styleSrc: [NONCE],
    },
  })
)

app.get('/', (c) => {
  const headerClass = css`
    background-color: orange;
    color: white;
    padding: 1rem;
  `
  return c.html(
    <html>
      <head>
        {/* Set the `nonce` attribute on the CSS helpers `style` and `script` elements */}
        <Style nonce={c.get('secureHeadersNonce')} />
      </head>
      <body>
        <h1 class={headerClass}>Hello!</h1>
      </body>
    </html>
  )
})

createCssContext Expérimental ​

createCssContext crée des fonctions utilitaires CSS (css, cx, keyframes, viewTransition, Style) avec un contexte personnalisé. Vous pouvez l’utiliser pour personnaliser l’identifiant de l’élément de style et les noms de classe générés.

ts
import { createCssContext } from 'hono/css'

const { css, cx, keyframes, Style } = createCssContext({
  id: 'my-app',
})

classNameSlug ​

Par défaut, les noms de classe CSS sont générés au format css-1234567890. Vous pouvez personnaliser ce comportement en passant une fonction classNameSlug.

La fonction reçoit trois arguments :

  • hash - le nom de classe généré par défaut (par exemple css-1234567890)
  • label - extrait d’un /* comment */ au début du gabarit CSS (chaîne vide s’il n’y en a pas)
  • css - la chaîne CSS minifiée
ts
const { css, Style } = createCssContext({
  id: 'my-styles',
  classNameSlug: (hash, label) => (label ? `h-${label}` : hash),
})

const heroClass = css`
  /* hero-section */
  background: blue;
`
// Generated class name: "h-hero-section"

onInvalidSlug ​

Si la fonction classNameSlug renvoie un nom de classe CSS invalide, un avertissement est journalisé par défaut. Vous pouvez personnaliser ce comportement avec onInvalidSlug.

ts
const { css, Style } = createCssContext({
  id: 'my-styles',
  classNameSlug: (hash, label) => label || hash,
  onInvalidSlug: (slug) => {
    throw new Error(`Invalid CSS class name: ${slug}`)
  },
})

Sécurité ​

Les utilitaires CSS sont des API de création de CSS : comme dans les autres bibliothèques CSS-in-JS, les valeurs interpolées sont insérées sous forme de CSS brut. Ils empêchent de sortir du contexte CSS pour injecter du HTML (guillemets, barres obliques inverses et </), mais laissent passer {, } et ;, car ces caractères sont valides en CSS.

Attention

Traitez les utilitaires CSS comme les autres points d’insertion de contenu brut (html, raw, rawCssString) : ne leur passez pas directement des données non fiables. Cela permettrait une injection CSS. Validez d’abord ces données à l’aide d’une liste de valeurs autorisées.

tsx
const ALLOWED_COLORS = ['red', 'green', 'blue']
const color = ALLOWED_COLORS.includes(input) ? input : 'black'
const headerClass = css`
  color: ${color};
`

Conseils ​

Si vous utilisez VS Code, vous pouvez installer vscode-styled-components pour obtenir la coloration syntaxique et IntelliSense dans les littéraux balisés CSS.

Publié sous licence MIT.