Lzh on GitHub

样式

Reka UI 是无样式的,并且与任何样式解决方案兼容,让您完全控制样式。

样式概述

功能样式

您可以控制样式的所有方面,包括功能样式。例如,默认情况下,Dialog Overlay 不会覆盖整个视口。您需要负责添加这些样式以及任何呈现样式。

所有组件都接受 class 属性,就像普通组件一样。此 class 将传递到 DOM 元素。您可以像预期一样在 CSS 中使用它。

传送元素

某些元素(例如模态框或弹出框)会传送到 body。当使用作用域样式应用 CSS 时,您需要使用 深层选择器 来定位它们。

数据属性

当组件是有状态时,它们的状态将通过 data-state 属性暴露。例如,当 Accordion Item 打开时,它会包含 data-state="open" 属性。

使用 CSS 样式

样式化部件

您可以通过定位提供的 class 来样式化组件部件。

<script setup lang="ts">
import { AccordionRoot, AccordionItem, ... } from "reka-ui";
</script>

<template>
  <AccordionRoot>
    <AccordionItem class="AccordionItem" value="item-1" />
    <!-- ... -->
    </AccordionRoot>
</template>

<style>
.AccordionItem {
  /* ... */
}
</style>

样式化状态

您可以通过定位组件的 data-state 属性来样式化组件状态。

.AccordionItem {
  border-bottom: 1px solid gainsboro;
}

.AccordionItem[data-state="open"] {
  border-bottom-width: 2px;
}

作用域样式

您可以使用作用域样式来样式化组件。请注意传送的元素,因为它们需要使用 深层选择器 才能被定位。

<script setup lang="ts">
import { DropdownMenuRoot, DropdownMenuItem, ... } from "reka-ui";
</script>

<template>
  <DropdownMenuRoot>
    <!-- ... -->
    <DropdownMenuPortal>
      <DropdownMenuContent class="DropdownMenuContent">
        <DropdownMenuItem class="DropdownMenuItem">An item</DropdownMenuItem>
      </DropdownMenuContent>
    </DropdownMenuPortal>
  </DropdownMenuRoot>
</template>

<style scoped>
:deep(.DropdownMenuContent) {
  /* ... */
}

.DropdownMenuItem {
  /* ... */
}
</style>
DropdownMenuContent 需要 :deep() 是因为它很可能通过 Portal 机制渲染到了当前 Vue 组件 DOM 树之外的位置,导致它无法获得当前组件 允许你的样式选择器穿透这种组件作用域的隔离,从而能够正确地应用样式。DropdownMenuItem 则通常在被 Portal 的 DropdownMenuContent 的内部正常渲染,所以可能不需要 deep

使用 Tailwind CSS 样式

以下示例使用 Tailwind CSS,但您可以使用任何您选择的库。

样式化部件

您可以通过定位 class 来样式化组件部件。

<script setup lang="ts">
import { AccordionRoot, AccordionItem, ... } from "reka-ui";
</script>

<template>
  <AccordionRoot>
    <AccordionItem class="border border-gray-400 rounded-2xl" value="item-1" />
    <!-- ... -->
    </AccordionRoot>
</template>

样式化状态

借助 Tailwind CSS 强大的变体选择器,您可以通过定位组件的 data-state 属性来样式化组件状态。

<script setup lang="ts">
import { AccordionRoot, AccordionItem, ... } from "reka-ui";
</script>

<template>
  <AccordionRoot>
    <AccordionItem
      class="
        border border-gray-400 rounded-2xl
        data-[state=open]:border-b-2 data-[state=open]:border-gray-800
      "
      value="item-1"
    />
    <!-- ... -->
    </AccordionRoot>
</template>
Tailwind CSS 是一个原子化 CSS 框架(Utility-First CSS framework)。它的核心思想是:
  • 直接在 HTML 中应用原子类: 你不是写 CSS 规则来定义一个组件的样式,而是直接在你的 HTML 元素上添加一系列预定义的、单一用途的工具类(如 flex, pt-4, text-center, bg-blue-500)。
  • 按需生成 CSS: Tailwind JIT (Just-In-Time) 编译器或 PostCSS 插件会在构建时扫描你的代码,只生成你实际用到的那些工具类的 CSS。
  • 全局作用域: Tailwind 生成的 CSS 类(例如 .pt-4)是全局的,它们没有被限定在特定的组件或文件中。当你应用 pt-4 类时,它就是 padding-top: 1rem;,这个规则在你的整个应用中都是一样的。
在 Vue 组件中使用 Tailwind CSS 和 scoped 样式。你可以在组件中使用 Tailwind 的原子类来快速构建 UI,同时使用 <style scoped> 来编写那些 Tailwind 无法覆盖或你希望更具组件特定性的自定义 CSS 规则。

扩展原始元素

扩展原始元素与扩展任何 Vue 组件的方式相同。

<script setup lang="ts">
import { AccordionItem, type AccordionItemProps } from "reka-ui";

interface Props extends AccordionItemProps {
  foo: string;
}

defineProps<Props>();
</script>

<template>
  <AccordionItem v-bind="$props"><slot /></AccordionItem>
</template>
v-bind="$props": 这是 Vue 的一个特殊用法。$props 是一个内置的变量,它包含了当前组件接收到的所有 props
  • v-bind="$props" 被应用到一个子组件时,它会将当前组件接收到的所有 props,原封不动地传递给子组件。
  • 这意味着,AccordionItem 将接收到所有 AccordionItemProps 中定义的 props,以及你自定义的 foo prop(尽管 AccordionItem 可能不认识 foo,但它会忽略)。这种模式称为 "透传 Attributes" (Attribute Inheritance),在封装组件时非常有用,因为它减少了手动绑定每个 prop 的繁琐。

总结

Reka UI 旨在封装可访问性问题和其他复杂功能,同时确保您完全控制样式。

为方便起见,有状态组件包含 data-state 属性。