主题与样式覆盖
先导入一次 @volcengine/chatkit/styles.css。公开的 --chatkit-* CSS token 提供视觉默认值;组件样式在实际绘制位置读取它们。CSS 变量沿 DOM 继承,React context 则提供上传、输入框命令和渲染配置,两者不能互相代替。
输入建议的段落样式边界
输入建议的候选文字绘制在内置编辑器的真实空段落内。相同原文、宿主样式和可用宽度下,提示与 Tab 填入后的正文共用内容起点、字形、行高、换行与段落盒模型;仅候选文字使用 --chatkit-color-text-tertiary。段落 border-color: currentColor 仍使用段落自身的颜色。候选不进入文档、草稿或撤销历史,操作 chip 是段落外的原生按钮。长候选随正文高度增长,达到编辑器 max-height 后在同一视口滚动。
不要覆盖内部 widget、CSS Module 哈希类名或 DOM 层级。若 :empty、.is-editor-empty、:has()、焦点/内容状态等让两态具有不同的几何样式,或者全局 reset 覆盖 widget,则不保证同形。flex/grid/table/float/绝对定位、多栏、竖排、CSS transform/zoom、连续几何动画、生成内容和特殊伪元素排版不在此契约内;浏览器正常缩放仍可使用。遵循下文的 CSS layer 约定。公开插槽 slots['composer.overlay'] 触发输入框下方的降级建议,物理位置不同,不适用同位置对齐保证。
输入建议的组合 Demo可切换非对称 padding/border、主题、自定义 chip 与长候选。
实例明暗与 token 作用域
Chatkit 默认浅色。通过 theme.appearance 可直接选择 light、dark 或 inherit(默认):显式模式优先于祖先;inherit 使用最近有效祖先的 data-chatkit-theme="light|dark",没有有效祖先时使用浅色。Provider 未提供显式明暗时,也可以只在外层容器上写 data-chatkit-theme,不传 theme;若 Provider 已指定明暗,实例需显式传 appearance: 'inherit' 才会重新按 DOM 祖先解析。同页并列或嵌套实例可独立选择主题,wrapper 的 color-scheme、代码高亮和内部弹层会跟随本实例。系统偏好和持久化由宿主管理。
root.className 和 root.style 直接作用到本实例的 .chatkit-wrapper。在外层容器仅声明同名 --chatkit-* 不会覆盖 wrapper 自身的默认值。可以直接在实例根节点映射宿主变量:
宿主也可用 CSS 命中 .chatkit-wrapper 覆盖公开 token;默认声明特异性为零,且处于 @layer chatkit,普通宿主规则即可覆盖:
如果聊天区背景改为 transparent,建议为 --chatkit-color-bg-elevated 提供不透明值。宿主变量不会自动影响 Chatkit;需要联动时显式将公开 token 指向宿主变量。
每个 wrapper 都声明自己的默认 token,嵌套实例也一样。因此 inherit 继承的是明暗选择,不是父实例的品牌色覆写。多个实例要共享品牌色时,将同一组宿主变量映射到各自 wrapper;只想修改一个实例时,用它自己的 root.className 或 root.style。
公开入口与 context 边界
“从包根导出”不代表组件可以在任意位置独立使用:
ChatkitProvider 自身不创建主题 DOM 边界。它把 theme 和 root 作为内部 Chatkit 的默认配置;实例显式提供同名配置时整体替换,不深合并 root.style。Provider 的 root 不会复制给外置列表、附件或语音按钮。外置组件的品牌色覆写也要命中它们自己的 wrapper,见独立组件接入。
例如,DOM 祖先为 dark、Provider 显式为 light 时,外置列表和附件按钮使用 light;内部 Chatkit 若显式设置 theme={{ appearance: 'inherit' }},则重新跟随自己的 DOM 祖先而使用 dark。不要把 Provider 的默认配置当成强制覆盖所有后代的主题。
附件菜单与 Portal
通过 Chatkit 插槽使用 ComposerAddAttachment 时,菜单使用实例内 Portal,挂在所属 wrapper 内,读取该实例的浅暗默认值和局部 token。同页多个实例的菜单分别跟随各自主题。
请通过公开的组件和插槽接入,不要手工拼装内部 Provider 或把菜单节点移到 document.body;脱离所属 wrapper 后,局部 token 和组件样式无法自动跟随。在聊天区外选择文件应使用 AttachmentButton。接入代码和键盘操作见附件页。
常用 token 的实际用途
键盘焦点与强制颜色模式
以下六个内置按钮共用下述键盘焦点样式:
普通浅色或暗色模式下,这六个按钮在 :focus-visible 使用 --chatkit-shadow-focus 取代浏览器原生 outline。默认表达式为 0 0 0 2px var(--chatkit-color-bg), 0 0 0 5px var(--chatkit-color-primary):背景色形成 2px 间隔,主操作色形成向外延伸至 5px 的外环。浅色默认背景/主色为 #fff / #101013,暗色为 #16171b / #e8e9ee。该 token 控制键盘焦点标记,不改变按钮的尺寸或非焦点态配色。
宿主可以按实例覆写,例如:
在 forced-colors: active 下,这六个按钮改用 outline: 2px solid Highlight 和 outline-offset: 2px。Highlight 是用户系统调色板中的颜色,不能理解为固定品牌色。此模式下浏览器将 box-shadow 计算为 none,因此只覆写阴影 token 不能替换系统色轮廓;该差异是为了保留焦点标记。参见 CSS Color Adjustment 规范。
上述系统色 outline 仅用于列出的六个按钮。基础 Button 及依赖它的控件(如语音按钮)没有同样的强制颜色兜底;仅靠 --chatkit-shadow-focus 的控件在该模式下可能失去焦点标记,需要宿主按使用场景补充可见的 outline。外置 AttachmentButton 则使用 2px solid var(--chatkit-color-link)、1px 间隔的 outline,它是独立的文件选择按钮,并非这里的附件菜单触发器。对强制颜色模式有要求时,请在目标环境检查用到的控件。
公开 token 默认值
表格由源码生成。暗色列未单独覆写的字体、尺寸及动效沿用浅色值;焦点环使用相同表达式,颜色随当前实例的背景与主操作色变化。阴影、图片遮罩、成功/警告/错误提示、diff、代码高亮、滚动条、流光及内置文件图标均可覆盖。
下表列出可覆写的公开值,具体消费范围以上文为准。使用相同 token 的控件会共同变化;独立定义的颜色不会自动互相推导。
样式覆盖的边界
使用公开 token 覆写实际消费它的组件样式。宿主若有更高的文字对比度要求,应结合实际背景调整前景色;例如 Markdown 正文外链使用 --chatkit-color-text-tertiary,链接按钮使用 --chatkit-color-link,两者需要分别设置。
--chatkit-session-max-width、--chatkit-flow-diff-code-width、--chatkit-flow-diff-line-bg、--chatkit-runtime-shimmer-position 等运行时变量不属于公开主题契约;自定义插槽与宿主图片由宿主自行配色。
--chatkit-color-link-subtle 用于文件 chip 悬停边框。Flow 与会话导航中的部分局部字体族使用固定列表,覆写通用 --chatkit-font-family / --chatkit-font-family-mono 不会改掉这些声明。宿主自定义图片、图标、插槽、Shiki 主题和第三方 KaTeX 样式也不会自动主题化;公开 token 表不等于全部 CSS 属性都可配置。
浏览器与宿主兼容性
图片预览、建议面板、附件菜单与 Tooltip 都挂在各自 wrapper 内并继承 token。使用 fixed 定位的浮层会受祖先样式影响:transform、filter 或会建立定位包含块的 contain 值可能改变其定位基准。自定义布局时,注意菜单和预览是否被祖先裁切或偏移。
系统强制颜色模式可以覆盖品牌配色,显示效果由系统调色板决定。需要高对比度支持时,请在目标系统中检查实际使用的控件,尤其是依赖阴影显示焦点的按钮;仅覆写颜色或阴影 token 不能替代系统色 outline。
在 Safari 或移动浏览器接入时,应结合目标设备确认主题切换、浮层位置和键盘或触摸操作。文件选择、麦克风权限以及上传、鉴权和语音服务有各自的平台与业务条件,主题配置只负责界面样式。附件交互见附件,文件存储见接入文件服务和 TOS,语音服务见语音输入。
级联层 @layer chatkit
Chatkit 的样式都在 @layer chatkit 里。同源的普通样式表声明中,未进层的全局样式(Tailwind v3 preflight、normalize、全局组件库 CSS 等)优先级高于层内声明,可能覆盖组件外观;!important 声明的层序相反。把全局 reset 实际放进排在 chatkit 前面的 reset 层即可。层的先后按首次出现的顺序确定。层序声明应放在导入 @volcengine/chatkit/styles.css 之前;在同一 CSS 文件中使用 @import 时,先写层序声明,再写 import,最后写其他样式规则: