样式

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

CSS 模块

Qwik 借助 Vite 的支持,原生支持 CSS 模块

要使用 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) => {
  // 数组语法示例
  return <div class={[
    styles.container, 
    'p-8', 
    props.isHighAttention ? 'text-green-500' : 'text-slate-500',
    { active: true}
  ]}>Hello world</div>;
 
  // 对象语法示例
  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 和 .sass
npm add -D sass
 
# .less
npm add -D less
 
# .styl 和 .stylus
npm add -D stylus

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

Tailwind

要在应用程序中使用 Tailwind,请使用我们内置的集成方式将其添加到应用程序中:

npm run qwik add tailwind

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

PostCSS

您还可以使用我们内置的集成方式在应用程序中使用 PostCSS:

npm run qwik add postcss

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

// 使用 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> 中。

Contributors

Thanks to all the contributors who have helped make this documentation better!

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