StyleX 备忘清单 ==== 这是 [StyleX](https://github.com/facebook/stylex) 用户界面的样式系统的快速参考指南备忘单 入门 StyleX --- ### 介绍 StyleX 是一个 CSS In JS 的用户界面的样式系统 - [StyleX Intellisense](https://marketplace.visualstudio.com/items?itemName=yash-singh.stylex) _VSCode 插件_ #### Vite - [vite-plugin-stylex](https://www.npmjs.com/package/vite-plugin-stylex) - [vite-plugin-stylex-dev](https://www.npmjs.com/package/vite-plugin-stylex-dev) #### Babel 插件 - [tailwind-to-stylex](https://www.npmjs.com/package/tailwind-to-stylex) 支持在 Tailwind CSS 中使用 - [@stylex-extend/babel-plugin](https://github.com/nonzzz/stylex-extend/tree/main/packages/babel-plugin) 使用 JSX 属性定义 StyleX #### Prettier - [prettier-plugin-stylex-key-sort](https://github.com/nedjulius/prettier-plugin-stylex-key-sort) #### Bun - [bun-plugin-stylex](https://www.npmjs.com/package/bun-plugin-stylex) #### 入门模板 - [next.js](https://github.com/nmn/nextjs-app-dir-stylex) _支持 StyleX 的 next.js 项目_ - [qwik](https://github.com/nmn/qwik-stylex) _使用 StyleX 和 tailwind-to-stylex 的 Qwik 项目_ - [docusaurus 3](https://github.com/nmn/docusaurus-stylex) _支持 StyleX 的 docusaurus 3 项目_ - [SvelteKit](https://github.com/nmn/sveltekit-stylex) _支持 StyleX 的 SvelteKit 项目_ ### 配置编译器 ```js import plg from '@stylexjs/rollup-plugin'; const config = () => ({ plugins: [ plg({ ...options }) ] }) export default config; ``` ### 使用样式 ```js import * as React from 'react'; import * as stylex from '@stylexjs/stylex'; const styles = stylex.create({ ... }); const colorStyles = stylex.create({ ... }); ``` 在 [React](./react.md) 中使用 ```jsx function ReactDemo( { color,isActive,style } ) { return (
); } ``` ### 定义样式 ```js import * as stylex from '@stylexjs/stylex'; const styles = stylex.create({ root: { width: '100%', maxWidth: 800, minHeight: 40, }, }); ``` 样式是使用对象语法和 `create()` API 定义的 安装 ---- ### StyleX 运行时包 ```bash npm install --save @stylexjs/stylex ``` ### 编译器(生产) Rollup ```bash npm install --save-dev @stylexjs/rollup-plugin ``` 修改 Rollup 配置 _rollup.config.js_ ```js import stylexPlugin from '@stylexjs/rollup-plugin'; const config = { input: './index.js', output: { file: './.build/bundle.js', format: 'es', }, // 确保在 Babel 之前使用 stylex 插件 plugins: [stylexPlugin({ // 必需项。生成的 CSS 文件的文件路径。 fileName: './.build/stylex.css', // 默认值:false dev: false, // 所有生成的类名的前缀 classNamePrefix: 'x', // CSS 变量支持所必需 unstable_moduleResolution: { // 类型:'commonJS' | 'haste' // 默认值:'commonJS' type: 'commonJS', // 项目根目录的绝对路径 rootDir: __dirname, }, })], }; export default config; ``` ### 编译器(开发) ```bash npm install --save-dev @stylexjs/babel-plugin ``` 修改 Babel 配置 _(babel.config.js)_ ```js import styleX from '@stylexjs/babel-plugin'; const config = { plugins: [ [styleX, { dev: true, // 设置为 true 以进行快照测试 // 默认值:false test: false, // CSS 变量支持所必需 unstable_moduleResolution: { // 类型:'commonJS' | 'haste' // 默认值:'commonJS' type: 'commonJS', // 项目根目录的绝对路径 rootDir: __dirname, } }], ], }; export default config; ``` ### 编译器(生产) Webpack ```bash npm install --save-dev @stylexjs/webpack-plugin ``` 修改 Webpack 配置 _webpack.config.js_ ```js const StylexPlugin = require('@stylexjs/webpack-plugin'); const path = require('path'); const config = (env, argv) => ({ entry: { main: './src/index.js', }, output: { path: path.resolve(__dirname, '.build'), filename: '[name].js', }, module: { rules: [ { test: /\.js$/, exclude: /node_modules/, use: 'babel-loader', }, ], }, plugins: [ // 确保在 Babel 之前使用 stylex 插件 new StylexPlugin({ filename: 'styles.[contenthash].css', // 获取 webpack 的模式并为开发设置值 dev: argv.mode === 'development', // 使用静态生成的 CSS 文件,而不是运行时注入的 CSS。 // 即使在开发环境中也是如此。 runtimeInjection: false, // 可选的。默认值:'x' classNamePrefix: 'x', // CSS 变量支持所必需 unstable_moduleResolution: { // 类型:'commonJS' | 'haste' // 默认值:'commonJS' type: 'commonJS', // 项目根目录的绝对路径 rootDir: __dirname, }, }), ], cache: true, }); module.exports = config; ``` ### 编译器(生产) Next.js ```bash npm install --save-dev @stylexjs/nextjs-plugin \ @stylexjs/babel-plugin rimraf ``` 在 `package.json` 添加配置 ```js { "scripts": { ..., "predev": "rimraf .next", "prebuild": "rimraf .next" } } ``` 修改 Babel 配置 _.babelrc.js_ ```js module.exports = { presets: ["next/babel"], plugins: [ [ "@stylexjs/babel-plugin", { dev: process.env.NODE_ENV === "development", test: process.env.NODE_ENV === "test", runtimeInjection: false, genConditionalClasses: true, treeshakeCompensation: true, unstable_moduleResolution: { type: "commonJS", rootDir: __dirname, }, }, ], ], }; ``` 修改 Next.js 配置 _next.config.mjs_ ```js /** @type {import('next').NextConfig} */ import stylexPlugin from "@stylexjs/nextjs-plugin"; const nextConfig = {}; const __dirname = new URL(".", import.meta.url).pathname; export default stylexPlugin({ rootDir: __dirname, })(nextConfig); ``` ### 仅限本地开发 要开始使用 `StyleX` 而无需配置编译器和构建过程,您可以安装本地开发运行时 ```bash npm install --save-dev @stylexjs/dev-runtime ``` 开发运行时必须导入到应用程序的 `JavaScript` 入口点并进行配置 ```js import inject from '@stylexjs/dev-runtime'; inject({ classNamePrefix: 'x', dev: true, test: false, }); ``` ### 用 ESLint 捕捉错误 ```bash npm install --save-dev @stylexjs/eslint-plugin ``` StyleX 编译器不会验证您的样式,并且会编译许多无效样式。当您创作样式时,您应该使用 ESLint 插件来捕获这些错误。修改 ESLint 配置 `.eslintrc.js` ```js module.exports = { plugins: ["@stylexjs"], rules: { "@stylexjs/valid-styles": "error", }, }; ``` 定义样式 ---- ### 创建样式 ```js import * as stylex from '@stylexjs/stylex'; const styles = stylex.create({ base: { fontSize: 16, lineHeight: 1.5, color: 'rgb(60,60,60)', }, highlighted: { color: 'rebeccapurple', }, }); ``` ### 伪类 ```js import * as stylex from '@stylexjs/stylex'; const styles = stylex.create({ button: { backgroundColor: 'lightblue', }, }); ``` 样式名为 `button` 的背景样式上添加 `:hover` 和 `:active` 伪类 ```js import * as stylex from '@stylexjs/stylex'; const styles = stylex.create({ button: { backgroundColor: { default: 'lightblue', ':hover': 'blue', ':active': 'darkblue', }, }, }); ``` ### 伪元素 ```js import * as stylex from '@stylexjs/stylex'; const styles = stylex.create({ input: { // 伪元素 '::placeholder': { color: '#999', }, color: { default: '#333', // 伪类 ':invalid': 'red', }, }, }); ``` ### 媒体查询(和其他@规则) ```js import * as stylex from '@stylexjs/stylex'; const styles = stylex.create({ base: { width: { default: 800, '@media (max-width: 800px)': '100%', '@media (min-width: 1540px)': 1366, }, }, }); ``` 同样,媒体查询也可以作为样式值中的 "条件" ### 组合条件 ```js import * as stylex from '@stylexjs/stylex'; const styles = stylex.create({ button: { color: { default: 'var(--blue-link)', ':hover': { default: null, '@media (hover: hover)': 'scale(1.1)', }, ':active': 'scale(0.9)', }, }, }); ``` 当您需要组合媒体查询和伪选择器时,嵌套超过`一层` ### 后备样式 ```css .header { position: fixed; position: -webkit-sticky; position: sticky; } ``` 使用 `firstThatWorks` 函数来实现相同的目的 ```js import * as stylex from '@stylexjs/stylex'; const styles = stylex.create({ header: { position: stylex.firstThatWorks('sticky', '-webkit-sticky', 'fixed'), }, }); ``` ### 关键帧动画 ```js import * as stylex from '@stylexjs/stylex'; const fadeIn = stylex.keyframes({ from: {opacity: 0}, to: {opacity: 1}, }); const styles = stylex.create({ base: { animationName: fadeIn, animationDuration: '1s', }, }); ``` 使用 `stylex.keyframes()` 函数来定义关键帧动画 ### 动态样式 ```js import * as stylex from '@stylexjs/stylex'; const styles = stylex.create({ // 函数参数必须是简单标识符 // -- 不允许解构或默认值 bar: (height) => ({ height, // 函数体必须是对象字面量 // -- 不允许使用 { return {} } }), }); function MyComponent() { // `height` 的值在编译时不能确定。 const [height, setHeight] = useState(10); return
; } ``` 注意:动态样式是一项高级功能,应谨慎使用。对于大多数用例,条件样式应该足够了。 使用样式 ---- ### 合并样式 ```jsx import * as stylex from '@stylexjs/stylex'; const styles = stylex.create({ base: { fontSize: 16, lineHeight: 1.5, color: 'grey', }, highlighted: { color: 'rebeccapurple', }, });
; ``` 如果样式的顺序颠倒,文本将为灰色 ```jsx
``` ### 条件样式 ```jsx
``` 通过使用常见的 JavaScript 模式(例如三元表达式和 `&&` 运算符),可以在运行时有条件地应用样式。 `stylex.props` 忽略虚假值,例如 `null`、`undefined` 或 `false` ### 样式变体 ```js import * as stylex from '@stylexjs/stylex'; const styles = stylex.create({ violet: { backgroundColor: { default: 'blueviolet', ':hover': 'darkviolet', }, color: 'white', }, gray: { backgroundColor: { default: 'gainsboro', ':hover': 'lightgray', }, }, // ... more variants here ... }); ``` 然后,通过使用 `variant` 属性作为样式对象上的键来应用适当的样式 ```jsx function Button({variant, ...props}) { return (