← 全部文章

前端窗口

一个响应式调试浮层:断点、溢出、网格标尺

DevTools 的设备模式很好用,直到它碍事:它缩小你的视口、在调整尺寸时卡顿,而且它没法告诉你哪个元素导致了那条恼人的水平滚动条。本文构建一个轻量的响应式调试浮层,你直接注入到页面上 —— 一个实时尺寸徽章、当前断点名、一个「轮廓化一切」开关、一个溢出查找器和一个列标尺。把它和 JustZix 的 CSS 面板配对,你就能在同一个窗口里发现一个 bug 并修好它。

为什么页内浮层胜过设备模式

设备模式回答「这在 375px 下看起来怎样?」 —— 但大多数响应式 bug 不是关于某个特定宽度,而是关于过渡:一个不会折叠的外边距、一张固定宽度的图片、一个拒绝收缩的 flex 子项。对那些,你想要拖动你真实的浏览器窗口,实时看着数字变化。一个注入的浮层给你这个,以原生性能,且没有占用像素的浏览器外壳。

下面的一切是一条 JS 规则。注入一次;浮层会在你调整尺寸时自己更新。

实时视口徽章

从一个固定徽章开始,它显示当前视口的宽和高,并在每次调整尺寸时更新。

(() => {
  document.getElementById('jz-resp')?.remove();

  const bar = document.createElement('div');
  bar.id = 'jz-resp';
  Object.assign(bar.style, {
    position: 'fixed', left: '10px', bottom: '10px',
    font: '12px/1.5 ui-monospace, monospace',
    background: '#111', color: '#fff',
    padding: '6px 10px', borderRadius: '6px',
    zIndex: 2147483600, pointerEvents: 'none',
    whiteSpace: 'pre',
  });
  document.body.appendChild(bar);

  function update() {
    const w = window.innerWidth;
    const h = window.innerHeight;
    bar.textContent = w + ' × ' + h + 'px  ·  ' + bpName(w);
  }
  window.addEventListener('resize', update);
  update();

徽章坐在左下角,忽略指针事件所以它永不挡住点击,并搭载一个高到足以盖过几乎任何站点的 z-index

给当前断点命名

一个原始的像素数很有用,但「我们在平板范围里吗?」才是你真正会问的问题。把宽度映射到名字 —— 调整这张表来匹配站点的框架(这些是 Tailwind 的默认值)。

  function bpName(w) {
    if (w >= 1536) return '2xl';
    if (w >= 1280) return 'xl';
    if (w >= 1024) return 'lg';
    if (w >= 768)  return 'md';
    if (w >= 640)  return 'sm';
    return 'xs';
  }

现在徽章读起来像 1024 × 768px · lg —— 而你拖过一个断点边界的那一刻,名字就翻转。那个即时反馈就是全部要点。

轮廓化每个元素

经典的「轮廓化一切」技巧暴露整个页面的盒模型 —— 你立刻看到游离的外边距、错位的列和意外的嵌套。把它做成一个开关,这样它不会碍事。

  let outlined = false;
  const styleEl = document.createElement('style');
  document.head.appendChild(styleEl);

  function toggleOutline() {
    outlined = !outlined;
    styleEl.textContent = outlined
      ? '* { outline: 1px solid rgba(255,0,0,.35) !important; }'
      : '';
  }

  // Press 'o' to toggle outlines
  window.addEventListener('keydown', e => {
    if (e.key === 'o' && !e.metaKey && !e.ctrlKey) toggleOutline();
  });

outline 而不是 border 很重要 —— 轮廓不占空间,所以切换它们不会让你正想检查的布局重排。

水平溢出查找器

这是值回整篇文章的功能。一条横向滚动条意味着某个元素比视口宽 —— 但是哪一个?遍历每个元素,标记任何右边缘越过 document.documentElement.clientWidth 的元素。

  function findOverflow() {
    document.querySelectorAll('.jz-of').forEach(n => {
      n.classList.remove('jz-of');
      n.style.outline = '';
    });

    const limit = document.documentElement.clientWidth;
    const culprits = [];

    document.querySelectorAll('*').forEach(el => {
      const r = el.getBoundingClientRect();
      if (r.right > limit + 1 || r.left < -1) {
        culprits.push(el);
        el.classList.add('jz-of');
        el.style.outline = '3px solid #f0f';
      }
    });

    console.log('%c' + culprits.length + ' overflowing element(s)',
      'color:#f0f');
    console.log(culprits);
    return culprits;
  }

  // Press 'f' to find overflow
  window.addEventListener('keydown', e => {
    if (e.key === 'f' && !e.metaKey && !e.ctrlKey) findOverflow();
  });

按下 f,每个碍事的元素都得到一道品红色轮廓;列表也落进 Output Console,这样你能检查每个节点。通常它就是一个元素 —— 一张固定宽度的图片、一个不换行的长字符串、一个负外边距 —— 而现在你精确知道是哪一个。

一个列 / 网格标尺

要检查内容是否对齐到网格,叠加均匀间隔的列。这会在视口上画一个带间隙的 12 列标尺。

  function toggleRuler() {
    let ruler = document.getElementById('jz-ruler');
    if (ruler) { ruler.remove(); return; }

    ruler = document.createElement('div');
    ruler.id = 'jz-ruler';
    Object.assign(ruler.style, {
      position: 'fixed', inset: '0',
      display: 'grid', gap: '16px',
      gridTemplateColumns: 'repeat(12, 1fr)',
      maxWidth: '1200px', margin: '0 auto',
      padding: '0 16px',
      zIndex: 2147483500, pointerEvents: 'none',
    });
    for (let i = 0; i < 12; i++) {
      const col = document.createElement('div');
      col.style.background = 'rgba(0, 120, 255, .12)';
      ruler.appendChild(col);
    }
    document.body.appendChild(ruler);
  }

  // Press 'g' to toggle the grid ruler
  window.addEventListener('keydown', e => {
    if (e.key === 'g' && !e.metaKey && !e.ctrlKey) toggleRuler();
  });
})();

maxWidthgap 和列数匹配站点实际的网格。现在你能一眼看出标题、卡片和图片是否吸附到同样的线 —— 还是偏移了几个像素。

完整的键盘映射

保留修饰键检查(!e.metaKey && !e.ctrlKey),这样快捷键不会和浏览器命令冲突。如果站点本身监听普通字母键,换成像 Alt+O 这样的。

把它和 CSS 面板配对

这个浮层告诉你什么出了错;JustZix 的 CSS 面板让你不离开标签页就修好它。工作流:

  1. 从 JS 面板注入浮层并运行它。
  2. 拖动你的窗口穿过断点,看着徽章。
  3. 看到一条滚动条出现?按 f,拿到元凶。
  4. 打开 CSS 面板,实时打补丁 —— max-width: 100%overflow-wrap: anywhere,它需要什么就给什么。
  5. 当它看起来对了,把 CSS 存进规则,让修复留下来。

另见

别再为设备模式诊断不了的 bug 与它搏斗。安装 JustZix,注入浮层,在你真实的浏览器里以全速调试响应式布局。

为这篇文章评分

暂无评分 — 成为第一个。

自己动手试试

安装 JustZix,粘贴本文中的任意代码片段。两分钟,从零到一条在你所有设备上生效的规则。

获取 JustZix

功能 · 工作原理 · 示例 · 应用场景