Phoenix LiveView 1.2 发布了。升级动作不大:从 1.1 过来,主要是把 mix.exs 里的依赖改成 {:phoenix_live_view, "~> 1.2.0"},再重新拉依赖。

真正有意思的是另一件事:LiveView 现在允许你在 HEEx 模板里就近写 CSS。组件在哪里,样式就放在哪里。听起来像现代前端框架的常规操作,但 LiveView 1.2 没有顺手把“样式隔离”默认打包送上。

这不是漏做。更像一次有意的刹车。

LiveView 1.2 到底加了什么

主角是 Colocated CSS。

LiveView 1.1 已经有 Colocated Hooks 和 Colocated JavaScript。1.2 把这条路延伸到 CSS:你可以在 HEEx 里写类似 <style :type={MyApp.ColocatedCSS}>...</style> 的样式块。

编译时,LiveView 会把这些 CSS 抽出来,放到 _build 目录下的 phoenix-colocated,再交给现有 CSS 管线处理。比如 Tailwind、Esbuild。

这点很关键。它不是另起一套样式系统,也不是绕过你原来的前端构建链。

变化具体做法对开发者的影响
升级phoenix_live_view 改到 ~> 1.2.0迁移入口很轻
Colocated CSS在 HEEx 内就近写 <style>组件样式更容易跟着组件走
编译处理CSS 抽取到 _build/phoenix-colocated继续接 Tailwind、Esbuild 等管线
样式隔离1.2 不默认启用 scoping不能当成天然 scoped CSS 用

还有一些小改进,偏工程细节。

HEEx 里的 script / style 可以通过 Phoenix.LiveView.HTMLFormatter.TagFormatter 接入自定义格式化工具。push_event 发送 Phoenix.LiveView.JS structs 时可以自动编码。HEEx 调试注解支持按模块配置。测试警告也能按类别配置。

这些都实用。但这版最该看懂的,还是 Colocated CSS 的边界。

关键限制:样式靠近了,作用域没有默认隔离

就近写 CSS 的好处很直接。

一个按钮组件、一个卡片组件、一个表单组件,样式可以和模板放在一起。维护时少跳文件。删组件时也更容易删干净。

问题也同样直接。

如果你在组件里写 p { font-weight: bold; },没有作用域边界,它可能影响页面上别的 p。代码看上去分开了,CSS 还在全局游荡。

LiveView 1.2 给出的方向是 CSS @scope

大致思路是:框架可以给模板根节点加边界标记,比如 phx-r;再给使用 scoped colocated CSS 的根元素加类似 phx-css-* 的唯一属性。这样 CSS 可以限定在某个组件范围内生效,并在边界处停止。

这个设计对 slot 场景尤其重要。

调用方传进来的内容,不应该被组件内部样式误伤。边界标记就是在告诉浏览器:谁是组件内部,谁是外部传入。

但官方没有默认 ship scoping。

原因不复杂:截至 2026 年 6 月,@scope 的浏览器支持仍不充分。LiveView 1.2 提供的是 @behaviour,让开发者自定义 scoping 策略。官方文档里有基于 @scope 的实现,适合早期采用者,但它不是默认安全带。

所以这次不能误读成“LiveView 已经给 CSS 做好了完整隔离”。

准确说法是:Colocated CSS 已经来了,默认样式隔离还没来。

该怎么用:小项目可试,组件库要慢一点

我更认可 LiveView 这次的克制。

很多框架在这种节点会选择把体验包装完整。API 漂亮,发布稿好看,示例也顺滑。浏览器兼容、编译复杂度、边界条件,留给用户在生产环境里补课。

LiveView 1.2 没这么干。

它做了底层编译调整,把 HEEx 编译拆成 tokenization 和 parsing,支撑 colocated CSS / JS 这类宏组件,也减少编译复杂度。但到了样式隔离这里,它没有替还不稳的浏览器标准背书。

“知止而后有定。”框架设计最难的,有时不是继续加功能,而是知道自己现在不能承诺什么。

代价也很清楚。克制不会让问题消失,只会把选择权交回团队。

使用场景我会怎么选主要风险
小型 LiveView 项目可以试用 Colocated CSS注意避免写过宽选择器
中后台页面适合逐步引入团队要约定命名和边界
复杂组件库不建议立刻全面迁移scoped 策略没定前,污染成本高
想用样式隔离先评估自定义 behaviour@scope 兼容性不能假装不存在

对普通 LiveView 开发者,我的建议很简单:可以升级,可以试 Colocated CSS,但别把它当 CSS Modules 或 Vue scoped CSS 的等价物。

对维护组件库的团队,动作要更慢。先定三件事:哪些组件允许 colocated CSS,哪些选择器禁止使用,是否采用文档里的早期 scoping 方案。

尤其别在复杂组件库里直接铺开全局迁移。

因为真正贵的不是写样式。是半年后没人知道某条 CSS 到底会影响哪里。

接下来最该观察的也不是“更多语法糖”。而是两个变量:浏览器对 @scope 的支持进展,以及 LiveView 社区会不会沉淀出足够稳的 scoping behaviour 实现。

如果这两个条件跟上,Colocated CSS 才会从“更顺手的组织方式”,变成“更可靠的组件边界”。

回到开头那句话:LiveView 1.2 的重点,不是终于能把 CSS 塞进 HEEx。重点是它把样式拉近组件时,没有假装边界问题已经解决。

这次少见地做对了。只是账单还在开发者手里。