跳转到内容

前端开发

2 篇包含标签 "前端开发" 的文章

边框灯光环绕动画特效实现指南

边框灯光环绕动画特效实现指南

Section titled “边框灯光环绕动画特效实现指南”

那个让用户一眼就注意到的重要元素,到底是怎么用纯 CSS 做出来的?其实也不难,就是绕了个弯子罢了。这篇文章带你从零开始实现边框灯光环绕动画,也顺带聊聊我们在 HagiCode 项目里踩过的那些坑。

做前端的同学应该都有过这样的经历:产品经理跑过来,脸上挂着那种”这需求很简单”的表情——“这个正在运行的任务,能不能加个特效让用户一眼就能看到?”

你说行啊,加个边框变色呗。结果对方摇摇头,眼神里透着一种”你不懂”的意味:“不够明显,要那种灯光绕着边框跑的效果,跟科幻电影里一样。”

这时候你可能就会犯嘀咕:这玩意儿怎么实现?用 Canvas?用 SVG?还是说 CSS 能搞?毕竟谁也不想承认自己不会嘛。

其实啊,边框灯光环绕动画在现代 Web 应用中特别常见,主要用在这么几个场景:

  • 状态指示:标记正在进行的任务或活跃的项目
  • 视觉焦点:突出显示重要的内容区域
  • 品牌增强:营造科技感和现代感的视觉体验
  • 节日主题:配合特殊节日创建庆祝氛围

我们做 HagiCode 的时候就遇到过这个需求——用户需要一眼看出哪些会话正在运行、哪些提案正在处理中。试了好几种方案,有些路好走一点,有些路稍微曲折一点罢了,最后沉淀出了一套还算成熟的实现思路。

本文分享的方案来自我们在 HagiCode 项目中的实践经验。HagiCode 是一个 AI 驱动的代码助手项目,在界面中大量使用边框灯光动画来指示各种运行状态。比如会话列表的运行状态、提案流程图的状态过渡、吞吐量指示器的强度显示等等。

其实这些效果说起来也不复杂,就是做的时候踩了不少坑。如果你想看看实际效果,可以访问我们的 GitHub 仓库 或者直接去 官网 了解一下,毕竟能用的才是最好的嘛。

经过对 HagiCode 代码的分析,我们总结出了下面几种核心的实现模式,每种都有它适用的场景,或者说,每种都有它存在的意义罢了。

1. Conic Gradient 旋转光晕(最常用)

Section titled “1. Conic Gradient 旋转光晕(最常用)”

这是最经典的边框灯光环绕实现方式,核心思路是用 CSS 的 conic-gradient 创建一个圆锥渐变,然后让它转起来。就像夜晚的路灯,一直在那里转啊转的。

关键要素:

  • ::before 伪元素创建光晕层
  • conic-gradient 定义渐变色分布
  • ::after 伪元素遮罩中心区域(可选)
  • @keyframes 实现旋转动画

这个适用于列表项的状态指示,在元素的一侧创建发光的细线条就行,不用整个边框都动。毕竟有时候,一点光就够了,不需要照亮整个世界。

关键要素:

  • 绝对定位的细线元素
  • box-shadow 创建发光效果
  • scaleopacity 实现呼吸动画

如果不需要环绕效果,只是想要个柔和的背景光晕,那用多层 box-shadow 叠加就够了。有些东西,简单点反而更好。

这个容易被忽略,但特别重要。所有动画都应该考虑 prefers-reduced-motion 媒体查询,给不喜欢动画的用户提供一个静态替代方案。毕竟不是所有人都喜欢动来动去的,尊重每个人的选择才是对的。

方案一:Conic Gradient 旋转边框(推荐)

Section titled “方案一:Conic Gradient 旋转边框(推荐)”

这是最完整的环绕灯光效果实现,也是 HagiCode 里用得最多的方案。毕竟,如果一样东西好用,为什么还要换呢?

/* 父容器 */
.glow-border-container {
position: relative;
overflow: hidden;
}
/* 旋转的光晕层 */
.glow-border-container::before {
content: '';
position: absolute;
top: -50%;
left: -50%;
width: 200%;
height: 200%;
background: conic-gradient(
transparent 0deg,
rgba(59, 130, 246, 0.6) 60deg,
rgba(59, 130, 246, 0.3) 120deg,
rgba(59, 130, 246, 0.6) 180deg,
transparent 240deg
);
animation: border-rotate 3s linear infinite;
z-index: -1;
}
/* 遮罩层(可选,用于创建空心边框效果) */
.glow-border-container::after {
content: '';
position: absolute;
inset: 2px;
background: inherit;
border-radius: inherit;
z-index: -1;
}
@keyframes border-rotate {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}

这个方案的原理挺简单的:创建一个比父容器大的伪元素,上面画一个圆锥渐变,然后让它不停旋转。父容器设置 overflow: hidden,所以只能看到边框那一部分的光在转。就像我们在窗子里看外面的路灯,只能看到它经过的那一小段罢了。

如果你不需要那么复杂的效果,HagiCode 里有个更轻量的工具类实现。毕竟简单点,有时候反而更好。

/* 旋转光边框工具类 */
.running-light-border {
position: absolute;
inset: -2px;
background: conic-gradient(
from 0deg,
transparent 0deg 270deg,
var(--theme-running-color) 270deg 360deg
);
border-radius: inherit;
animation: lightRayRotate 3s linear infinite;
will-change: transform;
z-index: 0;
}
@keyframes lightRayRotate {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
/* 无障碍支持 */
@media (prefers-reduced-motion: reduce) {
.running-light-border {
animation: none;
}
}

注意这里的 will-change: transform,这是告诉浏览器”这个元素要一直变”,浏览器就会提前做些优化,动画会更流畅。毕竟提前准备,总比临时抱佛脚强嘛。

列表项的状态指示用这个特别合适,HagiCode 的会话列表就是用的这个方案。一条细线,却能在众多项目中脱颖而出,这不也是一种生活哲学吗?

.side-glow {
position: relative;
isolation: isolate;
}
.side-glow::before {
content: '';
position: absolute;
left: 0;
top: 14px;
bottom: 14px;
width: 1px;
border-radius: 999px;
background: var(--theme-running-color);
box-shadow:
0 0 16px var(--theme-running-color),
0 0 28px var(--theme-running-color);
z-index: 1;
pointer-events: none;
animation: sidePulse 2.6s ease-in-out infinite;
}
.side-glow > * {
position: relative;
z-index: 2;
}
@keyframes sidePulse {
0%, 100% {
opacity: 0.55;
transform: scaleY(0.96);
}
50% {
opacity: 0.95;
transform: scaleY(1);
}
}

这里用了 isolation: isolate 创建一个新的层叠上下文,然后用 z-index 控制各层的显示顺序。pointer-events: none 也很关键,不然那个伪元素会挡住用户的点击操作。就像有些东西,好看是好看,但是不能碍事才行。

如果你项目里用 React,可以封装一个组件来处理这些逻辑,特别是无障碍访问的部分。毕竟代码写一次,用很多次,这才是我们想要的嘛。

import React from 'react';
import { useReducedMotion } from 'framer-motion';
import styles from './GlowBorder.module.css';
interface GlowBorderProps {
isActive: boolean;
children: React.ReactNode;
className?: string;
}
export const GlowBorder = React.memo<GlowBorderProps>(
({ isActive, children, className = '' }) => {
const prefersReducedMotion = useReducedMotion();
if (!isActive) {
return <div className={className}>{children}</div>;
}
if (prefersReducedMotion) {
return (
<div className={`${styles.glowStatic} ${className}`}>
{children}
</div>
);
}
return (
<div className={`${styles.glowAnimated} ${className}`}>
{children}
</div>
);
}
);

对应的 CSS 模块:

GlowBorder.module.css
/* 动画版本 */
.glowAnimated {
position: relative;
overflow: hidden;
}
.glowAnimated::before {
content: '';
position: absolute;
top: -50%;
left: -50%;
width: 200%;
height: 200%;
background: conic-gradient(
from 0deg,
transparent,
rgba(59, 130, 246, 0.6),
transparent,
rgba(59, 130, 246, 0.6),
transparent
);
animation: rotateGlow 3s linear infinite;
z-index: -1;
}
.glowAnimated::after {
content: '';
position: absolute;
inset: 2px;
background: inherit;
border-radius: inherit;
z-index: -1;
}
/* 静态版本(无障碍) */
.glowStatic {
position: relative;
border: 1px solid rgba(59, 130, 246, 0.5);
box-shadow: 0 0 15px rgba(59, 130, 246, 0.3);
}
@keyframes rotateGlow {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}

framer-motionuseReducedMotion hook 会自动检测用户的系统偏好,如果用户开启了”减弱动态效果”,就会返回 true,这时候就显示静态版本。毕竟,尊重用户的选择比强行展示更重要。

下面这些是我们在做 HagiCode 时踩过坑、总结出来的经验。其实也就是些碎碎念罢了,希望能帮到后来的你。

用 CSS 变量实现多主题支持特别方便。毕竟谁也不想每次切换主题都要改一堆代码呢?

:root {
--glow-color-light: rgb(16, 185, 129);
--glow-color-dark: rgb(16, 185, 129);
--theme-glow-color: var(--glow-color-light);
}
html.dark {
--theme-glow-color: var(--glow-color-dark);
}
/* 使用 */
.glow-effect {
background: var(--theme-glow-color);
box-shadow: 0 0 20px var(--theme-glow-color);
}

这样切换主题的时候只需要改一下 html 标签的 class,所有动画颜色都会自动更新。一套代码,两种风格,这不就是我们追求的吗?

使用 will-change 提示浏览器优化:

.animated-glow {
will-change: transform, opacity;
}

提前告诉浏览器,它就会帮你做些优化。就像生活中的很多事情,提前准备总是好的。

避免在大面积元素上使用复杂的 box-shadow:

/* 不好 - 大面积元素上使用模糊阴影 */
.large-card {
box-shadow: 0 0 50px rgba(0, 0, 0, 0.5);
}
/* 更好 - 使用伪元素限制发光区域 */
.large-card::before {
content: '';
position: absolute;
inset: 0;
border-radius: inherit;
box-shadow: 0 0 20px var(--glow-color);
pointer-events: none;
}

我们在 HagiCode 里测试过,在大卡片上直接加模糊阴影会让滚动帧率掉到 30fps 以下,改用伪元素后就稳稳 60fps 了。这种体验上的差异,用户是能感觉到的。

这个真的不能省,有些用户会觉得动画很晕或者很吵,尊重他们的选择是做产品的基本素养。毕竟美的事物不必强加于人嘛。

CSS 媒体查询:

@media (prefers-reduced-motion: reduce) {
.glow-animation {
animation: none;
}
.glow-animation::before {
/* 提供静态替代方案 */
opacity: 1;
}
}

React 中检测用户偏好:

import { useReducedMotion } from 'framer-motion';
const Component = () => {
const prefersReducedMotion = useReducedMotion();
return (
<div className={prefersReducedMotion ? 'static-glow' : 'animated-glow'}>
Content
</div>
);
};

HagiCode 里的 Token 吞吐量指示器会根据实时吞吐量显示不同颜色的灯光,这个是动态实现的。毕竟不同的状态,应该有不一样的表达方式。

const colors = [
null, // Level 0 - no color
'#3b82f6', // Level 1 - Blue
'#34d399', // Level 2 - Emerald
'#facc15', // Level 3 - Yellow
'#fbbf24', // Level 4 - Amber
'#f97316', // Level 5 - Orange
'#22d3ee', // Level 6 - Cyan
'#d946ef', // Level 7 - Fuchsia
'#f43f5e', // Level 8 - Rose
];
const IntensityGlow = ({ intensity }) => {
const glowColor = colors[Math.min(intensity, colors.length - 1)];
return (
<div
className="glow-effect"
style={{
'--glow-color': glowColor,
opacity: 0.6 + (intensity * 0.08),
}}
/>
);
};

有些细节还是要注意的,不然踩了坑才知道就晚了。

注意事项说明
z-index 管理光晕层应设置合适的 z-index,避免影响内容交互
pointer-events光晕伪元素应设置 pointer-events: none
边界溢出父容器需要设置 overflow: hidden 或调整伪元素尺寸
性能影响复杂动画在移动设备上可能影响性能,需要测试
深色模式确保发光颜色在深色背景下清晰可见
主题切换使用 CSS 变量确保主题切换时动画颜色正确更新

伪元素在开发者工具里有时候不太好找,可以临时加个边框来看看位置。

/* 临时显示伪元素边界用于调试 */
.glow-effect::before {
/* debug: border: 1px solid red; */
}

调好位置之后记得把这行注释掉或者删掉,不然生产环境会很尴尬。有些东西,还是留在开发环境比较好。

边框灯光环绕动画说难不难,说简单也不简单。核心就是 conic-gradient 加旋转,但要做到性能好、可维护、无障碍友好,还是有不少细节要注意的。

HagiCode 在这个上面踩了不少坑,也总结出了一些最佳实践。其实做项目就是这样,一遍遍试错,一遍遍改进。如果你在做类似的需求,希望这篇文章能帮你少走点弯路。

毕竟,有些东西,还是要亲自实践才知道深浅。

感谢您的阅读,如果您觉得本文有用,欢迎点赞、收藏和分享支持。 本内容采用人工智能辅助协作,最终内容由作者审核并确认。

Design.md:让 AI 一致性进行前端 UI 设计的解决方案

Design.md:让 AI 一致性进行前端 UI 设计的解决方案

Section titled “Design.md:让 AI 一致性进行前端 UI 设计的解决方案”

在 AI 辅助前端开发时代,如何让 AI 生成的 UI 保持一致性?本文分享了我们基于 awesome-design-md 构建设计画廊站点的实践经验,以及如何创建结构化的 design.md 来指导 AI 进行规范化的 UI 设计。

用过 AI 写前端代码的朋友应该都有过类似的经历:同一个页面,让 AI 多生成几次,每次的风格都不一样。有时候是圆角有时候是方角,有时候间距是 8px 有时候又变成 16px,甚至同一个按钮在不同对话里长得都不一样。

这不仅仅是个别现象。随着 AI 辅助开发的普及,AI 生成的前端 UI 缺乏一致性已经成为一个普遍问题。不同的 AI 助手、不同的提示词,甚至同一助手在不同对话中,都会产生风格迥异的界面设计。这给产品迭代带来了巨大的维护成本。

问题的根源其实很简单:缺少一份权威的设计参考文档。传统的 CSS 样式文件只能告诉开发者”怎么实现”,却无法完整传达”为什么这样设计”以及”在什么场景下使用什么设计模式”。而对于 AI 来说,它更需要一个清晰的结构化描述来理解设计规范。

与此同时,开源社区已经有了一些很好的资源。VoltAgent/awesome-design-md 项目收集了大量知名公司的设计系统文档,每个目录包含 README.md、DESIGN.md 和预览 HTML。但这些都分散在上游仓库中,难以快速查阅和比较。

那能不能把这些资源整合起来,做成一个方便查阅的设计画廊,同时沉淀出一份结构化的 design.md 给 AI 用呢?

答案是肯定的。接下来分享一下我们的方案。

本文分享的方案来自我们在 HagiCode 项目中的实践经验。HagiCode 是一个 AI 辅助开发平台,在开发过程中,我们也遇到了 AI 生成 UI 不一致的问题。为了解决这个问题,我们构建设计画廊站点并创建规范化的 design.md,本文就是这套方案的总结。

GitHub - HagiCode-org/site

先看一眼最终做出来的首页效果。首页把设计画廊入口、站点仓库、上游仓库和 HagiCode 的背景介绍收拢在同一个界面里,方便团队先建立统一上下文,再继续阅读具体条目。

Awesome Design MD Gallery 首页概览

在动手写代码之前,我们先来拆解一下这个问题的几个技术挑战。

内容源管理:如何统一分散的设计资源?

Section titled “内容源管理:如何统一分散的设计资源?”

上游的 awesome-design-md 仓库包含了大量设计文档,但我们需要一种方式把它纳入到我们的项目中。

方案:使用 git submodule

awesome-design-md-site
└── vendor/awesome-design-md # 上游资源(git submodule)

这样做有几个好处:

  • 版本可控:可以锁定特定的上游版本
  • 离线构建:不需要在构建时请求外部 API
  • 内容审阅:可以在 PR 中看到具体变更

数据标准化:不同文档结构怎么统一?

Section titled “数据标准化:不同文档结构怎么统一?”

不同公司的设计文档结构可能不同,有些缺少预览文件,有些命名不统一。我们需要在构建期进行标准化处理。

方案:构建期扫描并生成标准化条目

核心模块是 awesomeDesignCatalog.ts,负责:

  1. 扫描 vendor/awesome-design-md/design-md/* 目录
  2. 校验每个条目是否包含必需文件(README.md、DESIGN.md、至少一个预览文件)
  3. 提取并渲染 Markdown 内容为 HTML
  4. 生成标准化的条目数据
src/lib/content/awesomeDesignCatalog.ts
export interface DesignEntry {
slug: string;
title: string;
summary: string;
readmeHtml: string;
designHtml: string;
previewLight?: string;
previewDark?: string;
searchText: string;
}
export async function scanSourceEntries() {
// 扫描 vendor/awesome-design-md/design-md/*
// 校验文件完整性
// 生成标准化条目
}
export async function normalizeDesignEntry(dir: string) {
// 提取 README.md、DESIGN.md
// 解析预览文件
// 渲染 Markdown 为 HTML
}

静态站点架构:怎么在保持静态部署的同时提供动态搜索?

Section titled “静态站点架构:怎么在保持静态部署的同时提供动态搜索?”

既然是设计画廊,搜索功能是必须的。但 Astro 是静态站点生成器,怎么实现实时搜索呢?

方案:React island + URL 查询参数同步

src/components/gallery/SearchToolbar.tsx
export function SearchToolbar() {
const [query, setQuery] = useState('');
// URL 同步
useEffect(() => {
const params = new URLSearchParams(window.location.search);
setQuery(params.get('q') || '');
}, []);
// 实时过滤
const filtered = entries.filter(entry =>
entry.searchText.includes(query)
);
return <input value={query} onChange={e => {
setQuery(e.target.value);
updateURL(e.target.value);
}} />;
}

这样做的好处是保留了静态站点的可部署性(可以部署到任何静态托管服务),同时提供了即时过滤的用户体验。

设计文档化:怎么让 AI 理解并遵守设计规范?

Section titled “设计文档化:怎么让 AI 理解并遵守设计规范?”

这是整个方案的核心。我们需要创建一份结构化的 design.md,让 AI 能够理解并应用我们的设计规范。

方案:借鉴 ClickHouse DESIGN.md 的结构

ClickHouse 的 DESIGN.md 是一个很好的参考,它包含了:

  • Visual Theme & Atmosphere
  • Color Palette & Roles
  • Typography Rules
  • Component Stylings
  • Layout Principles
  • Depth & Elevation
  • Do’s and Don’ts
  • Responsive Behavior
  • Agent Prompt Guide

我们的做法是:结构参考,内容重写。保留 ClickHouse DESIGN.md 的章节结构,但把内容替换成我们自己项目实际使用的设计 token 和组件规范。

基于上述分析,我们的解决方案包含四个核心模块。

这是整个系统的基础,负责从上游资源中提取和标准化内容。

src/lib/content/awesomeDesignCatalog.ts
export async function scanSourceEntries(): Promise<DesignEntry[]> {
const designDir = 'vendor/awesome-design-md/design-md';
const entries: DesignEntry[] = [];
for (const dir of await fs.readdir(designDir)) {
const entryPath = path.join(designDir, dir);
if (await isValidDesignEntry(entryPath)) {
const entry = await normalizeDesignEntry(entryPath);
entries.push(entry);
}
}
return entries;
}
async function isValidDesignEntry(dir: string): Promise<boolean> {
const requiredFiles = ['README.md', 'DESIGN.md'];
for (const file of requiredFiles) {
if (!(await fileExists(path.join(dir, file)))) {
return false;
}
}
return true;
}

画廊界面包括三个主要部分:

首页:展示所有设计条目的卡片网格,每个卡片包含:

  • 设计条目标题和简介
  • 预览图(如果有)
  • 快速搜索高亮

详情页:聚合展示单个设计条目的完整信息:

  • README 文档
  • DESIGN 文档
  • 预览(支持明/暗主题切换)
  • 相邻条目导航

导航:支持返回画廊、浏览相邻条目

首页画廊使用高密度卡片布局,把不同来源的 design.md 条目平铺在一个统一的视觉框架里,方便快速对比品牌风格、按钮模式和排版节奏。

Awesome Design MD Gallery 设计卡片网格

进入具体条目后,详情页会把设计摘要和实时预览放在同一个页面中,减少在文档、预览和源码之间来回切换的成本。

Awesome Design MD Gallery 设计详情预览页

搜索功能基于客户端过滤,使用 URL 查询参数保持状态:

src/components/gallery/SearchToolbar.tsx
function SearchToolbar({ entries }: { entries: DesignEntry[] }) {
const [query, setQuery] = useState('');
const [results, setResults] = useState(entries);
useEffect(() => {
const params = new URLSearchParams(window.location.search);
const initialQuery = params.get('q') || '';
setQuery(initialQuery);
filterEntries(initialQuery);
}, []);
const filterEntries = (searchQuery: string) => {
const filtered = entries.filter(entry =>
entry.searchText.toLowerCase().includes(searchQuery.toLowerCase())
);
setResults(filtered);
};
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const value = e.target.value;
setQuery(value);
filterEntries(value);
// 更新 URL(不触发页面刷新)
const newUrl = value
? `${window.location.pathname}?q=${encodeURIComponent(value)}`
: window.location.pathname;
window.history.replaceState({}, '', newUrl);
};
return (
<div className="search-toolbar">
<input
type="text"
value={query}
onChange={handleChange}
placeholder="搜索设计条目..."
/>
<span className="result-count">{results.length} 个结果</span>
</div>
);
}

这是整个方案的核心输出。我们在项目根目录创建 design.md,结构如下:

除了给 AI 消费的原始 design.md 内容,我们还把 README 和 DESIGN 两份文档放进同一个阅读界面,方便人工校对、复制片段和对照预览结果。

Awesome Design MD Gallery README 与 DESIGN 文档页

# Design Reference for [Project Name]
## 1. Visual Theme & Atmosphere
- 整体风格描述
- 设计哲学和原则
## 2. Color Palette & Roles
- 主色调、辅助色
- 语义化颜色(success、warning、error)
- CSS Variables 定义
## 3. Typography Rules
- 字体家族
- 字号层级(h1-h6, body, small)
- 行高和字重
## 4. Component Stylings
- 按钮样式规范
- 表单组件样式
- 卡片和容器样式
## 5. Layout Principles
- 间距系统
- 网格和断点
- 对齐原则
## 6. Depth & Elevation
- 阴影层级
- z-index 规范
## 7. Do's and Don'ts
- 常见错误和正确做法
## 8. Responsive Behavior
- 断点定义
- 响应式适配规则
## 9. Agent Prompt Guide
- 如何将本文档用于 AI 提示词
- 示例提示词模板

了解了方案之后,具体怎么实施呢?

第一步:初始化子模块

Terminal window
# 添加上游仓库为子模块
git submodule add https://github.com/VoltAgent/awesome-design-md.git vendor/awesome-design-md
# 初始化并更新子模块
git submodule update --init --recursive

第二步:创建内容管线

实现 awesomeDesignCatalog.ts,包括:

  • 文件扫描和校验逻辑
  • Markdown 渲染(使用 Astro 的内置渲染器)
  • 条目数据提取

第三步:构建画廊 UI

使用 Astro + React Islands 创建:

  • 首页画廊布局(卡片网格)
  • 设计卡片组件
  • 搜索工具栏
  • 详情页布局

第四步:编写设计文档

基于 ClickHouse DESIGN.md 结构,填充自己项目的实际设计 token。更新 README.md,添加指向 design.md 的链接。

安全性:Markdown 渲染需要过滤不安全的 HTML。Astro 的内置渲染器默认会过滤 script 标签,但仍需注意 XSS 风险。

性能:大量 iframe 预览可能影响首屏加载。建议使用 loading="lazy" 延迟加载预览内容。

维护性:design.md 需要与代码实现保持同步。建议在 CI 中添加检查,确保 CSS 变量在文档和代码中一致。

可访问性:确保颜色对比度符合 WCAG AA 标准(至少 4.5:1)。

创建 design.md 之后,怎么让 AI 真正用它呢?这里有几个实用技巧:

技巧一:在提示词中明确引用

请参考项目根目录的 design.md 文件,使用其中定义的设计规范来实现以下组件:
- 按钮:使用 primary 色调,圆角 8px
- 卡片:使用 elevation-2 阴影层级

技巧二:要求 AI 引用具体的 CSS 变量

实现一个导航栏,要求:
- 背景色使用 --color-bg-primary
- 边框使用 --color-border-subtle
- 文字使用 --text-color-primary

技巧三:在系统提示词中包含 design.md 内容

如果你的 AI 工具支持自定义系统提示词,可以将 design.md 的核心内容直接添加进去。

内容管线测试

  • 文件缺失场景(缺少 README.md 或 DESIGN.md)
  • 格式错误场景(Markdown 解析失败)
  • 空目录场景

搜索功能测试

  • 空结果处理
  • 特殊字符(如中文、emoji)
  • URL 同步验证

UI 组件测试

  • 明/暗主题切换
  • 响应式布局
  • 预览加载状态
Terminal window
# 1. 更新子模块到最新版本
git submodule update --remote
# 2. 重新构建站点
npm run build
# 3. 部署静态资源
npm run deploy

建议将子模块更新和构建部署自动化,可以在上游仓库更新时自动触发 CI 流程。

HagiCode 在开发过程中遇到的 AI 生成 UI 不一致问题,本质上是缺少结构化的设计参考文档。通过构建设计画廊站点和创建规范化的 design.md,我们成功解决了这个问题。

这套方案的核心价值在于:

  • 统一资源:整合分散的设计系统文档
  • 结构化规范:将设计规范以 AI 可理解的形式呈现
  • 持续维护:通过 git submodule 保持内容更新

如果你也在使用 AI 辅助前端开发,建议尝试一下这个方案。创建一份结构化的 design.md,不仅能提升 AI 生成代码的一致性,也能帮助团队内部保持设计规范的统一。


如果本文对你有帮助:

感谢您的阅读,如果您觉得本文有用,欢迎点赞、收藏和分享支持。 本内容采用人工智能辅助协作,最终内容由作者审核并确认。