Skip to content

css 助手

🌐 css Helper

CSS 助手 - hono/css - 是 Hono 内置的 CSS in JS(X)。

🌐 The CSS helper - hono/css - is Hono's built-in CSS in JS(X).

你可以在名为 css 的 JavaScript 模板字面量中编写 JSX 的 CSS。css 的返回值将是类名,并设置为 class 属性的值。<Style /> 组件随后将包含 CSS 的值。

🌐 You can write CSS in JSX in a JavaScript template literal named css. The return value of css will be the class name, which is set to the value of the class attribute. The <Style /> component will then contain the value of the CSS.

导入

🌐 Import

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

css Experimental

你可以在 css 模板字符串中编写 CSS。在这种情况下,它使用 headerClass 作为 class 属性的值。别忘了添加 <Style />,因为它包含 CSS 内容。

🌐 You can write CSS in the css template literal. In this case, it uses headerClass as a value of the class attribute. Don't forget to add <Style /> as it contains the CSS content.

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>
  )
})

你可以使用 嵌套选择器 来为 :hover 伪类设置样式,方法如下,&

🌐 You can style pseudo-classes like :hover by using the nesting selector, &:

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

扩展

🌐 Extending

你可以通过嵌入类名来扩展 CSS 定义。

🌐 You can extend the CSS definition by embedding the class name.

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

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

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

此外,${baseClass} {} 的语法支持类的嵌套。

🌐 In addition, the syntax of ${baseClass} {} enables nesting 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>
)

全局样式

🌐 Global styles

一个叫做 :-hono-global 的伪选择器允许你定义全局样式。

🌐 A pseudo-selector called :-hono-global allows you to define global styles.

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>
)

或者你可以在 <Style /> 组件中使用 css 字面量编写 CSS。

🌐 Or you can write CSS in the <Style /> component with the css literal.

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 Experimental

你可以使用 keyframes 来编写 @keyframes 的内容。在这种情况下,fadeInAnimation 将是动画的名称。

🌐 You can use keyframes to write the contents of @keyframes. In this case, fadeInAnimation will be the name of the 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 Experimental

cx 组合了这两个类名。

🌐 The cx composites the two class names.

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

它还可以编写简单的字符串。

🌐 It can also compose simple strings.

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

Secure Headers 中间件结合使用

🌐 Usage in combination with Secure Headers middleware

如果你想将 CSS 辅助工具与 Secure Headers 中间件结合使用,你可以将 nonce 属性 添加到 <Style nonce={c.get('secureHeadersNonce')} /> 上,以避免 CSS 辅助工具引起的内容安全策略问题。

🌐 If you want to use the CSS helpers in combination with the Secure Headers middleware, you can add the nonce attribute to the <Style nonce={c.get('secureHeadersNonce')} /> to avoid Content-Security-Policy caused by the CSS helpers.

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 Experimental

createCssContext 使用自定义上下文创建 CSS 辅助函数(csscxkeyframesviewTransitionStyle)。你可以使用它自定义样式元素 ID 和生成的类名。

ts
import { createCssContext } from 'hono/css'

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

classNameSlug

默认情况下,CSS 类名会以 css-1234567890 格式生成。你可以通过传入 classNameSlug 函数来自定义它。

🌐 By default, CSS class names are generated in the format css-1234567890. You can customize this by passing a classNameSlug function.

该函数接收三个参数:

🌐 The function receives three arguments:

  • hash - 默认生成的类名(例如 css-1234567890
  • label - 从 CSS 模板开头的 /* comment */ 中提取(如果没有,则为空字符串)
  • css - 压缩后的 CSS 字符串
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

如果 classNameSlug 函数返回无效的 CSS 类名,默认情况下会记录警告。你可以通过 onInvalidSlug 自定义此行为。

🌐 If the classNameSlug function returns an invalid CSS class name, a warning is logged by default. You can customize this behavior with onInvalidSlug.

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

安全

🌐 Security

CSS 辅助工具是 CSS 编写 API:像其他 CSS-in-JS 库一样,插值的值会作为 原始 CSS 插入。它们会阻止破坏 HTML(引号、反斜杠和 </),但是 {}; 可以通过,因为它们是有效的 CSS。

🌐 The CSS helpers are CSS-authoring APIs: like other CSS-in-JS libraries, interpolated values are inserted as raw CSS. They block breaking out into HTML (quotes, backslashes, and </), but {, }, and ; pass through since they are valid CSS.

WARNING

像对待其他原始接收器(htmlrawrawCssString)一样处理 CSS 辅助工具:不要直接将不可信的输入传递给它们。 这样做会导致 CSS 注入。首先应对其进行允许列表验证。

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

提示

🌐 Tips

如果你使用 VS Code,你可以使用 vscode-styled-components 为 CSS 标签字面量提供语法高亮和智能感知。

🌐 If you use VS Code, you can use vscode-styled-components for Syntax highlighting and IntelliSense for CSS tagged literals.

Hono 中文网 - 粤ICP备13048890号