移动端与 viewport:rem、safe-area 与 1px 高清适配
系列文章目录《JavaScript 基础与进阶笔记》前期偏基础巩固与常见面试点后续进入闭包、异步、工程化等进阶主题第 01 篇数据类型与类型判断第 02 篇变量声明与作用域第 03 篇闭包与高阶函数第 04 篇函数工厂第 05 篇this 指向与绑定第 06 篇原型与原型链第 07 篇类与继承第 08 篇JS 执行机制与异步队列第 09 篇数组常用方法第 10 篇字符串算法第 11 篇常见手写题合集上第 12 篇常见手写题合集下第 13 篇Promise 与 async/await第 14 篇数据结构基础第 15 篇垃圾回收与内存第 16 篇DOM 基础全面解析第 17 篇DOM 性能与渲染第 18 篇DOM 交互补充第 19 篇DOM 实战案例第 20 篇CSS 布局与可视化高频第 21 篇移动端与 viewport本文文章目录系列文章目录前言一、viewport 视口1.1 为什么需要 meta viewport二、移动优先与媒体查询2.1 移动优先Mobile First2.2 常用断点参考非标准三、rem / vw / em 与选型3.1 单位对照3.2 rem 适配思路3.3 100vw 与横向滚动四、clamp 流式尺寸五、safe-area 安全区域六、高清屏下的 1px 边框6.1 常见方案七、高清图与 srcset7.1 为什么需要 2x/3x 图7.2 srcset 与 sizes八、补充touch-action九、易混淆点归纳十、思考与练习总结前言第 20 篇讲了 Flex/Grid 等布局能力移动端还要解决另一层问题视口怎么定、尺寸怎么随屏幕变、刘海和底部横条怎么避开、高清屏下 1px 和图片怎么不糊。本篇按「viewport → 移动优先 → rem/vw/clamp → safe-area → 1px/高清图」展开附最小示例与面试易混点。CSS 阶段在此收束下一篇进入BOM 与浏览器 API。一、viewport 视口1.1 为什么需要 meta viewport手机浏览器默认会把页面缩小放进「布局视口」常见约 980px 宽再让用户双指缩放。不设 viewport移动端会像「缩小版桌面页」字体极小、需手动放大。metanameviewportcontentwidthdevice-width, initial-scale1.0/属性含义widthdevice-width布局视口宽度 设备屏幕逻辑宽度CSS 像素initial-scale1.0初始缩放 1:1不默认缩小maximum-scale1禁止缩放慎用影响无障碍viewport-fitcover页面可铺满全屏配合safe-area见 §五逻辑像素 vs 物理像素window.devicePixelRatioDPR 物理像素 / CSS 像素。iPhone 常见 DPR 为 2 或 3影响 1px 边框与图片清晰度见 §六、§七。二、移动优先与媒体查询2.1 移动优先Mobile First默认写小屏样式再用min-width逐步增强大屏——比「先写桌面再max-width覆盖」更易维护、CSS 更少。/* 基础手机 */.container{padding:0 16px;}.grid{display:grid;grid-template-columns:1fr;gap:12px;}/* 平板及以上 */media(min-width:768px){.grid{grid-template-columns:repeat(2,1fr);gap:20px;}}/* 桌面 */media(min-width:1024px){.container{max-width:1200px;margin:0 auto;}.grid{grid-template-columns:repeat(3,1fr);gap:24px;}}2.2 常用断点参考非标准断点典型设备 768px手机768px ~ 1024px平板≥ 1024px桌面断点应跟设计稿与内容走不必死记数值配合第 20 篇Flex/Grid做列数切换即可。三、rem / vw / em 与选型3.1 单位对照单位相对谁特点rem根元素html的font-size全站统一缩放改根字号即可整体放大em当前元素的font-size嵌套会累积组件内相对字号常用vw/vh视口宽/高的 1%随视口变100vw 易出横向滚动见 §3.3%父元素对应维度高度%常需父级有明确高度3.2 rem 适配思路思路 A固定根字号 remhtml{font-size:16px;/* 1rem 16px */}.title{font-size:1.25rem;/* 20px */}思路 B按设计稿等比常见 750 宽稿/* 设计稿 750px 宽100vw 分成 7.5 份1 份 ≈ 100px 设计稿 */html{font-size:calc(100vw / 7.5);}/* 设计稿上 32px → 0.32rem */.card{padding:0.32rem;}大屏需max-width封顶避免根字号无限变大html{font-size:calc(100vw / 7.5);}media(min-width:750px){html{font-size:100px;/* 封顶750 以上不再放大 */}}工程里常用PostCSSpxtorem把写好的px转成rem根字号由构建或上面脚本统一控制。3.3100vw与横向滚动100vw 视口包含滚动条的宽度若body已有滚动条width: 100vw的元素可能比100%略宽出现横向滚动条。/* ❌ 易在部分浏览器出现 117px 横向溢出 */.full-bleed{width:100vw;}/* ✅ 优先用百分比或 max-width: 100% */.full-bleed{width:100%;max-width:100%;}四、clamp 流式尺寸clamp(最小, 首选, 最大)在区间内随视口平滑变化常用于标题字号、间距减少写很多media。h1{font-size:clamp(1.25rem,4vw,2.5rem);}.section{padding:clamp(16px,5vw,48px);}等价理解取max(最小, min(首选, 最大))。小屏不小于 1.25rem大屏不超过 2.5rem中间随4vw变化。五、safe-area 安全区域刘海屏、底部 Home 指示条会占用可视区域。需viewport-fitcoverenv(safe-area-inset-*)metanameviewportcontentwidthdevice-width, initial-scale1.0, viewport-fitcover/.fixed-bottom-bar{position:fixed;left:0;right:0;bottom:0;padding-bottom:env(safe-area-inset-bottom,0px);padding-left:env(safe-area-inset-left,0px);padding-right:env(safe-area-inset-right,0px);}/* 同时兼容旧写法 constantiOS 11.2 前 */supports(padding:max(0px)){.fixed-bottom-bar{padding-bottom:max(12px,env(safe-area-inset-bottom));}}env()读系统安全区内边距固定底栏、全屏弹窗、沉浸式 Header 都要留足避免按钮被横条挡住。六、高清屏下的 1px 边框CSS 里border: 1px是1 个 CSS 像素DPR2 的屏上 1 CSS 像素 2×2 物理像素细线会显得偏粗。6.1 常见方案方案说明border: 0.5px部分 WebKit 支持兼容性一般transform: scaleY(0.5)伪元素画 1px 线再缩放兼容好box-shadow0 0.5px 0 #eee模拟细线/* 伪元素 scale — 面试常写 */.hairline-bottom{position:relative;}.hairline-bottom::after{content:;position:absolute;left:0;right:0;bottom:0;height:1px;background:#e5e5e5;transform:scaleY(0.5);transform-origin:0 100%;}/* DPR2 时 scaleY(0.5) → 视觉约 0.5 CSS pxDPR3 可配合 JS 设 scale */口述物理 1px 1/DPR 个 CSS 像素要在 Retina 上看起来「发丝级」需0.5px或transform 缩放。七、高清图与 srcset7.1 为什么需要 2x/3x 图同样width: 100px的imgDPR2 需要200px 宽的图片资源才清晰否则被浏览器拉伸发糊。7.2 srcset 与 sizesimgsrclogo.pngsrcsetlogo.png 1x, logo2x.png 2x, logo3x.png 3xaltLogo/!-- 响应式按视口宽度选不同资源 --imgsrcbanner-800.jpgsrcsetbanner-400.jpg 400w, banner-800.jpg 800w, banner-1200.jpg 1200wsizes(max-width: 600px) 100vw, 800pxaltBanner/Nw图片固有宽度像素。sizes告诉浏览器「这个 img **大概占多宽」以便从 srcset 里选合适文件。CSS 背景图可用媒体查询 -webkit-min-device-pixel-ratio: 2换2x资源或直接用SVG / 足够大的位图。八、补充touch-action历史上有300ms 点击延迟等双击缩放现代浏览器在正确 viewport 下大多已优化。仍可在可点击区域加button, a{touch-action:manipulation;/* 禁用双击缩放延迟保留滚动 */}九、易混淆点归纳不设 viewport→ 移动端默认缩小整页不是「自动适配」。rem看根元素em看当前元素组件内相对字号用em全站缩放用rem。100vw≠ 100%前者可能含滚动条宽度导致横向溢出。viewport-fitcover必须配合safe-area-inset否则内容进刘海区。1px 边框在 Retina 上是「粗线」问题不是 CSS bug。移动优先用min-width增强桌面优先才常用max-width覆盖。十、思考与练习1.widthdevice-width解决的是什么问题解析让布局视口宽度等于设备逻辑宽度页面按真实手机宽度排版而非默认 ~980px 缩小版。2.设计稿 750px 宽某元素设计稿上宽 150px用 rem根字号100vw/7.5怎么写解析150 / 100 1.5rem750 稿下 1rem 对应 100px 设计稿尺寸。3.为什么全屏横幅写width: 100vw有时出现横向滚动条解析100vw 含滚动条宽度可能比body内容区略宽改用width: 100%或overflow-x: hidden后者慎用可能裁切内容。4.固定底部 Tab 在 iPhone 上被横条挡住最少改哪两处解析meta加viewport-fitcover底栏padding-bottom: env(safe-area-inset-bottom)。5.DPR2 时100×100 CSS 像素的 img 至少需要多大源图才清晰解析约200×200 物理像素或 srcset 提供2x资源。总结viewportwidthdevice-width, initial-scale1是移动端基线沉浸式加viewport-fitcover。适配移动优先min-width媒体查询尺寸用rem/vw/clamp按场景选。safe-area固定底/顶栏用env(safe-area-inset-*)。高清1px用伪元素缩放或 0.5px图片用srcset / 2x匹配 DPR。CSS 与布局专题至此完结。下一篇进入BOM 核心对象window、location、navigator、history等系列第 22 篇。