能力检测与排错:@supports 让你「用新写法而不赌运气」

① 测试的是「声明」,不是「特性名」

container-type
selector(:has())
grid subgrid
color-mix()

每一块后缀的 ✓/✗ 由浏览器自己判定:这条规则块实时反映当前内核的能力。上面用的是 @supports (声明) 与 @supports selector(...) 两种形态。

/* 声明测试:最常用 */
@supports (display: grid) { … }
@supports (position: sticky) { … }
/* 逻辑组合 */
@supports (display: grid) and (not (display: subgrid)) { … }
@supports selector(:has(*)) { … }        /* 选择器支持测试(较新,参数是选择器而不是声明) */
/* 注意:@supports 只判断「语法是否被接受」,不判断实现是否有 bug 或是否部分支持 */
/* 判断不了前缀差异:老 Safari 的 -webkit- 写法需要并列写两份测试 */

② 渐进增强的三种写法

/* A. 基线 + 增强(推荐):默认样式必须自身成立 */
.bar { display: flex; gap: 8px; }
@supports (container-type: inline-size) { .zone { container-type: inline-size; } }

/* B. 新方案 + 显式降级 */
.grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }
@supports not (display: grid) { .grid > * { display: inline-block; width: 48%; } }

/* C. 特性存在时加细节,不存在也不难看(本示例里 sup 块的 ✓ 就是这个模式) */
卡片 A:Grid 版
卡片 B
卡片 C:窄屏自动堆叠

③ DevTools 的四个面板,各自回答什么问题

面板回答最有用的三个动作
Styles「哪条规则胜出、为什么」逐条取消勾选看变化;看被划掉的声明与旁边的警告图标;展开 :hover / 层名 / 优先级数字
Computed「最终计算值是多少」看盒子图(margin/border/padding/content 各层实测像素);按 Ctrl+F 搜某个属性;展开 :root 变量看解析结果
Layout「几何问题出在哪」开启 Display sticky/wrap/scroll overflow containers;看 Grid overlay 与轨道尺寸;调试溢出与塌陷
Rendering「性能与状态」Paint flashing(绿闪=重绘)、Layers(合成层数量)、Emulate CSS prefers-reduced-motion / prefers-color-scheme
/* 三个不装插件就能做的动作:
   ① Elements 面板右键元素 → State… 强制 :hover/:focus/:checked(比反复悬停截图可靠);
   ② Styles 面板右上角 ⋮ → Show all user-agent styles,看默认样式表;
   ③ Network 面板禁用缓存 + DevTools 设置里关掉扩展,排除「缓存/插件造成的假象」。 */

④ 常见坑现场:四个可复现的盒子

A · 百分比高度不生效:父级没有确定高度时 height: 100% 会退化成 auto。

height:100% —— 现在只包住文字
/* 修法(择一):给父显式高度;或父用 grid/flex 并靠 stretch;
   或整条链都用 min-height;或用容器查询单位(20a)与 svh/aspect-ratio 表达「占满」 */
B · 一行长内容把容器撑破:这段文字没有空格也无法折行,会直接溢出父级 —— 修法是 min-width: 0(Flex 子项)、overflow-wrap: anywhere(长 URL)、或 overflow: hidden(兜住但会裁)。
C · 会被压缩的 flex 项
D · 内容很宽的兄弟项:它的下限是 min-content,所以左边再窄也压不下去 → 给需要的项写 flex-shrink: 0 或 min-width: 0

出现意外的横向滚动条 → 依次排查:① 负 margin 或 width: 100vw(100vw 含滚动条宽度,会永远比容器宽);② 未换行的长串(URL、代码);③ position: absolute 的元素跑到外面;④ white-space: nowrap 的容器。

定位办法:在 Console 里 document.querySelectorAll('*') 过滤 el.scrollWidth > el.clientWidth,或逐个 outline 描边(见下方)。滚动条本身可用 scrollbar-gutter: stable 预留,避免弹层出现时页面抖动。

⑤ 临时描边:一行 CSS 定位结构问题

这个块里的每个后代都被 .debug * { outline: 1px dashed … } 描了边
看到「谁比想象中宽/高」最快,比逐条注释代码快得多
/* 排查用的临时样式(只写在 DevTools 里,不要提交): */
* { outline: 1px dashed rgba(255,0,0,.3); }
img { background: #ff0; }                  /* 看图片实际渲染尺寸 */
[style] { border: 2px solid red; }          /* 揪出内联样式 */

⑥ 排错决策树

  1. 样式完全没变 → 选择器没命中(Styles 面板里根本没有这条):查拼写、查 DOM 结构、查是否被 content-visibility / 影子 DOM 隔离;再查文件有没有加载、有没有缓存。
  2. 命中了但被划掉 → 优先级或书写顺序问题(第四章):权重、!important、层(第十六章)、后写覆盖先写。
  3. 生效了但尺寸不对 → 盒模型与包含块(第六、九章):查 box-sizing、塌陷、min-width、百分比基准。
  4. 位置不对 → 定位参考系(第十二章):查最近的已定位祖先、查祖先 transform、查 sticky 的 overflow。
  5. 层级不对 → 层叠上下文(第十二 + 十六章):从目标往上找最近的上下文祖先,只在这一层比 z-index。
  6. 只在某浏览器不对 → @supports 检查该特性是否被「接受但未正确实现」,并用 DevTools 关掉实验性 flag 复现。
  7. 只有真机不对 → 视口单位与 svh/dvh(第五章)、安全区 env(safe-area-inset-*)、以及 hover/pointer 媒体查询(第十三章)。

⑦ 上线前的四件事

这个盒子演示「强制状态」调试:悬停它变蓝,也可以在 DevTools 里用 State 面板勾选 :hover 达到同样效果。