样式契约
每个公开的组成部分都直接接收className、style、ref、事件处理函数、原生props和data-*属性。不提供contentClassName或triggerClassName这类并行props。
uiify管理身份与状态属性。这些属性是样式钩子:应通过props或原生HTML行为改变状态,切勿直接写入data-state。--uiify-*命名空间保留给几何信息、动画和实例值。
<Popover.Root>
<Popover.Trigger className="toolbar-trigger">Open</Popover.Trigger>
<Popover.Content className="toolbar-popover" data-layout="compact">
Actions
</Popover.Content>
</Popover.Root>命名
| 钩子 | 用途 | 示例 |
|---|---|---|
| 身份标记 | 稳定的组件身份,由uiify管理 | data-uiify-popover |
| 结构标记 | 公开的复合组成部分,由uiify管理 | data-part="content" |
| 状态属性 | 供选择器读取的只读状态镜像 | data-state="open" |
| 自定义属性 | 动态几何信息和实例值 | --uiify-anchor-x |
每个承载状态的根元素都有一个以是否存在表示值的data-uiify-<component>标记。每个复合组成部分都有一个kebab-case形式的data-part值,例如trigger、content、item或label。使用方的props不能覆盖这些值。
纯CSS与Tailwind
[data-uiify-popover][data-part="content"] {
min-inline-size: 12rem;
}
[data-uiify-popover][data-part="content"][data-state="open"] {
opacity: 1;
}
/* Tailwind uses the same attributes. */
<div className="data-[state=open]:opacity-100" />多态
as和render可替换渲染的元素。自定义渲染器必须将收到的props和ref转发给DOM元素,否则标记、状态和样式将失效。
behavior.css不可缺少
该样式表包含使状态正常工作的规则:弹出层定位、::details-content尺寸、:has()传播、隐藏输入框定位和@starting-style过渡。不包含颜色、字体或间距。
import "@gunkin/uiify/components/behavior.css";缺少它时,组件能渲染,但状态无法正常工作。在应用任意位置导入一次即可。
用属性表达状态,而非类名
组件在承载状态的元素上通过data-*属性暴露状态,让CSS无须JavaScript或类名就能选中相应元素。每个组件页面都列出了它输出的属性。
.my-trigger[data-state="open"] { … }
.my-item[data-disabled] { … }
/* Native state works the same way, because the state IS native */
.my-panel:popover-open { … }
details[open] > summary { … }变体也使用data-*属性,而非容器样式查询,因为容器不能查询自身。
值写在内联样式中,规则写在样式表中
实例值通过内联自定义属性传入,所有规则则放在静态样式表中。内联样式无法表达伪类、伪元素、容器查询或@starting-style,而状态模型需要这些能力。
内联属性随HTML流式传输,不会导致水合不匹配;一张样式表只需解析一次,之后即可缓存。CSS-in-JS则在每个边界中注入<style>片段,无法跨请求缓存。
三种样式方案
自有CSS。通过元素及其data-*属性选择目标;没有需要覆盖的默认样式。
Tailwind。相同属性也可作为变体,例如data-[state=open]:rotate-180。在页头的“样式”设置中,可将网站预览切换为Tailwind皮肤。
@gunkin/uiify/styles。可选的纯CSS层,提供OKLCH令牌色阶、明暗主题和每个组件的皮肤,可作为起点,并非必需。
import "@gunkin/uiify/styles/reset";
import "@gunkin/uiify/styles";层叠顺序
uiify提供的所有样式都位于低于应用层的命名层中:
@layer ui.reset, ui.behavior, ui.tokens, ui.theme, app;应用层始终优先:覆盖样式无须!important或选择器优先级技巧,库重构后也仍然有效。
每个组件页面都列出属性和CSS变量,并提供两种皮肤可直接复制使用的CSS。