前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Panda CSS 确实很适合用来写UI库(CSS-in-JS)

Panda CSS 确实很适合用来写UI库(CSS-in-JS)

作者头像
HoMeTown
发布2023-08-23 11:00:05
8020
发布2023-08-23 11:00:05
举报
文章被收录于专栏:秃头开发头秃了

哈喽艾瑞巴蒂,我是努力在写优秀技术爽文的 HoMeTown。

Chakra UI 最近发布了一个新的CSS框架,PandaCSS。

在Github扒了一下作者发现 PandaCSS 其实在2023 年 3 月 Segun Adebayo 发布的《Chakra UI的未来》 一文中有提到过,只不过最近才正式发布。

PandaCSS的特点

来自 Github README:

  • Write style objects or style props, extract them at build time / 为 Style 定义对象和 props 并在构建中提取它们
  • ✨ Modern CSS output — cascade layers @layer, css variables and more / 现代 CSS 输出 — 级联层 @layer、css 变量等
  • 🦄 Works with most JavaScript frameworks / 适用于大多数JavaScript框架
  • 🚀 Recipes and Variants - Just like Stitches™️ ✨ / 专题和变体
  • 🎨 High-level design tokens support for simultaneous themes / 支持同步主题
  • 💪 Type-safe styles and autocomplete (via codegen) / 类型安全样式和自动完成(通过codegen)

文档中提到的支持的框架有:

  • Next.js
  • Solid
  • Vite
  • Svelte
  • Remix
  • Vue
  • ...

试试

文档的入门其实也写的比较详细了,这里简单尝试一下基于Vite + React的项目:

代码语言:javascript
复制


mkdir ./pandacss-react && cd ./pandacss-react

pnpm create vite . --template react-ts

pnpm install

安装 panda,使用panda init 可以生成配置文件:

代码语言:javascript
复制


pnpm install -D @pandacss/dev

pnpm panda init --postcss

这里需要注意的是,node版本不能过低,我首次init时的node版本为14.x,报错||=的语法错误,升级为最新长期支持稳定版v18.16.1后,就没问题了。

package.json中添加命令,构建panda

代码语言:javascript
复制

json
{
  "scripts": {
    "prepare": "panda codegen",
    ...
  }
}

修改src/index.css

代码语言:javascript
复制

css
@layer reset, base, tokens, recipes, utilities;

组件中使用:

main.tsx

代码语言:javascript
复制

ts
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App.tsx";
import "./index.css";

ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

App.tsx

代码语言:javascript
复制

ts
import { css } from "../styled-system/css";

function App() {
  return (
    <div className={css({ fontSize: "2xl", fontWeight: "bold" })}>
      Hello 🐼!
    </div>
  );
}

export default App;

styled-system/css 目录是用 panda 构建的结果。运行一次构建,然后启动 Vite。

代码语言:javascript
复制


pnpm panda codegen
pnpm dev

启动页面如下:

非常简单。

Cascade Layers/@layer 级联层

Panda CSS 使用Cascade Layers来控制CSS优先级,所以就意味着当前浏览器必须支持Cascade Layers,根据 MDN,浏览器需要以下版本:

层数固定为以下五层:

  • reset 重置CSS
  • base 全局CSS
  • tokens 设计令牌的CSS变量
  • recipes 类似一种封装
  • utilities 单独定义的CSS

图层的优先级顺序是@layer在index.css等css中定义的,所以你可以根据需要更改级联层顺序。

css()

使用 PandaCSS 时写 CSS 最简单的方法是通过css()函数并在对象中写css属性。而且类型安全。

代码语言:javascript
复制

tsx
<div>
  <div className={css({ color: "red" })}>red</div>
  <div className={css({ fontWeight: "bold" })}>bold</div>
  <div className={css({ color: "red", fontWeight: "bold" })}>red bold</div>
</div>

生成的CSS如下:

代码语言:javascript
复制

css
@layer utilities {
  .text_red {
    color: red;
  }
  .font_bold {
    font-weight: var(--font-weights-bold);
  }
}

可以看到生成的CSS内容会进行去重的处理。

event

代码语言:javascript
复制

tsx
<button className={css({ color: "red", _hover: { color: "blue" } })}>
  Button
</button>

Patterns

写CSS的时候会有一些频繁出现的布局或者样式,我们更希望这种情况能以模块的形式使用从而达到复用的目的,PandaCSS提供了一些内置的方法,比如center

代码语言:javascript
复制

tsx
import { center } from "../styled-system/patterns";

function App() {
  return (
    <div
      className={center({
        bg: "gray",
        color: "white",
        inlineSize: "200px",
        blockSize: "200px",
      })}
    >
      text
    </div>
  );
}

除了center之外PandaCSS还提供了以下内置方法:

  • container 容器
  • stack 垂直或水平布局容器
  • hstack 水平布局容器
  • vstack 垂直布局容器
  • wrap 元素间距与换行
  • aspectRatio 宽高比
  • flex 弹性布局
  • float 浮动
  • grid 网格
  • gridItem 网格子元素
  • divider 分割线
  • circle 圆形
  • square 正方形

还可以自己自定义一个Pattern,参考。

Recipes

Recipes主要用来封装组件样式,比如封装一个button组件的样式:

代码语言:javascript
复制

tsx
import { cva } from "../styled-system/css";

export const button = cva({
  base: {
    display: "flex",
    borderWidth: "1px",
    borderColor: "gray",
  },
  variants: {
    type: {
      default: { color: "gray" },
      danger: { color: "red", borderColor: "red" },
    },
    size: {
      small: { padding: "8px", fontSize: "12px" },
      large: { padding: "16px", fontSize: "16px" },
    },
  },
  defaultVariants: {
    type: "default",
    size: "small",
  },
});

组件定义了两种类型defaultdanger,两种大小smalllarge。如果没有指定值,默认被设置为defaultsmall,并且在写代码的时候也会有提示:

组件中使用:

代码语言:javascript
复制

tsx
import { hstack } from "../styled-system/patterns";
import { button } from "./button.css";

function App() {
  return (
    <>
      <div className={hstack({ gap: "8px", padding: "16px" })}>
        <button className={button({ size: "small", type: "default" })}>
          Button
        </button>
        <button className={button({ size: "large", type: "default" })}>
          Button
        </button>
        <button className={button({ size: "small", type: "danger" })}>
          Button
        </button>
        <button className={button({ size: "large", type: "danger" })}>
          Button
        </button>
        <button className={button()}>Button</button>
      </div>
    </>
  );
}

这仅仅是样式的封装,如果想要封装成组件,并将这些属性作为props使用的话,可以利用RecipeVariantProps提取类型:

Button.tsx

代码语言:javascript
复制

tsx
import { ReactNode } from "react";
import { RecipeVariantProps } from "../styled-system/css";
import { button } from "./button.css";

type Props = {
  children: ReactNode;
} & RecipeVariantProps<typeof button>;

export const Button = ({ children, ...recipeVariantProps }: Props) => {
  <button className={button(recipeVariantProps)}>{children}</button>;
};

使用:

代码语言:javascript
复制

tsx
import { Button } from "./Button";

function App() {
  return (
    <Button size="small" type="default">
      Button
    </Button>
  );
}

这里很好的一个点是,我们通过这种方式,可以把样式props和其他的props隔离开。

JSX Style Props

上面的方式都是通过className然后使用Panda生成的类来设计样式,类似unocss、tailwindcss这些css框架,除此之外,这些类在Panda中还可以作为一个JSX属性来使用。

首先,需要在panda.config.ts中指定对应的框架:

代码语言:javascript
复制

ts
export default defineConfig({
  ...
  jsxFramework: 'react'
})

然后通过引入styled,使用styled.xxx创建JSX元素:

代码语言:javascript
复制

tsx
import { VStack, styled } from "../styled-system/jsx";

function App() {
  return (
    <VStack gap="8px">
      <styled.a href="https://example.com" color="red">
        Link
      </styled.a>
      <styled.button type="button" color="blue">
        Button
      </styled.button>
    </VStack>
  );
}

export default App;

可以看到styled.a处理<a>标签的同时,也可以处理样式。

我个人还是更偏好于className的方式。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-08-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 秃头开发头秃了 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • PandaCSS的特点
  • 试试
  • Cascade Layers/@layer 级联层
  • css()
  • event
  • Patterns
  • Recipes
  • JSX Style Props
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档