前言前两周我用 Makepad 做了一个 JSON 查看器。功能跑通了文件能打开树能展开折叠搜索能跳转。自己用着挺爽。然后给一个前端朋友看了截图。他回了句“功能感觉还行但这界面……你是还没开始写 CSS 对吧”我愣了一下。确实。全程只调了flow、align、width、height。颜色没管字体没调间距全默认。界面能跑但看起来就像一个程序员半夜两点的临时作品。这一期就是从那句话开始的。Makepad 没有 CSS。样式系统是另一套东西。但不代表你只能做出 demo 感。我把调界面的过程捋了一遍先吃透布局再搭一套简陋但够用的设计系统最后用 before/after 展示怎么把 demo 调出产品感。1. 先把布局模型吃透1.1 Makepad 的布局不是 Flexbox如果你从 Web 背景过来看到flow: Down、align: Center这些词第一反应肯定是这不就是 flex-direction align-items 吗。像但不是。关键差异有三个。第一没有独立的尺寸轴控制。CSS 里justify-content管主轴、align-items管交叉轴两个维度可以独立设置。Makepad 里align同时控制两个方向的子元素对齐颗粒度更粗。第二没有margin。控件之间的间距主要靠spacing属性它作用于容器上控制所有子元素之间的统一间距。View { flow: Down, spacing: 12, // 所有子元素之间 12px 间距 align: Center, }CSS 里你可以给每个元素单独设margin-bottom: 8px或margin-right: 16px。Makepad 里不行。间距是容器级别的所有子元素一视同仁。第三width: Fill的行为和flex: 1不一样。Fill的意思是撑满父容器剩余的全部空间但它不会像 flex-grow 那样按比例分配。如果有两个Fill子元素它们的行为取决于flow方向——在Down流中第一个 Fill 会先占满第二个可能没空间。这些差异刚开始会让你很挫败。我前两个小时一直在找Makepad 的 margin 怎么设最后发现它就是没有。1.2 三个属性搞定 80% 的布局但挫败之后我发现一件事因为可调的属性少所以你反而更快。Makepad 布局的核心就三个属性属性作用常用值flow排列方向Down,Rightalign子元素对齐Center,Start,Endwidth / height尺寸Fill,Fit, 具体数值配合spacing子元素间距和padding内边距基本布局都能出来。一个典型的做产品感的页面大概是这样的嵌套View { // 根容器 flow: Down, align: Start, padding: { top: 24, bottom: 24, left: 24, right: 24 }, spacing: 16, // 标题区 View { flow: Right, align: Center, spacing: 12, Icon { ... } Label { text: JSON 查看器 } View { width: Fill } // 占位弹簧把后面的元素推到右边 Button { text: 打开文件 } } // 内容区 View { width: Fill, height: Fill, flow: Right, spacing: 0, // 左侧树 View { width: 280, ... } // 右侧内容 View { width: Fill, ... } } // 底部状态栏 View { flow: Right, align: Center, Label { text: 共 120 个节点 } } }注意那个View { width: Fill }的占位弹簧用法。因为没有justify-content: space-between你要在中间塞一个空的Fill元素把后面的按钮推到右边。很土。但能用。1.3 嵌套 View 是你的主要武器没有 margin。没有 gap。没有 flex-grow 的比例分配。那复杂布局怎么做嵌套 View。就这一招。每个需要和别人不太一样的区域包进一个独立View在这个 View 上设自己的flow、align、spacing、padding。这个思路和 Flutter 的一切皆 Widget很像只是 Makepad 里你的唯一武器是View。比如一个常见的图标 标题 副标题 右侧操作按钮的行布局// 这一行不能用简单的 flow:Right align:Center 搞定 // 因为标题和副标题是垂直排列的右侧按钮要对齐到行顶部 View { flow: Right, align: Start, spacing: 12, padding: {left: 16, right: 16, top: 12, bottom: 12}, Icon { ... } View { // 中间文字区标题上、副标题下 flow: Down, spacing: 4, Label { text: 文件名.json } Label { text: 120 个节点 · 3.2 KB } } View { width: Fill } // 弹簧 Button { text: ... } // 更多操作 }2. 建立一套迷你设计系统布局对了下一步是颜色和字体。这是 demo 感和产品感之间最大的一道坎。2.1 把所有硬编码的颜色抽出来Makepad 里颜色是直接写在控件上的Label { text: 标题 draw_text: { color: #333333, font_size: 16.0 } }小项目这样没问题。但当你有 20 个 Label、15 个 Button、10 个 View 背景色的时候散落的色值会让你调一次主题色改几十个地方。我的做法用 Makepad 的 live DSL 变量能力把颜色和字号统一定义在顶部// 设计系统变量 // 主色 color_primary: #4A90D9, color_primary_hover: #357ABD, // 文字色 color_text_primary: #1A1A2E, color_text_secondary: #6B7280, color_text_disabled: #9CA3AF, // 背景色 color_bg_page: #F9FAFB, color_bg_card: #FFFFFF, color_bg_hover: #F3F4F6, // 边框 color_border: #E5E7EB, // 字号 font_size_title: 20.0, font_size_body: 14.0, font_size_caption: 12.0, // 间距 spacing_xs: 4, spacing_sm: 8, spacing_md: 16, spacing_lg: 24, // 圆角 radius_sm: 4, radius_md: 8, radius_lg: 12,然后控件引用变量Label { text: 标题 draw_text: { color: (color_text_primary), font_size: (font_size_title) } } View { draw_bg: { color: (color_bg_card), border_radius: (radius_md) } }这一套做法不是 Makepad 官方推荐的但我在几个小项目里用了之后发现调主题快了很多。改一次色值全局生效。跟 CSS 变量的思路一模一样。2.2 字体层级不要超过 4 级我做 JSON 查看器的时候一开始用了 6 种字号。标题、小标题、正文、代码、标注、状态栏。看起来很精细实际上全是视觉噪音。后来砍成 3 级层级字号用途标题18-20页面标题、区块标题正文14主要内容、列表项、按钮文字辅助12说明文字、时间戳、状态标签整个界面干净了不止一个档次。如果你和我一样没有设计背景一个很实用的原则是先只用 2 级字号正文辅助等真的需要第三级再加。大多数时候你会发现两级就够了。2.3 颜色一个主色 一套灰度配色是最容易调过头的。我的原则很简单1 个主色管按钮、链接、选中态。1 个主色的 hover 变体比主色深 10-15%。4 级灰度——文字主色、文字次色、背景、边框。语义色红/绿/黄能不加就不加。4 级灰度是我踩出来的。少于 4 级区分不了主文字和次文字多于 4 级灰色会发脏偏蓝或偏紫。color_text_primary: #1A1A2E, // 深灰接近黑但更柔和 color_text_secondary: #6B7280, // 中灰辅助信息 color_bg_page: #F9FAFB, // 极浅灰页面底色 color_border: #E5E7EB, // 浅灰边框这套灰度偏冷带一点蓝底比纯中性灰看着更干净。想要暖一点可以用#F5F0EB方向看产品调性。3. 常见demo 感问题及修复下面是我从自己项目里揪出来的 demo 感问题。3.1 控件全部贴边窗口边缘到第一个控件的距离为 0。内容像贴在玻璃上。修法根容器加padding至少 16px。// ❌ 之前 View { flow: Down, // 没有 padding内容贴边 Label { text: 标题 } Button { text: 操作 } } // ✅ 之后 View { flow: Down, padding: { left: 24, right: 24, top: 20, bottom: 20 }, spacing: 16, Label { text: 标题 } Button { text: 操作 } }3.2 没有视觉层级所有文字一样大、一样粗、一样颜色。不知道先看哪。修法至少区分标题和内容。标题大一号或颜色重一点。// ❌ 之前标题和内容一样 Label { text: 文件列表, draw_text: { font_size: 14.0, color: #333 } } Label { text: data.json, draw_text: { font_size: 14.0, color: #333 } } // ✅ 之后标题 18px 深色内容 14px Label { text: 文件列表, draw_text: { font_size: 18.0, color: (color_text_primary) } } Label { text: data.json, draw_text: { font_size: 14.0, color: (color_text_primary) } }3.3 间距不均匀有的地方挤有的地方空。随手调的感觉很重。修法间距只用预设变量别写魔法数字。// ❌ 之前到处都是不同的间距值 View { spacing: 7, ... } View { spacing: 13, ... } View { spacing: 22, ... } // ✅ 之后只有 4/8/16/24 四档 View { spacing: (spacing_sm), ... } // 8 View { spacing: (spacing_md), ... } // 16 View { spacing: (spacing_lg), ... } // 243.4 背景全白没有区块感所有内容在同一个纯白背景上。信息没分组糊成一团。修法卡片背景 浅灰底色把信息块分开。// ❌ 之前全白 View { flow: Down, spacing: 16, Label { text: 设置 } Label { text: 主题暗色 } Label { text: 语言中文 } } // ✅ 之后卡片分组 View { flow: Down, spacing: (spacing_lg), padding: (spacing_md), draw_bg: { color: (color_bg_page) }, // 页面灰色底色 // 第一组外观设置 View { flow: Down, spacing: (spacing_sm), padding: (spacing_md), draw_bg: { color: (color_bg_card), border_radius: (radius_md) }, Label { text: 外观 } Label { text: 主题暗色 } } // 第二组语言设置 View { flow: Down, spacing: (spacing_sm), padding: (spacing_md), draw_bg: { color: (color_bg_card), border_radius: (radius_md) }, Label { text: 语言 } Label { text: 当前中文 } } }3.5 按钮像一行字没有背景色没有内边距没有圆角。看起来就是个 Label。修法背景色 横向 padding 圆角三样缺一不可。// ❌ 之前 Button { text: 保存 } // ✅ 之后 Button { text: 保存 draw_bg: { color: (color_primary), border_radius: (radius_sm) } draw_text: { color: #FFFFFF, font_size: (font_size_body) } padding: { left: 20, right: 20, top: 8, bottom: 8 } }4. before/after一个真实的调优案例下面是我那个 JSON 查看器的主界面调之前和调之后的关键差异。调之前demo 感Window { body : { View { flow: Down, View { // 顶部栏 flow: Right, Button { text: 打开 } Button { text: 展开全部 } Button { text: 折叠全部 } } TextInput { } // 搜索框 List { } // 文件树 Label { text: 120 个节点 } // 状态栏 } } }问题没有 padding、按钮挤在左上角、搜索框和工具栏没有视觉分隔、状态栏贴在最底部没有底边框、所有文字一样大。调之后产品感Window { body : { View { flow: Down, spacing: 0, draw_bg: { color: (color_bg_page) }, // 顶部工具栏 View { flow: Right, align: Center, spacing: (spacing_sm), padding: { left: (spacing_lg), right: (spacing_lg), top: 12, bottom: 12 }, draw_bg: { color: (color_bg_card) }, Label { text: JSON 查看器, draw_text: { font_size: (font_size_title), color: (color_text_primary) } } View { width: Fill } Button { text: 打开文件 } Button { text: 展开全部 } Button { text: 折叠全部 } } // 搜索栏 View { padding: { left: (spacing_lg), right: (spacing_lg), top: (spacing_sm), bottom: (spacing_sm) }, draw_bg: { color: (color_bg_card) }, TextInput { width: Fill, placeholder: 搜索节点... } } // 分割线一个 1px 高的 View View { width: Fill, height: 1, draw_bg: { color: (color_border) } } // 内容区文件树 View { width: Fill, height: Fill, padding: (spacing_md), List { } } // 底部状态栏 View { flow: Right, align: Center, spacing: (spacing_md), padding: { left: (spacing_lg), right: (spacing_lg), top: 8, bottom: 8 }, draw_bg: { color: (color_bg_card) }, Label { text: 共 120 个节点 · 3.2 KB, draw_text: { font_size: (font_size_caption), color: (color_text_secondary) } } } } } }改动看起来很多其实全是前面说的那几件事加了 padding、分了卡片区域、建立了颜色和字号变量、用 1px View 做分割线、按钮加了背景色。调完之后我自己都惊了。同样的功能和控件只是把视觉参数统一了一下整个界面直接从技术预览版变成了能给人看的工具。5. 几个 Makepad 特有的技巧5.1 用 1px View 做分割线因为没有border-bottom分割线就是在两个区域之间塞一个 1px 高的 ViewView { width: Fill, height: 1, draw_bg: { color: (color_border) } }5.2 用空 View 做弹簧需要space-between效果时中间塞View { width: Fill }View { flow: Right, align: Center, Label { text: 左侧 } View { width: Fill } // 弹簧 Button { text: 右侧 } }5.3 卡片圆角 微妙阴影感Makepad 的draw_bg支持border_radius。虽然没有 box-shadow但可以用一个微妙的背景色差异卡片比页面背景稍亮来产生层次感color_bg_page: #F3F4F6, // 页面底色稍深灰 color_bg_card: #FFFFFF, // 卡片底色纯白 // 卡片浮在灰色页面上自然产生层次5.4 hover 态别忘了交互反馈按钮和可点击的行一定要加 hover 态。不然用户点的时候没有任何反馈会觉得界面卡。Button { draw_bg: { color: (color_primary), color_hover: (color_primary_hover), border_radius: (radius_sm) } }列表行也类似——至少加个 hover 背景色变化。总结这一期不讲新 API只讲一件事怎么把你已有的界面从 demo 调成产品。如果你只想记住三个操作根容器加 padding至少 16px。贴边是 demo 感的第一来源。建立颜色和字号变量。不要到处写#333和14.0统一管理。用卡片 分割线做信息分组。全白背景是 demo 感的第二来源。这三个操作做完你的 Makepad 界面至少能达到可以给人看的水平。不需要设计天赋只需要纪律。下一期我准备做一期实战用 Makepad 从头做一个完整的小工具JSON 查看器或 Markdown 预览器把前六期所有内容串起来。从需求拆解到页面结构到代码组织完整走一遍。