news 2026/10/13 3:22:28

网页在电脑上正常,手机却挤成一团?CSS 响应式布局实战|AI 编程第 8 课

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
网页在电脑上正常,手机却挤成一团?CSS 响应式布局实战|AI 编程第 8 课

前几课,我们做出了一个效率工具箱:番茄钟可以计时,待办清单支持搜索和筛选,便签能够自动保存。

功能已经能用,但还需要检查一个问题:

当页面变窄时,它是否依然方便使用?

电脑上的空间很充足,输入框、下拉框和按钮可以排成一行。到了手机上,同一行可能出现这些情况:

输入框被挤得很窄 按钮文字换行 任务内容把删除按钮推到屏幕外 页面出现横向滚动

这一课,我们通过 CSS 调整布局,让工具箱根据可用宽度重新排列。

本课接着修改第六课的工具箱,也兼容第七课独立的待办页面。主要修改样式,已有 JavaScript 继续负责计时、任务操作和保存。

先明确我们希望得到的效果:

区域较宽的页面较窄的页面
页面容器居中显示,限制最大宽度跟随屏幕宽度,保留少量边距
新增任务输入框和按钮横向排列输入框与按钮上下排列
搜索与筛选多个控件按空间排列每个控件独占一行
任务文字正常显示长文字可以换行
操作按钮保持合适尺寸空间不足时换行
番茄钟数字使用较大的字号随页面宽度调整字号

这种根据可用空间改变排版的做法,就是响应式布局。

先打开你的 HTML 文件,检查<head>中有没有这一行:

<meta name="viewport" content="width=device-width, initial-scale=1.0" >

第六、七课的代码已经包含它,保留一份即可。

它告诉移动浏览器按照设备的 CSS 像素宽度设置视口,帮助窄屏布局规则正常工作。否则,某些移动浏览器可能先用一个较宽的虚拟视口排版,再把整个页面缩小。参考:MDN viewport

这里不要添加禁止用户缩放的设置。页面排版应适应宽度,读者也应该能够放大文字。

接下来,找到原有的<style>,把下面这段 CSS追加到里面的末尾、</style>之前。

这段代码使用前几课已有的 ID 和类名。

/* 统一计算元素宽度 */ *, *::before, *::after { box-sizing: border-box; } /* 外部边距由页面容器管理 */ body { margin: 0; padding: 0; } /* 同时适配工具箱和第七课的独立页面 */ .app, .standalone { width: 100%; max-width: 900px; margin: 0 auto; padding: 24px 16px; } /* 卡片允许在窄屏内收缩 */ .panel, #tasks-panel { min-width: 0; max-width: 100%; } /* 标题和状态文字允许换行 */ .app header h1 { font-size: clamp(22px, 5vw, 28px); line-height: 1.4; } #timer-overview, #timer-status, #task-summary, #task-view, #task-status, #note-status { overflow-wrap: anywhere; } /* 主要输入控件和按钮保留操作空间 */ .app button, #tasks-panel button, .app input[type="text"], .app input[type="search"], .app input[type="number"], #tasks-panel input[type="text"], #tasks-panel input[type="search"], #tasks-panel select { min-height: 44px; font-size: 16px; } /* 文本输入框允许收缩 */ #tasks-panel #task-input, #tasks-panel #task-search, #tasks-panel .search-field { min-width: 0; max-width: 100%; } /* 导航按可用空间排列 */ #tool-nav { display: flex; flex-wrap: wrap; gap: 10px; } #tool-nav button { flex: 1 1 120px; min-width: 0; white-space: normal; overflow-wrap: anywhere; } /* 番茄钟字号随视口宽度调整 */ #clock { font-size: clamp(40px, 12vw, 64px); line-height: 1.2; } /* 长任务文字可以收缩和换行 */ #tasks-panel .task span { min-width: 0; overflow-wrap: anywhere; } /* 删除按钮保留自己的空间 */ #tasks-panel .task .danger { flex-shrink: 0; } /* 便签始终跟随容器宽度 */ #note-editor { width: 100%; min-width: 0; max-width: 100%; min-height: 240px; font-size: 16px; line-height: 1.8; } /* 当视口宽度不超过 480 CSS 像素时调整排版 */ @media (max-width: 480px) { .app, .standalone { padding: 16px 12px; } .panel, #tasks-panel { padding: 16px; border-radius: 12px; } /* 三个导航按钮尽量均分一行 */ #tool-nav { gap: 8px; } #tool-nav button { flex: 1 1 0; padding: 10px 6px; font-size: 14px; } /* 新增任务改成上下排列 */ #tasks-panel #task-form { display: flex; flex-direction: column; align-items: stretch; gap: 10px; } #tasks-panel #task-input { flex: none; width: 100%; } #tasks-panel #task-form > button { width: 100%; } /* 搜索、状态筛选和清除按钮各占一行 */ #tasks-panel .task-tools { display: grid; grid-template-columns: minmax(0, 1fr); gap: 12px; align-items: stretch; } #tasks-panel .task-tools > div { min-width: 0; } #tasks-panel #task-search, #tasks-panel #task-filter, #tasks-panel #reset-view { width: 100%; } /* 任务行:勾选框、任务文字、删除按钮 */ #tasks-panel .task { display: grid; grid-template-columns: 24px minmax(0, 1fr) auto; align-items: start; gap: 10px; } #tasks-panel .task span { padding-top: 8px; } #tasks-panel .task .danger { padding: 10px; } /* 番茄钟和便签操作按钮允许换行 */ .app .actions { display: flex; flex-wrap: wrap; gap: 10px; } .app .actions > button { flex: 1 1 120px; } .app .note-actions #note-count { flex: 1 1 100%; } #clock { margin: 24px 0; } }

保存文件,刷新页面,再逐渐缩小浏览器窗口。

你应该能观察到:页面宽度较大时,保留横向排列;当视口宽度不超过 480 CSS 像素时,新增任务和筛选区域变成上下排列。

480 是本例选择的布局断点,不是手机型号的判断标准。

如果在你修改后的页面里,按钮到 520 像素宽时就已经拥挤,可以把断点调整到 520。选择断点的依据,是内容什么时候需要重新排列。

接下来拆开看几个容易忽略的细节。

首先是页面容器:

.app, .standalone { width: 100%; max-width: 900px; margin: 0 auto; padding: 24px 16px; }

width: 100%让容器跟随可用宽度。

max-width: 900px限制它在大屏幕上继续变宽。

margin: 0 auto让它居中。

再配合:

box-sizing: border-box;

容器的边距和边框会计入指定宽度,减少“宽度已经是 100%,加上内边距后又超出”的问题。

其次是min-width: 0。

不少新手会遇到这样的现象:已经设置了弹性布局,输入框或文字区域还是不肯缩小。

在某些 Flex 和 Grid 布局中,元素的默认最小宽度会受内容影响。给需要收缩的元素设置:

min-width: 0;

可以允许它缩到比内容默认最小宽度更窄,再交给换行规则处理文字。参考:MDN min-width

例如任务行里的文字:

#tasks-panel .task span { min-width: 0; overflow-wrap: anywhere; }

这两行配合使用,能处理一长串没有空格的英文、路径或网址。

你可以添加下面这条任务进行检查:

检查VeryLongFileNameWithoutSpacesAndMoreCharacters1234567890

也可以试试:

https://example.com/a/very/long/path/without/convenient/breaks

overflow-wrap: anywhere允许在需要时把长字符串拆到下一行,避免撑开容器。参考:MDN overflow-wrap

它适合任务说明和状态提示。如果以后展示需要保留格式的代码块,则应单独决定是否使用横向滚动。

然后看窄屏下的任务行:

grid-template-columns: 24px minmax(0, 1fr) auto;

它把一行分成三部分:

勾选框 任务文字 删除按钮 固定空间 使用剩余空间 按内容占用空间

中间的minmax(0, 1fr)允许文字区域收缩,长内容向下换行。

这样,删除按钮仍然留在任务右侧,不需要跟着长文字跑到屏幕外。

不过,按钮文字也会影响布局。如果以后把“删除”改成“永久删除这条任务”,右侧需要的空间会明显增加。按钮文案应与实际空间一起检查。

再看手机上的搜索区域。

上一课使用 Flex 布局,允许搜索、下拉框和按钮根据空间换行。

本课在较窄页面里明确改成一列:

#tasks-panel .task-tools { display: grid; grid-template-columns: minmax(0, 1fr); }

同时让里面的控件占满这一列:

#tasks-panel #task-search, #tasks-panel #task-filter, #tasks-panel #reset-view { width: 100%; }

这样,用户可以看到完整的搜索框和状态选项,不需要在很窄的控件里操作。

番茄钟数字则使用:

font-size: clamp(40px, 12vw, 64px);

这表示字号在 40px 到 64px 之间,根据视口宽度取合适值。

对于这个项目,数字仍然突出,同时减少窄屏上的空间占用。

不要通过隐藏页面横向溢出,直接掩盖布局问题。

如果一发现横向滚动,就给整个页面加上:

overflow-x: hidden;

超出的内容可能只是被裁掉了,按钮仍然可能留在可见范围之外。

应先找到撑开页面的元素,检查固定宽度、最小宽度、长字符串和子元素布局。

接下来用浏览器检查适配效果。

在 Windows 上的 Chrome 中打开页面,按F12打开开发者工具,再按Ctrl + Shift + M切换设备工具栏。

选择 Responsive 模式,手动调整宽度。设备模式可以模拟视口和部分移动设备行为,但不能完全替代真实手机测试。参考:Chrome 设备模式

建议检查下面几组宽度:

视口宽度主要检查内容
320px最窄情况下,输入框和删除按钮是否仍可操作
375px导航文字、任务行和便签是否拥挤
480px窄屏规则是否生效
481px断点外的布局是否依然自然
768px横向排列是否合理
1024px容器是否居中、宽度是否受限

除了空页面,还要加入真实内容测试:

  • 添加一条接近输入上限的任务。
  • 添加没有空格的英文任务。
  • 输入一条较长网址。
  • 搜索不存在的任务,检查空结果提示。
  • 在便签里输入多行文字。
  • 切换三个工具,检查隐藏区域是否正常。
  • 用键盘 Tab 键移动焦点,检查焦点提示是否可见。

如果页面出现横向滚动,还可以在开发者工具的 Console 中执行:

document.documentElement.scrollWidth > document.documentElement.clientWidth

返回true,说明根元素的可滚动宽度大于可见宽度。它是排查线索,还需要继续找到具体元素。

可以用下面这段代码列出超出视口左右边界的元素:

const viewportWidth = document.documentElement.clientWidth; const overflowElements = [ ...document.querySelectorAll("body *") ].filter(element => { const rect = element.getBoundingClientRect(); return rect.width > 0 && ( rect.left < -1 || rect.right > viewportWidth + 1 ); }); console.log(overflowElements);

这里留出 1 像素容差,减少小数尺寸造成的干扰。

输出列表里的元素不一定都是错误,例如你主动设计的滑动区域也可能超出。但对于本课工具箱,可以用它寻找需要调整的输入框、容器或任务行。

如果新增 CSS 没有效果,优先检查:

现象检查方向
搜索区域仍然挤在一行是否放进了正确的媒体查询,视口是否满足条件
输入框依然很窄是否还有旧的flex或宽度规则覆盖它
页面整体缩小是否存在正确的 viewport 标签
长任务仍然撑出屏幕文字元素是否匹配到min-width和换行规则
新样式显示为被划掉是否被优先级更高或更晚的规则覆盖
所有工具同时显示是否仍保留第六课的[hidden]隐藏规则

让 AI 帮你调整时,可以把需求描述得具体一些:

我的效率工具箱包含番茄钟、待办清单和便签。

在 375px 视口下,搜索框太窄,长任务把删除按钮推到了屏幕外。

请检查容器宽度、Flex/Grid 子元素的最小宽度和文字换行。

窄屏时让新增任务和搜索筛选上下排列,并保留可见的键盘焦点。

请指出要追加或替换的 CSS,并给出检查步骤。

如果在真实手机上测试,还要留意屏幕键盘弹出后的使用情况。

另外,手机里的127.0.0.1指向手机自身,不能直接打开电脑上绑定该地址的本地服务器。现阶段可以先用浏览器设备模式检查布局;第十课会讲静态页面发布,让工具箱拥有可以访问的网页地址。

下一课,待办清单能运行,为什么还会误删、丢数据?JavaScript 状态管理与故障测试实战|第 9 课进阶篇

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/13 3:22:13

Burp Suite入门第一章:获取工具

Window11系统 第一步&#xff1a;配置JAVA环境 官方下载链接&#xff1a;Download Java 按照路径找到文件位置并复制 打开设置&#xff0c;搜索“高级系统设置”&#xff0c;点开“环境变量”&#xff0c;点击“系统变量”板块的“新建”&#xff0c;在“变量名”位置填写“J…

作者头像 李华
网站建设 2026/10/13 3:21:23

systemd timer Persistent=true 深度解析:时间戳机制与补跑逻辑

用 systemd timer 管理计划任务的人&#xff0c;迟早都会碰到一个叫Persistenttrue的选项。早晚而已。最常见的剧本是这样的&#xff1a;你写了一个每天凌晨 2 点跑的备份 timer&#xff0c;头天晚上合盖关机&#xff0c;第二天上午开机一看&#xff0c;备份没跑。于是你开始翻…

作者头像 李华
网站建设 2026/10/13 3:21:15

降AI后专业术语连贯性怎么保

降AI改稿之后&#xff0c;同一个专业术语在摘要、正文和结论里被换成了好几种说法&#xff0c;全文口径对不上&#xff0c;这是不少研究生遇到的真实困扰。我们围绕「术语连贯性保持」这一单项能力做了逐项评估&#xff0c;发现知学术AIPaperGPT在术语基准固定与跨段口径统一两…

作者头像 李华
网站建设 2026/10/13 3:20:38

Codex 接上 API 能回复,为什么一跑真实仓库就断?15分钟验收法

很多人测试 API 中转时&#xff0c;只问一句“你好”&#xff0c;收到回复就认为线路可用。 但 Codex 真正修改仓库时&#xff0c;还要连续经历&#xff1a;读取项目、长上下文、SSE 流式返回、工具调用、执行测试、失败重试和用量结算。短问答成功&#xff0c;只能证明最短链路…

作者头像 李华
网站建设 2026/10/13 3:20:33

工控软件配置管理:分层外置、默认值合并、热更新,一次设计对

工控软件配置管理&#xff1a;分层外置、默认值合并、热更新&#xff0c;一次设计对 先说结论&#xff1a;配置管理做错的代价&#xff0c;通常不是"程序起不来"&#xff0c;而是**“程序在客户现场按错误参数安静地跑”**——地址连到隔壁线、单位差 1000 倍、超时短…

作者头像 李华
网站建设 2026/10/13 3:20:11

随机数生成器全面指南:PRNG、CSPRNG与工程选型

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华