ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Yeti 框架入门:CSS-first、零构建的原生布局与样式框架

Yeti 框架入门:CSS-first、零构建的原生布局与样式框架 Yeti 框架入门CSS-first、零构建的原生布局与样式框架【免费下载链接】yetiA CSS-first, native, zero-build layout and styling framework for web designers.项目地址: https://gitcode.com/gh_mirrors/fo/yetiYeti 是 Foundation 团队在 Foundation for Sites 之后推出的新一代 CSS 优先、原生、零构建的布局与样式框架目标是让设计师用人类可读、Agent 可写的标记快速搭建风格统一的站点。本文以仓库 README.md 为主线结合源码、官方指南与测试系统讲解 Yeti 的定位、核心特性、上手方式、Token 体系以及布局/组件/主题三大机制读完后你可以直接引入一个样式表开始构建页面并理解其背后的层叠层架构与可访问性保障。Yeti 是什么不是什么是什么Yeti 给设计师提供结构 视觉系统用来快速构建风格连贯的站点而且标记既适合人阅读也适合 AI Agent 编写。它本质上只有一个样式表link relstylesheet href/css/yeti.css其核心理念可以概括为六点CSS-first and nativeCSS 优先且原生容器查询container queries、层叠层cascade layers、原生嵌套native nesting、light-dark()、dialog、popover、scroll-snap 这些现代浏览器原生能力替代了过去需要 JavaScript 或预处理器才能完成的工作。Zero build, ever永远零构建使用它不需要 Sass、不需要 Node、不需要打包器如果项目本身有构建流程它可以无缝组合进去但绝不强制要求。Named layouts, not utility soup命名布局而非工具类大杂烩基于意图的布局原语layout primitives和组合好的配方recipes用少量data-*属性配置。One token scale单一 Token 刻度字体与间距由同一个基值base和同一个比率ratio在运行时推导出来改一个比率整个系统自动重算。Accessible by default默认可访问每个组件都有正确的焦点处理和 ARIA并且这些都在 CI 中自动检查。Legible to agents对 Agent 可读机器可读的 manifest 描述每个组件文档、类型提示和一个 MCP 服务器都从它生成。不是什么明确边界同样重要它不是 Web Component 库不是工具类框架不是构建期系统不带 polyfill核心中也没有全功能滑块。一句话概括——凡是用来绕开现代 CSS 已经解决的问题的东西都不存在。与 Foundation for Sites 的关系对于 Foundation for Sites 6 的用户需要特别说明这个仓库就是 Yeti是 Foundation for Sites 的继任者。6.x 版本继续在v6分支上维护仅修 bugnpm 上的foundation-sites也继续从该分支发布 6.x。当前 Yeti 处于7.0.0-alpha开发阶段没有任何东西是稳定的在 beta 之前类名、属性和 Token 都可能随提交变化。快速上手一行样式表与本地 fixtures方式一引入打包好的样式表生产项目中最简单的用法是像文档开头那样链接打包产物package.json的style字段指向dist/yeti.csslink relstylesheet href/css/yeti.css方式二直接链接未构建源码README 的 Try it today 部分说明当前 Token、reset、基础层、十七个布局原语、三个配方和前八个组件已经就位并附带两个示例主题。想立即试用可以直接链接源码目录下的入口文件link relstylesheet hrefsrc/yeti.css然后写纯 HTML 即可无需任何构建步骤。方式三在本地运行全部 fixtures仓库提供了完整的本地演示环境可以浏览每一个组件和布局的示例页面git clone https://gitcode.com/gh_mirrors/fo/yeti cd yeti npm ci npx playwright install npm test npm run fixtures # then open http://localhost:4173/ to browse every fixture各步骤的作用可以从 package.json 的 scripts 中确认npm ci按package-lock.json安装开发依赖Playwright 与 axe-core 等。npx playwright install安装浏览器测试所需的浏览器运行时。npm test串联执行npm run validate校验 manifest / Token / 主题→npm run test:toolsNode 单元测试见 test/tools/→npm run test:browserPlaywright 浏览器测试配置见 playwright.config.js。npm run fixtures启动由 test/browser/serve.js 提供的静态服务器然后打开http://localhost:4173/即可浏览所有 fixture 页面。核心特性深度解读CSS-first and native层叠层如何工作原生不是口号而是有具体的源码实现。入口文件 src/yeti.css 的第一行导入 src/layers.css后者一次性声明了层叠层顺序layer yeti.reset, yeti.base, yeti.layouts, yeti.components, yeti.utilities;这个声明的关键点在于层顺序固定后才解析任何规则并且用户自己写的未分层CSS 默认会胜过所有这些子层——这意味着覆盖 Yeti 样式不需要!important直接写普通 CSS 即可。整个导入链从 src/yeti.css 也可以看清分层结构layers.css→ 各 Token → reset → base 基础层 → 十七个布局 → 三个配方 → 八个组件。Zero build为什么不需要预处理器零构建源于两件事一是依赖现代 CSS 原生特性原生嵌套、layer、容器查询等替代了 Sass/Less 承担的角色二是产物组织上package.json 的exports除了默认的./dist/yeti.css还提供了./css/*、./themes/*、./manifest等细分入口允许项目按需引入例如只引入某个dist/css/下的文件。用与不用构建工具取决于你自己的项目而不是 Yeti 的要求。Named layouts意图化布局原语Yeti 不用.grid-md-4这类视口断点类而是提供 17 个命名布局每个布局只负责排列自己的子元素、并决定子元素之间的间距——子元素永远不携带自己的 margin间距由持有它们的布局决定。完整清单见 layouts 指南每个布局的独立文档位于 docs/ 下如 stack、sidebar、grid、timeline 等。所有布局共享同一套data-*属性词汇表其完整取值如下详见 layouts 指南AttributeValuesRead bydata-gapnone,xs,sm,md,lg,xl,2xl,3xl, plus a fluid pair of any two of those (xs-sm,xs-md,xs-lg,xs-xl,xs-2xl,xs-3xl,sm-md,sm-lg,sm-xl,sm-2xl,sm-3xl,md-lg,md-xl,md-2xl,md-3xl,lg-xl,lg-2xl,lg-3xl,xl-2xl,xl-3xl,2xl-3xl)stack, cluster, sidebar, columns, cover, grid, scroller, overlay, box, center, icondata-alignstart,center,end,stretch,baselinestack, cluster, sidebar, columns, icondata-justifystart,center,end,between,around,evenlycluster, columnsdata-thresholdxs,sm,md,lg,xl,2xlcolumnsdata-widthxs,sm,md,lg,xl,2xlsidebar, scrollerdata-minnone,xs,sm,md,lg,xl,2xlgriddata-maxxs,sm,md,lg,xl,2xlcenterdata-ratio1/1,4/3,3/2,16/9,21/9framedata-columns1,2,3,4,5,6griddata-sidestart,endsidebardata-limit2,3,4,5columns — the first N share a row; every later child takes a full rowdata-align-selfstart,center,end,stretch,baselinea child of layer — places that child verticallydata-justify-selfstart,center,end,stretcha child of layer — places that child horizontallydata-span1,2,3,4,5,6a child of columns — that childs share of the rowdata-ranks2,3,4,5,6grid — how many parts each child has; lines up neighbours parts across the rowdata-foldbooleangrid — the column count halves as the grid narrows, instead of stepping down one at a timedata-notebooleana child of breakout — a margin note beside the paragraph it followsdata-alternatebooleantimeline — entries take alternate sides of a centred rail once it is wide enough这套词汇表在源码中有精确的落点src/layouts/attributes.css 把每个data-*值映射为一次私有属性赋值——data-gaplg读取--yeti-space-lgdata-widthsm读取--yeti-width-sm行为类属性data-align、data-justify、data-ratio等则映射为对应的 CSS 关键字。文件头部的注释还说明了一个重要设计属性值只设置一次私有属性布局仅在属性缺失时才提供自己的默认值因此嵌套布局永远不会继承父级的值。此外data-gap支持流体对如data-gapsm-lg它不是在两档之间跳变而是从窄视口的sm到宽视口的lg平滑过渡与字体刻度本身的流体行为一致。阈值threshold而非断点breakpoint布局指南用一个对比解释了columns为什么接收data-threshold而不是断点阈值读取的是元素所在容器的宽度而不是视口宽度。同一个columns放进sidebar的内容侧时永远不会看到完整视口侧边栏已经占掉了一部分宽度它仍然会在自己的阈值处切换为行排列同样的标记放进全宽区块时因为容器更宽切换发生在更宽的视口下。相同标记、相同阈值两个不同的视口宽度——因为阈值读的是盒子不是窗口div classsidebar>:root { --yeti-base: 1.0625rem; /* body size, every viewport */ --yeti-ratio: 1.25; /* each step is 1.25 times the last */ }左侧未设置时二者都是流体的基值从--yeti-base-min--yeti-viewport-min处默认320px增长到--yeti-base-max--yeti-viewport-max处默认1280px比率从--yeti-ratio-min默认1.2小三度增长到--yeti-ratio-max默认1.333纯四度——宽屏上标题比正文打开得更多。完整的 Token 清单以 JSON 形式维护在 src/tokens/tokens.json并由脚本生成参考文档 docs/tokens.md。常用几组默认值TokenDefaultDescription--yeti-base-min1remBody text size at the narrow viewport.--yeti-base-max1.125remBody text size at the wide viewport.--yeti-ratio-min1.2Scale ratio at the narrow viewport (minor third).--yeti-ratio-max1.333Scale ratio at the wide viewport (perfect fourth).--yeti-space-mdstep 0Default gap; equals the body text size.--yeti-space-lgstep 1Comfortable gap.--yeti-space-xlstep 2Section gap.--yeti-text-mdstep 0Body text; h5 in bold.--yeti-text-2xlstep 3h2.--yeti-width-md32remThe columns layouts default threshold.--yeti-width-xl64remThe center layouts default maximum.尺寸名称xs sm md lg xl 2xl 3xl中的md就是基值步且同名步在间距--yeti-space-lg、文本--yeti-text-lg、圆角--yeti-radius-lg上含义一致。每个间距 Token 还有一个-static孪生如--yeti-space-lg-static供那些不能随视口缩放的特殊间隙使用。Accessible by defaultCI 里的可访问性检查默认可访问在仓库里是可验证的事实浏览器测试对每个组件都跑 axe 可访问性检查。例如 test/browser/components/button.spec.js 中有has no accessibility violations测试test/browser/base.spec.js、test/browser/color.spec.js 亦然axe 构建器来自axe-core/playwright在 package.json 的 devDependencies 中。测试辅助函数集中在 test/browser/lib/layout.js。组件层还明确了状态原生原则不发明任何状态属性所有可见状态都来自浏览器或 ARIA 已知的状态——:hover、:focus-visible、:disabled、[aria-pressedtrue]、[aria-busytrue]、:checked、:user-invalid/[aria-invalidtrue]详见 components 指南。设置状态真正含义的属性aria-pressed、required、disabled外观自动跟随无需额外脚本。Legible to agentsmanifest 驱动的生态每个组件/布局/配方目录下都有一个机器可读的 manifest.json由 schema/manifest.schema.json 约束字段包括属性attributes、类、子元素、Token、可访问性说明a11y、浏览器支持support等。文档、类型提示与 MCP 服务器都从这些 manifest 生成其校验逻辑有专门的测试保障见 test/tools/manifest.test.js。这构成了 Yeti Agent 可写标记承诺的基础AI 可以读取 manifest 理解每个组件的契约再生成合法的 HTML。组件速览三个属性、原生状态、Token 皮肤目前前八个组件button、buttons、badge、card、field、affix、table、seam已就位。组件的外观统一由三个data-*属性控制任何组件都用相同的三个名字详见 components 指南AttributeValuesRead bydata-variantprimary,secondary,success,warning,alert,neutralbutton, badge, card, fielddata-emphasishigh,medium,lowbutton, badgedata-sizesm,md,lgbutton, badge, field, table, seam其中data-variant从调色板选一个色相组件读取该色相的阶梯色ladder作为填充、边框或文字data-emphasis决定阶梯色露出多少high实心填充、medium描边或淡色、low仅文字带色data-size让文字与内边距同步缩放。组件不携带属性时使用默认值默认值通过.name:not([data-size])这类选择器设定可在按钮的 manifest.json 中看到每个属性的默认值data-variant默认primary、data-emphasis默认high、data-size默认md。组件外观的每一个视觉值都是 Token其中大部分与布局共享--yeti-color-primary、--yeti-radius-md少数属于单一组件--yeti-button-radius、--yeti-card-padding、--yeti-badge-radius、--yeti-table-stripe、--yeti-seam-size等完整清单见 docs/tokens.md。改 Token 就能改全局外观无需替换类或编写自定义 CSS。主题机制改 Token 而不是改 CSS主题化是 Yeti 的核心卖点之一。设置 Token 即主题化——所有公开 Token 都是命名规范为--yeti-group-name的自定义属性在:root上、Yeti 之后设置即可:root { --yeti-hue-primary: 160; --yeti-ratio: 1.25; --yeti-font-sans: Inter, system-ui, sans-serif; }主题机制有几个关键设计详见 theming 指南色相进颜色出颜色输入是色相--yeti-hue-primary、-secondary、-success、-warning、-alert、-neutral加一个--yeti-chroma饱和度默认0.15。Yeti 在运行时由此推导出所有颜色角色--yeti-color-primary及其-subtle/-soft/-strong/-text变体、--yeti-on-primary、页面角色--yeti-color-surface/-text/-border等明暗两套都自动推导。oklch 颜色空间颜色写作oklch(lightness chroma hue)——明度 0黑到 1白感知上均匀chroma 0 是灰、约 0.15 是清晰但不刺眼的强调色hue 是角度25 红、80 琥珀、145 绿、250 蓝、300 紫。明暗双模式:root声明color-scheme: light dark跟随访问者偏好每个颜色 Token 用light-dark()写一次。强制整页或单个面板的配色时在该元素上设置color-scheme: light或dark即可其内部全部翻转。主题文件 纯数据一个主题就是一份只含:root上的 Token 赋值、不含任何其他选择器的样式表在yeti.css之后加载。校验器会拒绝设置类、元素或未识别 Token 的主题文件这保证了主题是可移植的数据而非代码升级到新版本 Yeti 也不会破坏。仓库自带了两个完整示例主题src/themes/soft.css圆润温暖、胶囊按钮、宽松卡片和 src/themes/sharp.css方正等宽、粗边框。一个小主题就能改变很多东西:root { --yeti-hue-primary: 30; --yeti-radius-md: 1rem; --yeti-radius-lg: 1.5rem; --yeti-button-radius: var(--yeti-radius-full); }浏览器支持Baseline 2025Yeti 的目标是Baseline 2025任何在 2025 年底前进入 Baseline 的特性都无守卫地直接使用更新的特性放在supports之后并提供可用的回退。README 明确提示如果你需要支持比这更老的浏览器Yeti 很可能不适合你。贡献与许可证贡献指南见 CONTRIBUTING.md问题讨论走 Discussionsbug 与提案使用 Issue 模板。许可方面Yeti 采用 Functional Source License 1.1, MIT future licenseFSL-1.1-MIT除将其作为竞品提供外可用于任何目的的使用、复制、修改与再分发每个版本在发布两年后自动转为纯 MIT。Foundation for Sites 6 仍然保持 MIT。小结从 README.md 出发可以看到Yeti 的全部承诺——零构建、原生 CSS、命名布局、单一 Token 刻度、默认可访问、Agent 可读——都有对应的源码与测试落地层叠层声明在 src/layers.cssToken 数据源在 src/tokens/tokens.json属性词汇表在 src/layouts/attributes.css组件契约在各自的 manifest.json可访问性由 test/browser/ 下的 axe 测试在 CI 中把关。当前版本仍是7.0.0-alpha类名、属性与 Token 都可能变动但方向已经非常清晰用一份人类可读、Agent 可写的标记配合现代 CSS 原生能力把站点快速搭起来。【免费下载链接】yetiA CSS-first, native, zero-build layout and styling framework for web designers.项目地址: https://gitcode.com/gh_mirrors/fo/yeti创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进