一、面试题:同一个 URL,手机打开是移动端页面,电脑打开是 PC 页面,怎么实现?
1. 核心思路(一句话)
主要看移动端和 PC 端的页面差异:差异小,用响应式布局共用一套页面;差异大,服务端根据 User-Agent 等请求信息识别终端,再分别提供两套页面。
主要矛盾
不是“怎么判断设备”,而是“两个端到底应该共用多少代码”。
次要矛盾
- 屏幕尺寸怎么适配
- 是否需要不同的 HTML 结构
- 是否需要不同的 JavaScript 逻辑
- 是否需要分别部署
- 首屏性能和资源体积
- SEO 和缓存策略
二、解决方案流程图
同一个 URL │ ▼ 移动端和 PC 端差异大吗? ┌──────┴──────┐ 小 大 │ │ ▼ ▼ 共用一套页面 分开提供页面 │ │ ▼ ▼ 响应式设计 服务端识别终端 │ │ ┌──────┴──────┐ ▼ │ │ User-Agent ▼ ▼ │ CSS媒体查询 流体布局 ▼ │ │ PC / Mobile │ │ │ ▼ │ ┌───┴───┐ 少量布局差异 │ ▼ ▼ 直接调整 CSS │ PC页面 移动页面 │ │ └──────┬──────┘ ▼ 共用代码较多三、方案一:流体布局
核心思路
让页面尺寸随着视口变化,通过百分比、相对单位、弹性布局等方式自动缩放和排列。
例如:
屏幕变宽 ↓ 容器变宽 ↓ 内容跟着变宽 屏幕变窄 ↓ 容器变窄 ↓ 内容跟着变窄示例
<!DOCTYPEhtml><htmllang="zh-CN"><head><metacharset="UTF-8"/><metaname="viewport"content="width=device-width, initial-scale=1.0"/><style>/* 页面主体宽度随视口变化 */.container{width:80%;max-width:1200px;margin:0 auto;/* * 使用 Flexbox 让内部内容具备弹性布局能力。 */display:flex;gap:20px;}.sidebar{/* * 左侧固定一个相对稳定的宽度。 */width:240px;flex-shrink:0;}.content{/* * 剩余空间全部交给内容区域。 */flex:1;min-width:0;}img{/* * 图片不能超过父容器。 */max-width:100%;height:auto;}</style></head><body><divclass="container"><asideclass="sidebar">左侧菜单</aside><mainclass="content"><h1>文章标题</h1><p>页面内容随着容器宽度变化。</p><imgsrc="image.jpg"alt="示例图片"/></main></div></body></html>底层原理
流体布局本质上是:
视口尺寸 ↓ CSS布局计算 ↓ 百分比 / vw / rem / Flexbox / Grid ↓ 重新计算元素尺寸和位置 ↓ 页面随着空间变化它解决的是:
“同一套页面,在不同尺寸下怎么自然缩放和排列?”
但它不一定解决:
“手机和 PC 的页面结构、功能、交互完全不同怎么办?”
因此,不能简单把“响应式设计”等同于“所有页面只需要缩放”。
四、方案二:CSS 媒体查询
核心思路
页面和组件基本共用,只在不同屏幕条件下修改布局、尺寸、显示状态等样式。
这是实际开发中非常常见的方案。
同一份 HTML │ ▼ CSS 媒体查询 │ ┌────┴────┐ ▼ ▼ PC样式 移动端样式示例
<!DOCTYPEhtml><htmllang="zh-CN"><head><metacharset="UTF-8"/><metaname="viewport"content="width=device-width, initial-scale=1.0"/><style>/* * 默认按照移动端设计。 */.container{display:flex;flex-direction:column;gap:16px;}.sidebar{width:100%;}.desktop-only{display:none;}/* * 当视口宽度达到 768px 时, * 切换到更适合平板/PC的布局。 */@media(min-width:768px){.container{flex-direction:row;}.sidebar{width:240px;flex-shrink:0;}.desktop-only{display:block;}}</style></head><body><divclass="container"><asideclass="sidebar">菜单</aside><main><h1>商品详情</h1><!-- PC端额外展示的内容 --><sectionclass="desktop-only">PC端扩展信息</section><p>商品描述</p></main></div></body></html>底层原理
浏览器会根据当前媒体环境判断 CSS 条件是否成立:
浏览器获取视口尺寸 ↓ 匹配 @media 条件 ↓ 条件成立 ↓ 应用对应 CSS ↓ 重新计算样式和布局例如:
@media(max-width:767px){/* 移动端 */}@media(min-width:768px){/* PC / 平板 */}它的优势
如果两端:
业务逻辑相同 组件结构基本相同 数据基本相同 只有布局和少量展示差异那么:
一套 HTML + 一套 JavaScript + 少量媒体查询 CSS开发和维护成本比较低。
五、JavaScript 如何根据屏幕尺寸执行不同逻辑?
如果只是样式变化,优先使用 CSS 媒体查询。
如果确实存在:
不同屏幕尺寸需要执行不同 JavaScript 逻辑
可以使用window.matchMedia()。
示例
// 创建一个媒体查询对象。// 判断当前视口是否属于移动端。constmediaQuery=window.matchMedia("(max-width: 767px)");functionhandleViewportChange(event){if(event.matches){// 移动端逻辑console.log("当前是移动端布局");}else{// PC端逻辑console.log("当前是 PC 端布局");}}// 页面初始化时先执行一次。handleViewportChange(mediaQuery);// 当视口尺寸发生变化并导致匹配结果变化时执行。mediaQuery.addEventListener("change",handleViewportChange);六、方案三:服务端识别终端,分别提供页面
如果移动端和 PC 端已经是两套完全不同的页面,那么可以在服务端根据请求信息判断终端。
最常见的信息之一就是:User-Agent请求头。
浏览器 │ │ 请求同一个 URL ▼ 反向代理 / Web服务器 │ │ 读取 User-Agent ▼ 判断终端类型 │ ├──────────────┐ ▼ ▼ 移动端 PC端 │ │ ▼ ▼ 移动端页面 PC页面注意
User-Agent 负责提供终端识别依据;服务器可以根据判断结果直接返回对应页面,也可以选择重定向到另一个 URL。
七、服务端直接返回不同页面
例如 Node.js:
importhttpfrom"node:http";constserver=http.createServer((req,res)=>{/* * User-Agent 是浏览器发送过来的请求头。 * * 注意: * User-Agent 只能作为终端判断依据之一, * 不能把它当成绝对可靠的“设备身份证”。 */constuserAgent=req.headers["user-agent"]||"";// 这里只演示最简单的移动端判断。constisMobile=/Android|iPhone|iPad|Mobile/i.test(userAgent);res.setHeader("Content-Type","text/html; charset=utf-8");if(isMobile){// 移动端直接返回移动端 HTML。res.end(`<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>移动端页面</title> </head> <body> <h1>这是移动端页面</h1> </body> </html>`);}else{// PC端直接返回 PC HTML。res.end(`<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>PC端页面</title> </head> <body> <h1>这是 PC 端页面</h1> </body> </html>`);}});server.listen(3000);这种情况下:
https://example.com/始终是同一个 URL。
但是:
手机请求 ↓ 服务器识别 User-Agent ↓ 返回移动端 HTML PC请求 ↓ 服务器识别 User-Agent ↓ 返回 PC HTMLURL 可以完全不变。
八、如果需要跳转到移动端 URL,可以使用 302
例如:
PC: https://example.com/ 移动端: https://m.example.com/服务器判断移动端后:
HTTP/1.1 302 Found Location: https://m.example.com/浏览器收到以后,再请求:
https://m.example.com/流程:
手机 │ │ GET / ▼ 服务器 │ │ 判断 User-Agent ▼ 移动端 │ │ 302 + Location ▼ 浏览器 │ │ GET https://m.example.com/ ▼ 移动端服务器 │ ▼ 移动端页面301 和 302 的区别
301 → 永久重定向 302 → 临时重定向302 是临时重定向,301 是永久重定向。
如果只是根据当前设备临时把用户引导到另一个地址,通常不会因为“设备不同”就直接把它理解成永久迁移。
九、三种方案到底怎么选?
| 方案 | 页面关系 | 核心特点 | 适用场景 |
|---|---|---|---|
| 流体布局 | 基本同一套页面 | 尺寸随空间变化 | 页面结构非常简单 |
| CSS 媒体查询 | 高度复用 | 不同尺寸应用不同 CSS | 两端差异较小 |
| 服务端识别终端 | 可以完全不同 | 服务端决定返回哪套页面 | 两端差异较大 |
| 独立部署 | 两套应用 | 独立开发、部署、维护 | 两端业务和交互差异非常大 |
十、真正应该怎么判断?
不要简单问:
“页面复杂不复杂?”
更应该问:
“移动端和 PC 端的差异有多大?”
例如:
场景一:电商详情页
PC: 商品图片 + 商品信息 + 推荐商品 移动端: 商品图片 + 商品信息 + 推荐商品主要只是:
布局变化 字号变化 间距变化 部分内容隐藏这种情况下适合:
响应式布局 + CSS 媒体查询场景二:管理后台
PC:
左侧导航 顶部导航 多列数据表格 复杂筛选移动端:
底部导航 卡片列表 抽屉筛选 完全不同的交互如果强行使用一套 DOM:
大量 if 判断 大量 CSS 覆盖 大量移动端/PC端分支最终容易变成:
一套代码 ↓ 大量条件判断 ↓ 维护困难 ↓ 构建产物也可能包含两端不需要的代码这时候可以考虑:
PC端应用 + 移动端应用 + 公共组件 / 公共业务模块 + 服务端路由或网关进行终端分流十一、一个更合理的现代工程方案
实际项目不要简单理解成:
“移动端和 PC 端不同,就复制两份代码。”
更合理的是:
同一个业务 │ ┌────────────┴────────────┐ ▼ ▼ PC端应用 移动端应用 │ │ └────────────┬────────────┘ ▼ 公共业务层 │ ┌────────┼────────┐ ▼ ▼ ▼ API层 工具函数 公共组件这样可以做到:
页面层 → 两端独立 业务逻辑 → 尽可能复用 接口层 → 复用 工具函数 → 复用 设计 Token → 尽可能复用 基础组件 → 根据实际情况复用这样比“所有东西都共用”或者“所有东西全部复制”都更容易长期维护。
十二、边界场景
1. User-Agent 不是绝对可靠
不能简单理解成:
User-Agent = 真实设备因为:
- 浏览器可以修改 User-Agent
- 爬虫可以伪造 User-Agent
- 平板设备判断存在复杂情况
- 新设备和新浏览器可能出现新的标识
所以服务端设备识别应该设计成:
User-Agent + 设备能力 + 业务规则而不是依赖某几个字符串永久判断。
2. 不要为了隐藏几个元素就拆成两套页面
例如:
PC 多一个搜索框 移动端少一个搜索框没必要直接拆成:
PC项目 移动端项目这种场景通常:
@media(...)就足够了。
3. 不要用 JavaScript 代替 CSS 做纯样式响应式
例如:
if(window.innerWidth<768){element.style.display="none";}如果只是控制样式,这通常不如:
@media(max-width:767px){.element{display:none;}}因为:
样式问题 → CSS解决 业务逻辑问题 → JavaScript解决这是比较重要的职责划分。
十三、底层原理总结
这道题实际上涉及三个层次:
第一层:CSS布局层 ↓ 视口变化 ↓ 媒体查询 / Flexbox / Grid / 相对单位 ↓ 调整页面布局 第二层:浏览器逻辑层 ↓ window.matchMedia() ↓ JavaScript感知媒体条件变化 ↓ 执行不同业务逻辑 第三层:服务端分流层 ↓ HTTP请求 ↓ 读取 User-Agent 等请求信息 ↓ 识别终端 ↓ 返回不同HTML 或者 返回重定向响应因此要记住:
CSS 媒体查询解决的是“同一页面怎么适配不同屏幕”;
window.matchMedia()解决的是“JavaScript 是否需要感知媒体条件”;服务端分流解决的是“不同终端是否应该拿到不同的页面”。
十四、结构化逻辑思维
遇到这道题,可以按照下面的顺序回答:
① 先确认需求 ↓ 同一个 URL ↓ 手机和 PC 是否需要不同页面? ② 看差异程度 ↓ 差异小 → 共用页面 → 响应式布局 → CSS媒体查询 差异大 → 页面结构和交互都不同 → 服务端分流 → 分别提供 PC / 移动端页面 ③ 再看 JavaScript ↓ 只是样式变化 → CSS 需要不同 JS 逻辑 → window.matchMedia() ④ 再看部署方式 ↓ 差异较大 → 可以独立构建、部署两端应用 ⑤ 最后考虑工程问题 ↓ 公共代码复用 缓存 SEO 首屏性能 资源体积 维护成本十五、满分答案
同一个 URL 实现 PC 和移动端不同页面,核心看两端差异有多大。
如果两端结构和业务基本一致,只是布局、尺寸、部分内容展示不同,我会采用响应式设计,主要用 CSS 媒体查询,必要时用window.matchMedia()让 JavaScript 感知屏幕条件。
如果两端页面结构、交互甚至业务逻辑差异很大,我会考虑 PC 和移动端分别开发、构建和部署,然后由服务端或反向代理根据请求中的User-Agent等信息进行终端识别,直接返回对应页面;如果采用不同 URL,也可以通过 302 临时重定向到移动端地址。
所以这道题真正的判断标准不是页面复杂不复杂,而是 PC 和移动端的差异大小:差异小就尽量复用,差异大就适当拆分,同时把公共业务和基础能力抽出来复用。