Appearance
UI className 样式 AI 速查
本文档用于 AI 给动态 UI 的 Div、P、Group 或少量表单组件追加 className。目标是让界面更清晰,而不是把页面写成复杂前端项目。
基础规则
className 是追加 CSS/Tailwind 类名的字符串:
lua
local tip = {
P = {
text = "请先填写参数,再保存配置。",
className = "text-sm text-default-500",
layout = { span = 12 },
}
}AI 生成规则:
- 优先用于
Div、P这种展示/布局组件。 - 不要把
className当作业务参数,它不会进入UICurrentValue。 - 不要依赖复杂定位类,例如
fixed、absolute、top-*、left-*,除非用户明确要求。 - 不要使用硬编码颜色,例如
text-red-500、bg-blue-900。优先使用主题类:text-default-500、bg-default-50、border-default-200。 - 不要为了布局只堆
className。组件排列优先使用Group.direction、Group.columns、layout.span。
哪些组件支持 className
当前动态 UI 前端会把组件配置里的 className 透传给实际组件。推荐和支持情况如下:
| 组件 | 是否支持 | 推荐程度 | 说明 |
|---|---|---|---|
Div | 支持 | 强烈推荐 | 最适合做卡片、分区、边框、背景、间距 |
P | 支持 | 强烈推荐 | 最适合控制说明文字大小、颜色、换行 |
Group | 支持 | 推荐 | 用于一组组件外层样式;排列仍优先用 direction / columns / gap |
Alert | 支持 | 可用 | 通常优先用 color、variant,必要时再加 className |
Chip | 支持 | 可用 | 通常优先用 color、variant、size |
Divider | 支持 | 可用 | 可控制外边距、宽度 |
Image | 支持 | 可用 | className 作用于图片组件,不是外层容器 |
Input | 支持 | 可用 | 简单宽度/外边距可以用;复杂内部样式用 classNames 更合适 |
NumberInput | 支持 | 可用 | 同 Input |
Slider | 支持 | 可用 | 通常优先用 color、size、showTooltip |
Select | 支持 | 可用 | 通常优先用 variant、color、size |
Autocomplete | 支持 | 可用 | 同 Select |
Checkbox | 支持 | 可用 | 通常只做外层间距 |
Switch | 支持 | 可用 | 通常只做外层间距 |
CheckboxGroup | 支持 | 可用 | 排列优先用 orientation |
RadioGroup | 支持 | 可用 | 排列优先用 orientation |
Tabs | 部分支持 | 谨慎 | 普通 top/bottom Tabs 支持;placement = "start" / "end" 侧边 Tabs 是自定义渲染,顶层 className 不作为主要样式入口 |
Accordion | 支持 | 可用 | 适合控制整个手风琴外层;每个 ui.createTab 面板项也可加 className |
AI 推荐:
- 做布局和装饰时,优先给
Div、P、Group加className。 - 表单组件不要大量堆样式类,优先用组件自身属性:
variant、color、size、radius、isDisabled。 - 容器组件
Tabs、Accordion更适合用自身属性控制,例如variant、color、placement、selectionMode。
className 与 classNames
className 是整体样式,最简单,适合小白和 AI 默认使用:
lua
nameInput.Input.className = "w-full"部分 HeroUI 组件也支持 classNames,用于改内部插槽。AI 不要默认生成复杂 classNames,除非用户明确要求细调内部结构。
示例:普通 Tabs 可以使用 classNames:
lua
local tabs = ui.createTabs({
ui.createTab("参数", {
{ ui.createInput("name", "名称", "请输入", "") }
})
})
tabs.Tabs.className = "w-full"
tabs.Tabs.classNames = {
tabList = "flex-wrap",
panel = "w-full min-w-0",
}注意:placement = "start" 或 "end" 的侧边 Tabs 当前使用自定义侧边栏渲染,优先用 Tabs 的 placement、variant、color 控制,不要依赖 className 精细控制侧边栏内部按钮。
常用文字样式
| className | 用途 |
|---|---|
text-xs | 很小的辅助文字 |
text-sm | 说明文字 |
text-base | 普通正文 |
text-lg font-semibold | 小标题 |
font-medium | 轻强调 |
font-semibold | 标题强调 |
text-default-400 | 弱说明文字 |
text-default-500 | 普通说明文字 |
text-default-700 | 较明显文字 |
text-primary | 主色强调 |
text-warning | 警告文字 |
text-danger | 错误文字 |
leading-5 | 紧凑行高 |
leading-6 | 常规行高 |
break-words | 长文本自动换行 |
whitespace-normal | 允许文本正常换行 |
示例:
lua
local desc = {
P = {
text = "这些设置会影响运行速度,请根据设备性能调整。",
className = "text-sm leading-6 text-default-500 break-words",
layout = { span = 12 },
}
}常用容器样式
| className | 用途 |
|---|---|
p-2 | 小内边距 |
p-3 | 中小内边距 |
p-4 | 常用内边距 |
px-4 py-3 | 横向大、纵向中等内边距 |
rounded-small | 小圆角,推荐默认 |
rounded-medium | 中圆角 |
border border-default-200 | 默认边框 |
bg-default-50 | 很浅的背景 |
bg-default-100 | 稍明显的背景 |
shadow-sm | 轻阴影 |
w-full | 占满宽度 |
overflow-hidden | 隐藏溢出内容 |
推荐普通分组卡片:
lua
local card = {
Div = {
className = "rounded-small border border-default-200 bg-default-50 p-4",
item = {
{ nameInput, countInput },
{ speedSlider },
},
layout = { span = 12 },
}
}大小屏幕适配规则
动态 UI 通常显示在运行页或弹窗里,宽度可能变化很大。AI 生成布局时必须优先保证小屏不溢出。
硬性要求:制作任何动态 UI 时都必须考虑大小屏幕适配。不要只按当前电脑上的宽屏效果生成布局。
核心原则:
- 默认按小屏写法生成,再用
sm:、md:、lg:增强大屏。 - 表单组件宽度优先用
layout.span、layout.sm、layout.md、layout.lg、layout.xl。 - 短输入组件优先使用
layout = { span = 6, lg = 3 },小屏最多 2 列,大屏最多 4 列。 - Slider、长说明、图片、Alert、复杂分组优先使用
layout = { span = 12 }。 - 大小屏幕的样式变化使用
className里的响应式前缀,例如md:flex-row、md:grid-cols-2。 - 长文字必须允许换行:使用
break-words whitespace-normal。 - 横向内容必须允许换行:使用
flex-wrap。 - 不要使用固定大宽度,例如
w-[800px]、min-w-[600px]。 - 不要使用
h-screen、min-h-screen撑开运行页。
常用断点:
| 前缀 | 含义 | 典型用途 |
|---|---|---|
| 无前缀 | 默认,小屏优先 | 手机、窄弹窗 |
sm: | 小屏以上 | 稍宽弹窗 |
md: | 中屏以上 | 普通桌面窗口 |
lg: | 大屏以上 | 宽屏运行页 |
响应式 className 常用写法
小屏纵向,大屏横向
lua
className = "flex flex-col gap-3 md:flex-row md:items-center"含义:
- 小屏:上下排列。
- 中屏以上:左右排列。
小屏一列,大屏两列
lua
className = "grid grid-cols-1 gap-3 md:grid-cols-2"小屏一列,中屏两列,大屏三列
lua
className = "grid grid-cols-1 gap-3 md:grid-cols-2 lg:grid-cols-3"宽度自适应容器
lua
className = "w-full max-w-full overflow-hidden"长文本不撑破容器
lua
className = "text-sm leading-6 text-default-500 break-words whitespace-normal"按钮或标签自动换行
lua
className = "flex flex-wrap items-center gap-2"layout.span 宽度规则
表单组件的宽度优先用 layout 控制。span 是默认/小屏宽度,sm、md、lg、xl 是响应式覆盖值。它们都按 12 栅格计算:
| span | 效果 |
|---|---|
12 | 占满一行 |
6 | 半行,两个一行 |
4 | 三分之一行,三个一行 |
3 | 四分之一行,四个一行 |
响应式断点按当前容器宽度判断,不是按整个屏幕宽度判断:
| 字段 | 生效条件 |
|---|---|
span | 默认,小屏 |
sm | 容器宽度 >= 480px |
md | 容器宽度 >= 768px |
lg | 容器宽度 >= 1024px |
xl | 容器宽度 >= 1280px |
正确写法:
lua
nameInput.Input.layout = { span = 6 }
countInput.NumberInput.layout = { span = 6 }
speed.Slider.layout = { span = 12 }大屏 4 列、小屏最多 2 列:
lua
nameInput.Input.layout = { span = 6, lg = 3 }
countInput.NumberInput.layout = { span = 6, lg = 3 }
modeSelect.Select.layout = { span = 6, lg = 3 }
enableSwitch.Switch.layout = { span = 6, lg = 3 }
speedSlider.Slider.layout = { span = 12 }AI 保守规则:
- 面向小白示例时,优先
span = 12或span = 6。 - 如果用户要求大屏更紧凑,使用
{ span = 6, lg = 3 }。 - 输入框、下拉框、数字框在窄屏容易挤压,复杂表单优先
span = 6或span = 12。 - 开关、短标签、Chip 可以用
span = 6、span = 4、span = 3。 - Slider 通常用
span = 12,避免滑杆太短。
响应式 Group 推荐写法
普通表单:
lua
local group = {
Group = {
title = "基础参数",
direction = "grid",
columns = 12,
gap = 4,
item = {
{ nameInput, countInput },
{ modeSelect, enableSwitch },
{ speedSlider },
},
}
}组件 layout:
lua
nameInput.Input.layout = { span = 6, lg = 3 }
countInput.NumberInput.layout = { span = 6, lg = 3 }
modeSelect.Select.layout = { span = 6, lg = 3 }
enableSwitch.Switch.layout = { span = 6, lg = 3 }
speedSlider.Slider.layout = { span = 12 }如果目标界面主要在小屏或窄弹窗显示,就改成全部单列:
lua
nameInput.Input.layout = { span = 12 }
countInput.NumberInput.layout = { span = 12 }
modeSelect.Select.layout = { span = 12 }
enableSwitch.Switch.layout = { span = 12 }
speedSlider.Slider.layout = { span = 12 }注意:className 适合控制容器外观、文字、间距、纯展示排版;表单组件在 Group.direction = "grid" 里的宽度优先使用 layout,不要只靠 className = "grid-cols-4" 硬排。
小屏适配禁忌
- 不要生成
grid-cols-4作为默认布局;默认应从grid-cols-1开始。 - 不要生成
flex items-center后忘记flex-wrap,否则窄屏会横向溢出。 - 不要给
P文本使用whitespace-nowrap。 - 不要给容器写固定宽度:
w-[700px]、min-w-[500px]。 - 不要给卡片写过大的内边距:小屏下避免
p-8、p-10。 - 不要把很多输入组件塞进
span = 3,小屏会显示不全。
Flex 布局类
简单横向排列可使用 Flex,但表单栅格仍优先用 Group.direction = "grid"。
| className | 用途 |
|---|---|
flex | 开启横向布局 |
flex-col | 纵向布局 |
flex-wrap | 空间不足自动换行 |
items-center | 垂直居中 |
items-start | 顶部对齐 |
justify-between | 两端对齐 |
justify-center | 居中 |
gap-2 | 小间距 |
gap-3 | 中间距 |
gap-4 | 常用间距 |
示例:标题和标签同行显示:
lua
local header = {
Div = {
className = "flex items-center justify-between gap-3",
item = {
{
{ P = { text = "基础参数", className = "text-lg font-semibold text-default-700" } },
ui.createChip("推荐", "primary", "flat"),
}
},
layout = { span = 12 },
}
}Grid 布局类
动态 UI 表单更推荐使用 Group:
lua
local group = {
Group = {
title = "基础设置",
direction = "grid",
columns = 12,
gap = 4,
item = {
{ nameInput, countInput },
{ speedSlider },
},
}
}只有在做纯展示排版时,才用 className 的 grid:
lua
local info = {
Div = {
className = "grid grid-cols-2 gap-3",
item = {
{
{ P = { text = "设备:已连接", className = "text-sm text-success" } },
{ P = { text = "延迟:12ms", className = "text-sm text-default-500" } },
}
},
layout = { span = 12 },
}
}常用组合模板
普通说明文字
lua
className = "text-sm leading-6 text-default-500"警告说明
lua
className = "text-sm font-medium text-warning"标题
lua
className = "text-lg font-semibold text-default-700"普通卡片
lua
className = "rounded-small border border-default-200 bg-default-50 p-4"紧凑卡片
lua
className = "rounded-small border border-default-200 p-3"横向工具栏
lua
className = "flex flex-wrap items-center gap-2"两端对齐标题栏
lua
className = "flex items-center justify-between gap-3"完整示例
lua
local ui = require("ui_builder")
local nameInput = ui.createInput("name", "名称", "请输入名称", "")
nameInput.Input.layout = { span = 6 }
local countInput = ui.createNumberInput("count", 1, "数量", 0, 100, 1, "1~100")
countInput.NumberInput.layout = { span = 6 }
local speed = ui.createSlider("speed", 50, "速度", 0, 100, 1)
speed.Slider.layout = { span = 12 }
local page = {
Div = {
className = "rounded-small border border-default-200 bg-default-50 p-4",
item = {
{
{
P = {
text = "基础配置",
className = "text-lg font-semibold text-default-700",
layout = { span = 12 },
}
}
},
{
{
P = {
text = "这里的 className 只控制外观,不影响 name、count、speed 的取值。",
className = "text-sm leading-6 text-default-500",
layout = { span = 12 },
}
}
},
{
{
Group = {
direction = "grid",
columns = 12,
gap = 4,
item = {
{ nameInput, countInput },
{ speed },
},
}
}
}
},
layout = { span = 12 },
}
}
ui.buildUI({ page }, 1)
StartUI()
function onUIChanged(values)
print("name =", values.name)
print("count =", values.count)
print("speed =", values.speed)
endAI 禁忌
- 不要为了美观生成大量随机类名。
- 不要使用项目未确认支持的自定义类名。
- 不要用
className控制业务取值。 - 不要把
className写成 table,必须是字符串。 - 不要在小容器里使用过大的文字类,例如
text-4xl。 - 不要用
h-screen、min-h-screen撑开动态 UI 弹窗或运行页。