样式

Qwik 不强制使用特定的样式方法,您可以使用任何您喜欢的方法来为您的 Qwik 应用程序设置样式,例如 CSS、CSS-in-JS、CSS 模块...

CSS 模块

Qwik 通过 CSS 模块 开箱即用地支持 Vite.

要使用 CSS 模块,只需创建一个 .module.css 文件。例如,MyComponent.module.css 并将其导入您的组件中。

src/components/MyComponent/MyComponent.module.css
.container {
  background-color: red;
}

然后,在您的组件中导入 CSS 模块。

src/components/MyComponent/MyComponent.tsx
import { component$ } from '@builder.io/qwik';
import styles from './MyComponent.module.css';
 
export default component$(() => {
  return <div class={styles.container}>Hello world</div>;
});

请记住,Qwik 使用 class 而不是 className 来表示 CSS 类。

Qwik 还接受数组、对象或它们的组合来分配多个类

src/components/MyComponent/MyComponent.tsx
import { component$ } from '@builder.io/qwik';
import styles from './MyComponent.module.css';
 
export default component$((props) => {
  // Array syntax example
  return <div class={[
    styles.container, 
    'p-8', 
    props.isHighAttention ? 'text-green-500' : 'text-slate-500',
    { active: true}
  ]}>Hello world</div>;
 
  // Object syntax example
  return <div class={{  
    'text-green-500': props.isHighAttention,
    'p-4': true
  }}>Hello world</div>;
});

全局样式

许多应用程序使用全局样式表来重置浏览器并定义全局样式。这是一个好习惯,但不建议将其用于为组件设置样式。Qwik 经过优化,可以使浏览器仅下载当前视图所需的样式。如果您使用全局样式表,则所有样式都将在首次加载时下载,即使它们不是当前视图所需的样式。

import './global.css';

Qwik 会自动尝试在生产模式下内联此文件,如果 CSS 的数量小于 10KB。如果文件大于 10KB,它将作为单独的文件加载。

CSS-in-JS

Qwik 使用 styled-vanilla-extract 提供一流的 CSS-in-JS 支持,它提供了一个非常高效的 css-in-js 解决方案,没有任何运行时!

style.css.ts
import { style } from 'styled-vanilla-extract/qwik';
 
export const blueClass = style({
  display: 'block',
  width: '100%',
  height: '500px',
  background: 'blue',
});
component.tsx
import { component$ } from '@builder.io/qwik';
import { blueClass } from './styles.css';
 
export const Cmp = component$(() => {
  return <div class={blueClass} />;
});
npm run qwik add styled-vanilla-extract

有关更多信息,请参阅 我们官方集成的文档

那么 emotion 或其他 CSS-in-JS 库呢? 虽然非常流行,但 emotion 和其他 CSS-in-JS 库不是 Qwik 的最佳选择。 它们没有针对运行时性能进行优化,并且没有良好的 SSR 流式支持,导致服务器和客户端性能下降。

Styled-components

styled-components 库是 React 世界中用于编写 CSS-in-JS 的流行工具。得益于相同的 styled-vanilla-extract 插件,您可以在 Qwik 中使用 styled-components 语法编写样式,而无需任何运行时成本!

npm run qwik add styled-vanilla-extract

像这样

styles.css.ts
import { styled } from 'styled-vanilla-extract/qwik';
 
export const BlueBox = styled.div`
  display: block;
  width: 100%;
  height: 500px;
  background: blue;
`;
component.tsx
import { component$ } from '@builder.io/qwik';
import { BlueBox } from './styles.css';
 
export const Cmp = component$(() => {
  return <BlueBox />;
});

作用域 CSS

要使用作用域 CSS,您可以使用从 @builder.io/qwik 导出的 useStylesScoped$() 钩子。

src/components/MyComponent/MyComponent.tsx
import { component$, useStylesScoped$ } from '@builder.io/qwik';
 
export default component$(() => {
  useStylesScoped$(`
    .container {
      background-color: red;
    }
  `);
  return <div class="container">Hello world</div>;
});

您也可以导入外部 CSS 文件。为此,您需要在导入 CSS 文件时添加 ?inline 查询参数,并将 CSS 文件的默认导出传递给 useStyleScoped$() 钩子。

src/components/MyComponent/MyComponent.css
.container {
  background-color: red;
}
src/components/MyComponent/MyComponent.tsx
import { component$, useStylesScoped$ } from '@builder.io/qwik';
 
import styles from './MyComponent.css?inline';
 
export default component$(() => {
  useStylesScoped$(styles);
  return <div class="container">Hello world</div>;
});

:global() 选择器

使用 useStylesScoped$ 将使规则集中所有子选择器作用域到组件。如果您需要通过 <Slot /> 渲染的子组件设置样式,则需要使用 :global() 选择器跳出作用域样式。

import { useStylesScoped$, component$ } from '@builder.io/qwik';
 
export const List = component$(() => {
  useStylesScoped$(`
    .list {
      display: flex;
 
      > :global(*nth-child(3)) {
        width: 100%
      }
    }
  `);
 
  return (
    <div class="list">
      <Slot />
    </div>;
  );
});

这将渲染一个 .list.⭐️8vzca0-0 > *:nth-child(3) 的 css 选择器,允许您定位子组件。这可以被认为等同于在 Angular 中使用 ::ng-deep

请注意,这可能会对您的组件树级联产生意想不到的影响。

useStyles$()

对组件样式的延迟加载引用。

组件样式允许 Qwik 仅在需要时延迟加载组件的样式信息,这避免了 SSR 水合期间的双重加载。

import { useStyles$, component$ } from '@builder.io/qwik';
import styles from './code-block.css?inline';
 
export const CmpStyles = component$(() => {
  useStyles$(styles);
  return <span class="my-text">Some text</span>;
});
// code-block.css
.my-text {
  color: red;
}

请注意,为了在 Vite 中将 CSS 作为字符串导入,您需要在导入时添加 ?inline 查询参数,如下所示:import styles from './code-block.css?inline';

CSS 预处理器

得益于 Vite,Qwik 支持 Sass、Less、Stylus 和 PostCSS 等 CSS 预处理器。

无需为它们安装特定于 Qwik 的插件,但必须安装相应的预处理器本身

# .scss and .sass
npm add -D sass
 
# .less
npm add -D less
 
# .styl and .stylus
npm add -D stylus

有关更多信息,请查看 Vite 的文档

Tailwind

要在您的应用程序中使用 Tailwind,您可以使用我们的内置集成将其添加到您的应用程序中

npm run qwik add tailwind

有关更多信息,请查看 集成文档

PostCSS

也可以使用我们的内置集成在您的应用程序中使用 PostCSS

npm run qwik add postcss

重要提示:由于我们使用的是 vite,因此配置应如下所示才能正常工作

// Configuration with vite
module.exports = {
  plugins: {
    autoprefixer: {},
    "postcss-preset-env": {
      stage: 3,
      features: {
        "nesting-rules": true,
      },
    },
  },
}

现在您将能够使用具有嵌套规则的 CSS,例如以下规则

body {
  & .box {
    background: red;
 
    &:hover {
      background: yellow;
    }
  }
}

有关更多信息,请查看 集成文档

为什么不使用 <style> 标签内联样式?

确保组件加载正确样式的一种简单方法是将样式信息内联到组件中,如下所示。

export const MyComponent = () => {
  return (
    <>
      <style>.my-class { color: red; }</style>
      My Component
    </>
  );
}

这种方法的问题是我们会加载两次样式。

  1. 样式作为 SSR 的一部分被插入到 HTML 中。
  2. 然后,当组件失效并需要重新渲染时,样式会再次加载,因为它们是内联的。

需要的是独立于组件加载样式。这就是 useStyles$() 的作用。有两种情况

  1. 组件在服务器上渲染,样式作为 SSR 的一部分被插入到 <head> 中。
    • 向应用程序添加新的组件实例不需要我们加载样式,因为它们已经作为 SSR 的一部分包含在内。
  2. 组件第一次在客户端上渲染。在这种情况下,新组件在 <head> 中没有样式,因为组件不是 SSR 的一部分。
    • 添加一个不是 SSR 部分的新组件需要加载样式并将其插入到 <head> 中。

贡献者

感谢所有帮助改进本文档的贡献者!

  • manucorporat
  • zanettin
  • cunzaizhuyi
  • manuelsanchez2
  • literalpie
  • forresst
  • DustinJSilk
  • saikatdas0790
  • LiKang6688
  • Craiqser
  • adamdbradley
  • the-r3aper7
  • mhevery
  • igorbabko
  • mrhoodz
  • tanftw