约 8 分钟读完 · 更新于 2026-10-21 · 文中每条都能在下面的配套工具里动手验证
没有这行 meta,手机浏览器会把页面按 980px 宽排版再缩小塞进屏幕——「整体缩小但字小得看不清」就是它的杰作。width=device-width 让布局宽度等于设备 CSS 宽度;initial-scale=1 禁止初始缩放;viewport-fit=cover 让页面延伸进刘海与圆角区域(要用安全区就必开)。这不是可选优化,是移动端适配的第 0 步。
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
CSS 里的 375px 宽度指的是设备独立像素(dip/iPhone 的 pt),物理像素 = CSS 像素 × devicePixelRatio(DPR)。iPhone 的 DPR 是 3,所以 1px 边框实际由 3 个物理像素渲染——看起来比设计稿的「1px 线」粗。理解这一点,1px 问题和图片清晰度问题都有了同一个解释框架:图片按 2–3 倍尺寸提供、CSS 按 dip 写,两条规则互不冲突。
手机浏览器的地址栏收起/展开会改变可视高度,而 100vh 恒等于「最大视口」——地址栏展开时底部会被裁掉一截。新单位修复了它:svh 是最小视口(地址栏展开时),dvh 是动态视口(随地址栏实时变),lvh 才等价旧 100vh。全屏 hero 用 min-height: 100svh 保证内容永远完整可见;需要跟随地址栏变化的吸底工具栏用 100dvh。兼容性兜底写法是先 100vh 再 100dvh。
.hero {
min-height: 100vh; /* 老浏览器兜底 */
min-height: 100svh; /* 地址栏展开时也不裁内容 */
}viewport-fit=cover 开启后,页面会画进刘海与底部手势条区域,固定定位的顶栏底栏必须让开。env(safe-area-inset-top / bottom / left / right) 给出各方向的避让距离(无刘海设备为 0),配合 max() 保证普通设备不受影响:padding-bottom: max(12px, env(safe-area-inset-bottom))。
.bottombar {
position: fixed; left: 0; right: 0; bottom: 0;
padding-bottom: max(12px, env(safe-area-inset-bottom));
}| 方案 | 写法要点 | 取舍 |
|---|---|---|
| transform 缩放 | 1px 高度伪元素 scaleY(0.5)(按 DPR) | 最精确,但多一个伪元素且圆角处麻烦 |
| box-shadow 模拟 | box-shadow: 0 0.5px 0 #ccc | 一行解决,但 DPR=1 的桌面会显示 0.5px 直接消失或加粗(浏览器而异) |
| 直接接受 1px | border: 1px solid | 最简单;DPR≥2 屏幕上略粗于设计稿,多数产品可接受 |
主流手机的 CSS 宽度集中在 360–430px,断点跳变在这条窄带里反而生硬。流式字号让数值随视口连续变化:正文 clamp(0.875rem, 0.8336rem + 0.2vw, 1rem) 在 360px 时约 14px、430px 时 16px,无需媒体查询。配合 rem 基准,用户调大浏览器字号时依然全部生效——比整站 rem 缩放方案(html { font-size: 4vw })对无障碍友好得多。工具页的 clamp() 生成器可以直接算出这一行。
100vh 等于最大视口高度(地址栏收起时),地址栏展开时实际可视高度更小。改用 min-height: 100svh(内容永远完整)或 100dvh(随地址栏动态变化),并保留 100vh 作为老浏览器兜底。
那是 DPR 放大所致。要求高就上 transform scaleY(0.5) 伪元素或 0.5px box-shadow;多数产品直接保留 1px 也可接受,先确认设计是否真的在意。
根字号随视口缩放的方案能让整站等比缩放,但会连用户浏览器字号设置一起无视,无障碍受损。更现代的组合是:根字号固定、布局用 rem、需要流式的局部用 clamp() + vw。