Skip to content

CSS工具类

css 工具类 - hono/css - 是 Hono 内置的 CSS in JS(X) 解决方案。

你可以在 JSX 中使用名为 css 的 JavaScript 模板字面量来编写 CSS。css 的返回值将是类名,用于设置 class 属性的值。<Style /> 组件则包含 CSS 的具体内容。

导入

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

css 实验性

你可以在 css 模板字面量中编写 CSS。在这个例子中,headerClass 被用作 class 属性的值。别忘了添加 <Style /> 组件,因为它包含了 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>
  )
})

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

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

样式继承

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

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

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

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

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

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

全局样式

伪选择器 :-hono-global 允许你定义全局样式。

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。

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 实验性

你可以使用 keyframes 来编写 @keyframes 的内容。在这个例子中,fadeInAnimation 将作为动画的名称。

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 实验性

cx 用于组合多个类名。

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

它也可以组合普通的字符串。

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

Secure Headers 中间件配合使用

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

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

app.get(
  '*',
  secureHeaders({
    contentSecurityPolicy: {
      // 在 `styleSrc` 中设置预定义的 nonce 值:
      styleSrc: [NONCE],
    },
  })
)

app.get('/', (c) => {
  const headerClass = css`
    background-color: orange;
    color: white;
    padding: 1rem;
  `
  return c.html(
    <html>
      <head>
        {/* 在 css 辅助工具的 `style` 和 `script` 元素上设置 `nonce` 属性 */}
        <Style nonce={c.get('secureHeadersNonce')} />
      </head>
      <body>
        <h1 class={headerClass}>Hello!</h1>
      </body>
    </html>
  )
})

使用技巧

如果你使用 VS Code,可以安装 vscode-styled-components 插件,以获得 css 标签字面量的语法高亮和智能提示功能。

VS Code

Released under the MIT License.