浏览 AI 使用教程
操作教程

Codex响应式测试怎么做:别只看375像素和1440像素

从 768px 和 1121px 规则构造相邻宽度矩阵,用完整 Playwright 脚本检查溢出、导航对齐与菜单开关;保留几何检查的误报和覆盖边界。

Codex项目开发与自动化工作流主视觉
本文目录 · 跳到当前步骤

375px 和 1440px 都正常,不能排除中间断点坏掉。先读 CSS 规则,再选断点前一像素、断点本身、后一像素;菜单展开状态也需要进入矩阵。

使用有明确故障的输入

先从截图定位教程复制完整 nav-demo.html。它有两个关键条件:max-width:768px 切换手机菜单,width:1121px 故意把文章链接下移 14px。

本练习用 390、767、768、769、1024、1120、1121、1122、1440 九个宽度,高度统一 800 CSS 像素。390/767/768 都测菜单收起和展开,共 12 个状态。这里的宽度是布局视口,不是手机硬件像素。

完整检查脚本

在独立练习目录运行 npm init -y、npm install playwright,然后 npx playwright install chromium。已有项目优先使用锁定的依赖。保存下面为 check-responsive.mjs:

js
import fs from 'node:fs';
import path from 'node:path';
import {pathToFileURL} from 'node:url';
import {chromium} from 'playwright';

const file=process.argv[2]||'nav-demo.html';
const out=process.argv[3]||'responsive-report';
if(fs.existsSync(out))throw Error('Choose a new report directory');
fs.mkdirSync(out,{recursive:true});
const browser=await chromium.launch({
  headless:true,
  ...(process.env.PW_CHANNEL?{channel:process.env.PW_CHANNEL}:{})
});
const page=await browser.newPage({deviceScaleFactor:1});
const rows=[];
try{
 for(const width of [390,767,768,769,1024,1120,1121,1122,1440]){
  await page.setViewportSize({width,height:800});
  await page.goto(pathToFileURL(path.resolve(file)).href);
  await page.evaluate(()=>document.fonts.ready);
  const states=width<=768?['closed','open']:['desktop'];
  for(const state of states){
   if(state==='open')await page.locator('#menu-toggle').click();
   const measured=await page.evaluate(()=>{
    const root=document.documentElement;
    const links=[...document.querySelectorAll('nav a')].map(a=>{
     const r=a.getBoundingClientRect(),style=getComputedStyle(a);
     if(!r.width||!r.height||style.visibility==='hidden')return null;
     const top=document.elementFromPoint(r.x+r.width/2,r.y+r.height/2);
     return {text:a.textContent,top:r.top,right:r.right,left:r.left,
       hit:top===a||a.contains(top),transform:style.transform};
    }).filter(Boolean);
    return {
     overflow:root.scrollWidth>root.clientWidth+1,
     visibleLinks:links.length,
     topSpread:links.length?Math.max(...links.map(x=>x.top))-Math.min(...links.map(x=>x.top)):null,
     offscreen:links.filter(x=>x.left<0||x.right>root.clientWidth+1).map(x=>x.text),
     blockedCenters:links.filter(x=>!x.hit).map(x=>x.text),
     expanded:document.querySelector('#menu-toggle').getAttribute('aria-expanded'),
     links
    };
   });
   const expectedCount=state==='closed'?0:3;
   rows.push({width,state,...measured,
    expectedCount,
    aligned:state==='closed'?null:measured.topSpread<=1,
    countMatches:measured.visibleLinks===expectedCount
   });
   await page.screenshot({path:path.join(out,width+'-'+state+'.png'),fullPage:true});
  }
 }
}finally{await browser.close();}
fs.writeFileSync(path.join(out,'report.json'),JSON.stringify(rows,null,2));
const failures=rows.filter(r=>r.overflow||r.offscreen.length||r.blockedCenters.length||!r.countMatches||r.aligned===false);
console.log(JSON.stringify({states:rows.length,failures},null,2));
process.exitCode=failures.length?1:0;

运行 node check-responsive.mjs nav-demo.html report-before。故障版预期只有 1121/desktop 的 topSpread=14、aligned=false,最终退出码为 1;不能因为无横向滚动就说通过。删掉教学故障规则后,用新目录 report-after 再运行,预期 12 个状态无上述失败。

脚本可通过 PW_CHANNEL 使用已安装的受支持浏览器通道;默认使用 Playwright Chromium。环境安装失败、浏览器未启动时属于“未执行”,不能填零缺陷。

告诉 Codex 哪些是产品期望

text
按文章脚本执行故障前后检查,保留实际 JSON 与截图。
检查 768 附近菜单数量和 aria-expanded,1121 附近链接对齐。
再把“文章”临时换成“文章与项目实操长标题”,另跑一次独立报告,不覆盖基线。
对每个失败回到截图和元素定位,说明是否真影响点击/阅读;最终恢复本次临时长文案。
只修本例错位规则,不用 overflow:hidden 掩盖内容,不为通过测试删除入口。

对齐断言是此导航的设计要求,不适合强套所有多行卡片。长标题允许换行的导航也不能再要求所有行 top 相同,需改为可见、可点击和容器内换行等规则。

两个常见误判

父容器与子链接矩形重叠是正常包含关系,不能把任何相交都报遮挡。本脚本只在链接中心做命中测试,并允许命中其子元素。中心可点仍不代表整个按钮每个位置都可点,透明遮罩、滚动后 sticky 状态、键盘焦点还需专门检查。

截图的手机视口也不等于真机。触摸、软键盘、移动浏览器工具栏和字体可能不同;Playwright 设备模拟说明列出了视口、触摸、UA 等独立配置。此处只做一个本地页面、九种宽度、菜单开关的回归,不应写成“全站所有设备通过”。

下一步

继续阅读与你当前问题相关的教程: