前言
前两周我用 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,Right |
align | 子元素对齐 | Center,Start,End |
width / 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 高的 View:
View { 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 预览器),把前六期所有内容串起来。从需求拆解到页面结构到代码组织,完整走一遍。