样式随心定制:TinyRobot 样式覆写与 CSS 变量实战解析
一个优秀的组件库不仅要提供功能完备的 API,还要提供灵活的样式定制能力。TinyRobot 基于 CSS 变量构建了完整的样式体系,每个组件都有详细的变量列表,开发者只需覆写对应的 CSS 变量,即可实现从微调到全面改版的样式定制。
本文将从 Sender、Container、Prompts、Feedback 四个核心组件的 CSS 变量出发,结合实战案例,全面解析 TinyRobot 的样式覆写体系。
Sender CSS 变量完整列表
Sender 是样式变量最丰富的组件之一,覆盖了背景、文字、间距、按钮等各个方面。
基础颜色
| 变量名 | 说明 | 典型值 |
|---|---|---|
--tr-sender-bg-color |
背景颜色 | #ffffff |
--tr-sender-text-color |
文本颜色 | #333333 |
--tr-sender-placeholder-color |
占位符颜色 | #999999 |
--tr-sender-button-hover-bg |
按钮悬停背景 | #f5f5f5 |
基础颜色变量是最常用的定制点。通过覆写这四个变量,可以快速改变 Sender 的整体色调:
css
/* 暗色风格 */
.my-sender-dark {
--tr-sender-bg-color: #1a1a2e;
--tr-sender-text-color: #e0e0e0;
--tr-sender-placeholder-color: #666666;
--tr-sender-button-hover-bg: #2a2a4e;
}
/* 蓝色品牌风格 */
.my-sender-brand {
--tr-sender-bg-color: #f0f7ff;
--tr-sender-text-color: #1a365d;
--tr-sender-placeholder-color: #90cdf4;
--tr-sender-button-hover-bg: #bee3f8;
}
尺寸和间距
| 变量名 | 说明 | 典型值 |
|---|---|---|
--tr-sender-font-size |
字体大小 | 14px |
--tr-sender-line-height |
行高 | 1.5 |
--tr-sender-border-radius |
圆角大小 | 8px |
--tr-sender-padding |
内边距 | 12px |
--tr-sender-gap |
元素间距 | 8px |
--tr-sender-footer-gap |
底部元素间距 | 8px |
间距变量控制 Sender 的空间节奏。通过调整这些变量,可以让 Sender 从紧凑到宽松切换:
css
/* 紧凑布局 */
.my-sender-compact {
--tr-sender-padding: 8px;
--tr-sender-gap: 4px;
--tr-sender-footer-gap: 4px;
--tr-sender-font-size: 13px;
--tr-sender-line-height: 1.4;
}
/* 宽松布局 */
.my-sender-relaxed {
--tr-sender-padding: 16px;
--tr-sender-gap: 12px;
--tr-sender-footer-gap: 12px;
--tr-sender-font-size: 16px;
--tr-sender-line-height: 1.6;
--tr-sender-border-radius: 12px;
}
Header 区域
| 变量名 | 说明 |
|---|---|
--tr-sender-header-padding |
头部内边距 |
--tr-sender-header-divider-inset |
头部分割线缩进 |
--tr-sender-multi-main-padding |
多行模式主区域内边距 |
Header 区域变量用于定制 Sender 上方的提示区域。当使用 header 插槽或 Template 扩展时,这些变量会影响 Header 的空间布局:
css
.my-sender {
--tr-sender-header-padding: 12px 16px;
--tr-sender-header-divider-inset: 16px;
--tr-sender-multi-main-padding: 12px 16px;
}
Footer 区域
| 变量名 | 说明 |
|---|---|
--tr-sender-footer-padding |
底部内边距 |
Footer 区域是放置功能按钮(VoiceButton、UploadButton 等)的区域:
css
.my-sender {
--tr-sender-footer-padding: 8px 12px;
}
前缀和操作区
| 变量名 | 说明 |
|---|---|
--tr-sender-prefix-padding-right |
前缀区域右内边距 |
--tr-sender-actions-padding-right |
操作区域右内边距 |
这两个变量控制输入框内部左侧前缀和右侧操作区与文本之间的间距:
css
.my-sender {
--tr-sender-prefix-padding-right: 8px;
--tr-sender-actions-padding-right: 8px;
}
按钮
| 变量名 | 说明 | 典型值 |
|---|---|---|
--tr-sender-button-size |
按钮尺寸 | 32px |
--tr-sender-button-size-submit |
提交按钮尺寸 | 32px |
按钮尺寸变量可以单独调整提交按钮的大小,使其比其他按钮更大或更小:
css
/* 大提交按钮 */
.my-sender {
--tr-sender-button-size: 32px;
--tr-sender-button-size-submit: 40px;
}
/* 小按钮紧凑风格 */
.my-sender {
--tr-sender-button-size: 24px;
--tr-sender-button-size-submit: 28px;
}
尺寸变体:size="small"
当 Sender 设置 size="small" 时,所有尺寸相关的 CSS 变量会自动切换到对应的 -small 变体:
css
/* size="normal" (默认) */
--tr-sender-font-size → 14px
--tr-sender-padding → 12px
--tr-sender-button-size → 32px
/* size="small" (自动切换) */
--tr-sender-font-size-small → 13px
--tr-sender-padding-small → 8px
--tr-sender-button-size-small → 28px
每个变量都有对应的 -small 版本,组件内部通过 CSS 选择器自动切换:
css
/* 组件内部实现(伪代码) */
.tr-sender {
font-size: var(--tr-sender-font-size);
padding: var(--tr-sender-padding);
}
.tr-sender--small {
font-size: var(--tr-sender-font-size-small);
padding: var(--tr-sender-padding-small);
}
开发者可以覆写 -small 变体来定制紧凑模式下的样式:
css
/* 自定义紧凑模式的样式 */
.my-sender {
--tr-sender-font-size-small: 12px;
--tr-sender-padding-small: 6px;
--tr-sender-button-size-small: 24px;
--tr-sender-button-size-submit-small: 28px;
}
Container CSS 变量
Container 作为聊天界面的容器框架,其样式变量覆盖了标题、边框、宽度等属性。
全局变量
| 变量名 | 说明 |
|---|---|
--tr-container-bg-color |
容器背景色 |
--tr-container-border-color |
容器边框色 |
--tr-container-border-width |
容器边框宽度 |
--tr-container-header-operations-gap |
操作按钮间距 |
--tr-container-header-padding |
头部内边距 |
--tr-container-title-color |
标题文字颜色 |
--tr-container-title-font-size |
标题字体大小 |
--tr-container-title-font-weight |
标题字体粗细 |
--tr-container-title-line-height |
标题行高 |
--tr-container-width |
容器宽度 |
全屏模式变量
| 变量名 | 说明 |
|---|---|
--tr-container-header-padding-fullscreen |
全屏模式头部内边距 |
--tr-container-title-font-size-fullscreen |
全屏模式标题字体大小 |
--tr-container-title-line-height-fullscreen |
全屏模式标题行高 |
全屏模式下,Container 会加上 fullscreen 类名,使用专用的 CSS 变量:
css
/* 非全屏模式 */
:root {
--tr-container-width: 600px;
--tr-container-title-font-size: 16px;
--tr-container-bg-color: #ffffff;
--tr-container-border-color: #e5e7eb;
}
/* 全屏模式 */
:root {
--tr-container-title-font-size-fullscreen: 20px;
--tr-container-header-padding-fullscreen: 0 200px 24px;
--tr-container-bg-color: #f8f9fa;
}
Prompts CSS 变量
Prompts 组件的 CSS 变量非常丰富,覆盖了提示项、标题、描述、徽章的各个方面。
Prompt 根元素
| 变量名 | 说明 |
|---|---|
--tr-prompt-bg |
提示项背景色 |
--tr-prompt-bg-hover |
提示项悬停背景色 |
--tr-prompt-bg-active |
提示项激活背景色 |
--tr-prompt-bg-disabled |
提示项禁用背景色 |
--tr-prompt-border-radius |
圆角大小 |
--tr-prompt-shadow |
阴影效果 |
--tr-prompt-width |
提示项宽度 |
--tr-prompt-padding |
内边距 |
--tr-prompt-gap |
图标与内容间距 |
Title 标题
| 变量名 | 说明 |
|---|---|
--tr-prompt-title-color |
标题文字颜色 |
--tr-prompt-title-font-size |
标题字号 |
--tr-prompt-title-line-height |
标题行高 |
--tr-prompt-title-font-weight |
标题字重 |
Description 描述
| 变量名 | 说明 |
|---|---|
--tr-prompt-description-color |
描述文字颜色 |
--tr-prompt-description-font-size |
描述字号 |
--tr-prompt-description-line-height |
描述行高 |
Badge 徽章
| 变量名 | 说明 |
|---|---|
--tr-prompt-badge-bg |
徽章背景色 |
--tr-prompt-badge-color |
徽章文字颜色 |
--tr-prompt-badge-padding |
徽章内边距 |
--tr-prompt-badge-font-size |
徽章字号 |
--tr-prompt-badge-line-height |
徽章行高 |
尺寸变体
Prompts 的 size 属性支持 small、medium、large 三种尺寸。与 Sender 不同,Prompts 使用 -small、-medium、-large 后缀:
css
/* 不同尺寸的内边距 */
--tr-prompt-padding-small
--tr-prompt-padding-medium
--tr-prompt-padding-large
/* 不同尺寸的标题字号 */
--tr-prompt-title-font-size-small
--tr-prompt-title-font-size-medium
--tr-prompt-title-font-size-large
Prompts 容器变量
| 变量名 | 说明 |
|---|---|
--tr-prompts-gap |
提示项之间的间距 |
Feedback CSS 变量
Feedback 组件主要用于气泡消息的操作反馈,其 CSS 变量控制操作按钮和动作按钮的样式。
由于 Feedback 的样式变量在官方文档中没有完整列出,开发者可以通过浏览器开发者工具(F12)检查 Feedback 组件的 DOM 结构,找到对应的 CSS 变量名称。TinyRobot 的所有组件都遵循 --tr-组件名-属性名 的命名规范。
CSS 变量覆写实战
实战1:自定义品牌色 Sender
vue
<template>
<tr-sender
class="brand-sender"
v-model="text"
@submit="handleSubmit"
>
<template #footer="{ disabled, loading }">
<tr-voice-button :disabled="disabled || loading" />
</template>
</tr-sender>
</template>
<style>
.brand-sender {
/* 品牌蓝色背景 */
--tr-sender-bg-color: #f0f7ff;
--tr-sender-text-color: #1a365d;
--tr-sender-placeholder-color: #a0aec0;
/* 更大的圆角 */
--tr-sender-border-radius: 16px;
/* 适中间距 */
--tr-sender-padding: 14px;
--tr-sender-gap: 10px;
/* 大提交按钮 */
--tr-sender-button-size: 36px;
--tr-sender-button-size-submit: 44px;
/* 悬停效果 */
--tr-sender-button-hover-bg: #bee3f8;
}
</style>
实战2:暗色主题全组件覆写
结合 ThemeProvider,实现暗色主题下的全组件样式定制:
css
/* 暗色模式全局覆写 */
[data-tr-color-mode='dark'] {
/* Sender */
--tr-sender-bg-color: #1e1e2e;
--tr-sender-text-color: #cdd6f4;
--tr-sender-placeholder-color: #585b70;
--tr-sender-button-hover-bg: #313244;
--tr-sender-border-radius: 12px;
/* Container */
--tr-container-bg-color: #181825;
--tr-container-border-color: #313244;
--tr-container-title-color: #cdd6f4;
/* Prompts */
--tr-prompt-bg: #313244;
--tr-prompt-bg-hover: #45475a;
--tr-prompt-title-color: #cdd6f4;
--tr-prompt-description-color: #a6adc8;
/* Bubble */
--tr-bubble-box-bg: #313244;
--tr-bubble-text-color: #cdd6f4;
}
vue
<template>
<theme-provider v-model:color-mode="colorMode">
<tr-container title="AI 助手">
<tr-bubble-list :messages="messages" />
<template #footer>
<tr-sender @submit="handleSubmit" />
</template>
</tr-container>
</theme-provider>
</template>
<script setup>
import { ref } from 'vue'
const colorMode = ref('dark')
</script>
实战3:Prompts 卡片化风格
将默认的条状提示项改为卡片风格:
css
.card-prompts {
--tr-prompt-bg: #ffffff;
--tr-prompt-bg-hover: #f8f9fa;
--tr-prompt-border-radius: 12px;
--tr-prompt-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
--tr-prompt-padding: 16px;
--tr-prompt-gap: 12px;
--tr-prompt-title-font-size: 15px;
--tr-prompt-title-font-weight: 600;
--tr-prompt-title-color: #1a365d;
--tr-prompt-description-color: #718096;
--tr-prompt-description-font-size: 13px;
--tr-prompts-gap: 12px;
}
实战4:紧凑移动端布局
针对移动端空间受限的场景,使用 size="small" + 自定义 -small 变量:
css
/* 移动端紧凑布局 */
.mobile-sender {
--tr-sender-font-size-small: 12px;
--tr-sender-padding-small: 8px;
--tr-sender-gap-small: 4px;
--tr-sender-footer-gap-small: 4px;
--tr-sender-border-radius-small: 8px;
--tr-sender-button-size-small: 28px;
--tr-sender-button-size-submit-small: 32px;
}
vue
<template>
<tr-sender class="mobile-sender" v-model="text" size="small" />
</template>
主题继承与 ThemeProvider 联动
Sender 的 CSS 变量会根据父级 ThemeProvider 的配置自动继承。这意味着:
- 包裹在 ThemeProvider 中的 Sender 无需额外设置主题
- ThemeProvider 切换主题后,Sender 的样式自动跟随
- 嵌套 ThemeProvider 时,Sender 使用最近的 ThemeProvider 的配置
vue
<template>
<!-- 外层:默认主题 -->
<theme-provider color-mode="light">
<tr-sender /> <!-- 继承 light 主题 -->
<!-- 内层:自定义主题 -->
<theme-provider theme="brand" color-mode="dark">
<tr-sender /> <!-- 继承 brand + dark 主题 -->
</theme-provider>
</theme-provider>
</template>
CSS 变量的覆写优先级遵循标准 CSS 规则:
- 直接类名覆写 (如
.my-sender { --tr-sender-bg-color: ... })------ 最高优先级 - 属性选择器覆写 (如
[data-tr-color-mode='dark'] { ... })------ ThemeProvider 驱动 - 组件默认值 ------ 最低优先级
css
/* 直接类名覆写优先级最高 */
.my-sender {
--tr-sender-bg-color: #f0f7ff; /* 即使 ThemeProvider 设置了 dark,这里仍然生效 */
}
/* 属性选择器覆写------由 ThemeProvider 驱动 */
[data-tr-color-mode='dark'] {
--tr-sender-bg-color: #1e1e2e; /* 仅在 dark 模式下生效 */
}
ShadowDOM 兼容注意事项
如果你的应用使用 ShadowDOM(如 Web Components),需要注意:
- CSS 变量可以穿透 ShadowDOM 边界------
:host和:host-context()选择器可以访问外部 CSS 变量 - 但 ThemeProvider 设置的
data-tr-theme和data-tr-color-mode属性在 ShadowDOM 外部的html元素上,:host-context()可以匹配 - 如果
targetElement设置为 ShadowDOM 内部的元素,需要确保属性选择器能匹配到
css
/* ShadowDOM 内部样式 */
:host {
--tr-sender-bg-color: var(--external-sender-bg, #ffffff);
}
:host-context([data-tr-color-mode='dark']) {
--tr-sender-bg-color: var(--external-sender-bg-dark, #1e1e2e);
}
小结
TinyRobot 的 CSS 变量体系遵循一致的命名规范(--tr-组件名-属性名),覆盖了从颜色、间距到按钮尺寸的各个方面。关键设计特点:
- 完整覆盖:每个组件都有详细的变量列表,满足从微调到全面改版的定制需求
- 尺寸变体 :通过
-small(Sender)或-small/-medium/-large(Prompts)后缀,自动适配不同尺寸 - 主题联动:CSS 变量与 ThemeProvider 的属性选择器无缝联动,切换主题自动生效
- ShadowDOM 兼容:CSS 变量天然穿透 ShadowDOM 边界,但需注意属性选择器的匹配范围
样式定制不再是"改源码"或"写全局覆盖"的粗糙操作------通过 CSS 变量,TinyRobot 让样式定制变得精确、可控、可维护。
🔗 TinyRobot 官网 :tiny-robot.opentiny.design
🔗 GitHub 仓库 :github.com/opentiny/ti...