airi 项目 UnoCSS 实战:用 transformerDirectives 在 CSS 中原生启用 @apply、@screen、theme() 与 icon()

发布时间:2026/11/3 6:28:28

airi 项目 UnoCSS 实战:用 transformerDirectives 在 CSS 中原生启用 @apply、@screen、theme() 与 icon() airi 项目 UnoCSS 实战用 transformerDirectives 在 CSS 中原生启用 apply、screen、theme() 与 icon()【免费下载链接】airi Self hosted, you-owned Grok Companion, a container of souls of waifu, cyber livings to bring them into our worlds, wishing to achieve Neuro-samas altitude. Capable of realtime voice chat, Minecraft, Factorio playing. Web / macOS / Windows supported.项目地址: https://gitcode.com/GitHub_Trending/ai/airitransformerDirectives 是 UnoCSS 提供的一个核心 transformer它让开发者能够直接在 CSS 中书写apply、screen、theme()与icon()四种指令把工具类utilities与主题theme能力搬进普通 CSS 文件中。在 airi 仓库中这条能力既被根配置集中启用uno.config.ts也被应用到桌面端渲染层如 spotlight.vue的复杂渐变与响应式样式编写上。读完本文你将掌握四种指令的完整语法、别名配置方法以及如何像 airi 一样在 Vue SFC 的 scoped style 里优雅地混用工具类与原生 CSS。本文的原始知识卡位于仓库 .agents/skills/unocss/references/transformer-directives.md下面结合 airi 的真实配置与源码逐层展开。transformerDirectives 解决的问题在纯 UnoCSS 工作流中工具类通常直接写在模板的 class 属性中。但当你需要复用一组工具类、或想在::before/::after等伪元素、keyframes内部、媒体查询里组合样式时模板 class 就无能为力了。transformerDirectives 正是为此而生——它扫描 CSS 源码把指令转换为展开后的工具类声明使样式逻辑收敛到 CSS与工具类按需生成两种范式可以共存。安装与最小配置非常简单在 UnoCSS 配置文件通常是uno.config.ts中加入 transformer 即可import { defineConfig, transformerDirectives } from unocss export default defineConfig({ transformers: [ transformerDirectives(), ], })airi 中的启用方式从根配置到各应用共享airi 的根级 uno.config.ts 把共享配置封装为sharedUnoConfig()其中 transformers 同时启用了 directives 与 variant group 两个转换器并对别名做了显式限定// 根 uno.config.ts节选 transformers: [ transformerDirectives({ applyVariable: [--at-apply], }), transformerVariantGroup(), ],这里的关键点显式传入applyVariable: [--at-apply]后自定义属性别名只保留--at-apply一个不再包含默认同义别名详见下文别名一节。随后不同子应用通过mergeConfigs复用这份共享配置——例如 packages/stage-ui/uno.config.ts 直接合并了根配置import { defineConfig, mergeConfigs } from unocss import { histoireUnoConfig, sharedUnoConfig } from ../../uno.config export default mergeConfigs([ sharedUnoConfig(), histoireUnoConfig(), defineConfig({}), ])也有的应用独立声明完整配置例如 apps/component-calling/uno.config.ts 中与transformerVariantGroup()并排启用了默认形态的transformerDirectives()不传参数。仓库通过 pnpm workspace catalog 统一锁定了unocss版本见 pnpm-workspace.yaml 中unocss: 66.7.5的 catalog 条目因此各应用获得的 transformer 行为是一致的。apply在 CSS 中内联工具类基础用法与带变体的写法apply可以把一组工具类合并进任意 CSS 规则中最直接的应用是封装类组件化的样式.custom-btn { apply py-2 px-4 font-semibold rounded-lg; }当需要混入hover:、focus:等**变体variant**时由于变体值中带冒号与空格必须使用引号包裹整个字符串否则指令解析会失败.custom-btn { apply hover:bg-blue-600 focus:ring-2; }CSS 自定义属性替代写法vanilla CSS 兼容apply是标准 CSS 之外的指令语法若希望样式文件仍能通过普通 CSS 解析器例如防止原生 CSS 校验报错或希望渐进增强可改用 CSS 自定义属性别名.custom-div { --at-apply: text-center my-0 font-medium; }transformer 支持三个同义别名配置如下transformerDirectives({ applyVariable: [--at-apply, --uno-apply, --uno], // 或完全关闭别名能力applyVariable: false })默认别名是--at-apply当传入数组时数组内容即生效别名集合设为false可关闭该特性若你的样式表中恰好有用到这些自定义属性的场景可避免误展开。airi 的真实用法伪元素 复杂渐变 深色模式自定义属性写法在 airi 桌面端被大量使用因为它能出现在::before/::after这类伪元素规则中与手写 position、mask-image 等原生属性无缝共存。下面摘自已搜索可见的 apps/stage-tamagotchi/src/renderer/pages/spotlight.vue舞台 spotlight 输入框的光晕层.spotlight-card::before { pointer-events: none; --at-apply: bg-gradient-to-r from-primary-500/25 via-primary-500/12 to-transparent dark:from-primary-400/25 dark:via-primary-400/12 dark:to-transparent; content: ; position: absolute; inset: 0; z-index: 0; width: 85%; height: 100%; mask-image: linear-gradient(120deg, white 100%); } .spotlight-card::after { pointer-events: none; --at-apply: bg-dotted-[primary-300/35] dark:bg-dotted-[primary-200/16]; position: absolute; inset: 0; z-index: 0; width: 100%; height: 100%; background-size: 10px 10px; content: ; mask-image: linear-gradient(165deg, white 30%, transparent 55%); }这个例子至少说明了三点实战要点值必须带引号多段工具类含空格与dark:变体必须写成引号字符串--at-apply后的值才会被当作完整指令解析可以消费自定义规则与主题色bg-dotted-[primary-300/35]对应根配置 uno.config.ts 中自定义的bg-dotted-[...]规则而primary-300等色板来自presetChromatic生成的主题——证明--at-apply展开的是与模板 class 完全一致的完整工具类体系原生 CSS 与指令可并存同一规则内mask-image、background-size、position等手写声明与--at-apply互不干扰这让UI 引擎层样式保持为可读的 CSS。另一个更简洁的用法见 apps/stage-tamagotchi/src/renderer/pages/index.vue加载动效墙.wall { --at-apply: text-primary-300; --wall-width: 8px; animation: wall-move 1s linear infinite; background-image: repeating-linear-gradient( 45deg, currentColor, currentColor var(--wall-width), #ff00 var(--wall-width), #ff00 calc(var(--wall-width) * 2) ); }这里--at-apply: text-primary-300仅为元素注入文字颜色随后手写的background-image通过currentColor引用它——指令与原生 CSS 通过颜色关键字协同工作是工具类用于取主题 token、原生 CSS 负责复杂绘制的理想分工。提示从源码检索看airi 的 Vue SFC 中统一采用--at-apply别名而非apply关键字。若团队规约更看重可迁移性可采用与根配置一致的applyVariable显式列表避免样式被其他解析器误读。screen把断点写成语义化的媒体查询screen 断点名会被转换为对应的媒体查询断点名称来自主题breakpointspresetWind3 / preset-mini 默认提供sm/md/lg/xl/2xl等。经典响应式栅格示例.grid { display: grid; grid-template-columns: repeat(2, 1fr); } screen sm { .grid { grid-template-columns: repeat(3, 1fr); } } screen lg { .grid { grid-template-columns: repeat(4, 1fr); } }相比手写媒体查询screen的可读性更强且断点值始终与主题定义保持单一事实来源。断点变体lt- 与 at-除默认的大于等于某断点语义外还支持两种变体/* 小于某断点才生效max-width 语义 */ screen lt-sm { .item { display: none; } } /* 仅在该断点区间生效min/max 组合 */ screen at-md { .item { width: 50%; } }这在移动端隐藏某元素仅中屏横排等场景中比默认的向上兼容语义更精确。theme()在任意 CSS 属性中读取主题令牌theme(路径点分字符串)允许在 CSS 值里直接读取 UnoCSS 主题配置避免把colors.blue.500这类十六进制硬编码散落在样式文件中.btn-blue { background-color: theme(colors.blue.500); padding: theme(spacing.4); border-radius: theme(borderRadius.lg); }取值路径采用点分记号映射到根配置defineConfig({ theme: {...} })的对象结构。airi 根配置扩展了丰富的主题段见 uno.config.ts例如theme.fontFamily中定义的cute/cutejp/sans-rounded等字体族、以及theme.animation下一整套 keyframes / durations / timingFns 的入场退场动画配置——这些都可以通过theme(fontFamily.cute)、theme(animation.durations.fadeIn)这类写法在 CSS 中引用与apply、模板 class 读取的是同一份主题数据。icon()把图标工具类转成 SVG 背景图icon()指令能把预设图标工具类如i-carbon-sun转换为内联 SVGbackground-image。它依赖 preset-icons 提供图标解析——airi 根配置恰好启用了presetIcons并挂载了多个 Iconify 集合见 uno.config.ts.icon-sun { background-image: icon(i-carbon-sun); } /* 第二个参数指定自定义颜色 */ .icon-moon { background-image: icon(i-carbon-moon, #fff); } /* 颜色参数同样支持 theme() 读取主题色 */ .icon-alert { background-image: icon(i-carbon-warning, theme(colors.red.500)); }注意两点颜色的使用方式是覆盖图标原色本质是为内联 SVG 注入指定色值而theme(colors.red.500)之所以用双引号是因为它嵌套在外层单引号之内且颜色参数本身是一个表达式而非普通字符串。该能力非常适合为那些无法通过text-*染色的背景型图标注入主题色。完整组合示例Card 组件把四种指令放进一个组件级样式即可看到它们如何协作完整示例亦保留于原始知识卡.card { apply rounded-lg shadow-md p-4; background-color: theme(colors.white); } .card-header { apply font-bold text-lg border-b; padding-bottom: theme(spacing.2); } screen md { .card { apply flex gap-4; } } .card-icon { background-image: icon(i-carbon-document); apply w-6 h-6; }从这份示例可以归纳协作模式apply负责排版骨架与可见性theme()负责取值screen负责响应式分段icon()负责图形资产。在 airi 这类多端Web / Electron / Capacitor / tamagotchi 桌面应用monorepo 中把这份 CSS 放在公共 UI 包如 packages/stage-ui内配合根配置的分层启用策略即可保证各端获得一致的指令行为。使用建议与注意事项作用域内使用在 Vue SFC 中style scoped内的apply/--at-apply展开发生在 UnoCSS 构建阶段Vue 的 scoped 属性处理与其并不冲突airi 的多个页面即采用这种组合。带空格与变体务必加引号apply与--at-apply的值若包含hover:/dark:/ 空格分隔的多段类名必须整体加引号否则会被当作单一工具类解析失败。别名的统一管理既然项目从根配置统一了applyVariable新增子应用时应优先复用sharedUnoConfig()或与其保持一致避免不同应用间别名集合漂移。图标类需存在集合icon()依赖presetIcons及其配置的 collections如果图标名不在已加载集合内构建期不会生成对应背景图。与 extractor 的配合apply/--at-apply等指令内出现的工具类由 transformer 收集并触发生成airi 根配置的 content pipeline见 uno.config.ts同时覆盖.vue、.ts/.js等文件确保 CSS 中引用的类与模板中用到的类都进入统一扫描范围。若需进一步了解相关的 preset-icons、preset-wind3、variant-group 与 shortcuts 能力可继续查阅仓库 .agents/skills/unocss 下的 references 知识卡如 preset-icons.md、preset-wind3.md、transformer-variant-group.md、core-shortcuts.md它们与本文共同构成 UnoCSS 在 airi 中的完整使用参考。【免费下载链接】airi Self hosted, you-owned Grok Companion, a container of souls of waifu, cyber livings to bring them into our worlds, wishing to achieve Neuro-samas altitude. Capable of realtime voice chat, Minecraft, Factorio playing. Web / macOS / Windows supported.项目地址: https://gitcode.com/GitHub_Trending/ai/airi创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
延伸阅读

更多相关文章

2026/11/1 20:27:36

一串9引发的技术思考:数值溢出与边界测试

1. 先别急,这个标题到底在说什么我先说结论:这个“项目标题”一共14个9,没有别的字符。你把它丢给我,让我拆解背后的核心领域、技术点、应用场景,那我第一反应是——这根本不是传统意义上的项目名,而是一串…

2026/11/2 4:36:08

乐鑫ESP32模组智能交互实战:选型、语音、GUI与量产避坑指南

1. 乐鑫模组为什么总能出现在智能交互的第一线 做智能硬件这几年,我发现一个很有意思的现象:不管是做智能音箱、中控屏、离线语音开关,还是做雷达人体存在传感器,大家聊着聊着总会提到乐鑫。早些年大家用ESP8266做联网&#xff0c…

2026/10/31 19:19:53

2007年数学建模B题公交车调度优化:从建模到代码实现

简介:2007年全国大学生数学建模B题通常涉及交通网络或公交路径优化,Dijkstra算法是求解最短路径的核心工具。该压缩包提供了当年参赛队伍的完整Java实现,包含7个Java源文件、11个编译后的class文件以及Eclipse工程配置文件,共21个…

2026/11/3 6:25:10

std::reverse并非C++11新特性:从C++98到C++20的兼容性解析

说实话,看到“C11以下能用std::reverse吗”这个热词冲上榜单的时候,我第一反应是愣了几秒。不是因为这问题有多难,而是它让我意识到:原来后端、算法岗的年轻同事里,有相当一批人把“std::reverse很年轻”当成了一种默认…

2026/11/3 6:25:10

虚拟机密码重置全攻略:从原理到实战

1. 虚拟机密码重置场景解析第一次遇到虚拟机密码遗忘的情况时,我正赶在项目交付前夜调试环境。那种面对登录界面反复输入错误密码的焦灼感,相信很多运维人员都深有体会。不同于物理主机可以直接拆机清CMOS,虚拟环境密码恢复有其独特的技术路径…

2026/11/3 6:25:10

RAG系统测试工程:防幻觉与一致性测试实践

1. RAG测试工程的核心挑战在构建基于检索增强生成(Retrieval-Augmented Generation)的系统时,测试环节往往是最容易被忽视的部分。最近我在为某金融知识问答系统实施RAG测试时,深刻体会到没有健全的测试体系就像在悬崖边蒙眼行走—…

2026/11/3 6:25:10

设计工具内实时翻译技术解析与应用实践

1. 项目背景与核心价值在全球化运营的今天,多语言内容输出已成为企业标配。传统模式下,运营团队需要将设计稿交给专业翻译人员处理,再返给设计师调整排版,这种"设计→翻译→返工"的流程平均需要3-5天周转时间。我们团队…

2026/11/3 6:25:10

电商多语言自动化设计系统开发实战

1. 项目背景与核心价值去年双十一大促期间,我们电商团队需要为30多个国家市场同步发布促销素材。传统流程需要设计团队先出中文版,再由翻译团队处理多语言版本,最后交给本地化团队调整排版。这个链条上任何一个环节卡顿,都会导致整…

2026/11/3 6:20:09

ESP32本地声音事件检测:用FFT与状态机识别蜂鸣报警

上个月半夜出差回来,刚把钥匙插进锁孔,门没开,楼道里的声控灯倒是先亮了。我一回头,发现门上那个报警蜂鸣器正在“哔——”地叫,是出门时门没关严,触发了防撬报警。问题是,我人在外面&#xff0…

2026/11/2 6:08:01

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/2 6:39:12

SSM电子书店源码全解析:结构、原理、部署与排错实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/3 1:04:48

STM32实战:基于MAX14431数字隔离器的SPI隔离通信方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/3 1:04:48

工业SPI隔离通信设计:MAX14431BAEE+与STM32L4A6RG实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/3 1:04:48

STM32+NRF24L01无线抢答器:硬件设计、通信协议与低功耗实现

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/2 6:08:01

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/2 6:39:12

SSM电子书店源码全解析:结构、原理、部署与排错实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑