Skip to content

DPR (Device Pixel Ratio 设备像素比)

在现代前端和跨端(小程序/App)开发中,屏幕适配是一个绕不开的话题。而这一切的核心,都建立在一个概念之上:DPR (Device Pixel Ratio)

什么是 DPR

DPR (设备像素比) 是默认缩放为 100% 的情况下,设备物理像素逻辑像素的比例。

简单来说,它表示了操作系统在一个方向上(宽度或高度),用多少个真实的屏幕发光点,来渲染一个代码里写的 CSS 像素。

计算公式:

DPR = 物理像素 (Physical Pixels) / 逻辑像素 (Logical Pixels)

核心概念解析

要真正理解 DPR,必须先搞清楚它等式右边的两个“像素”:

物理像素 (Physical Pixel / Device Pixel)

  • 本质: 屏幕硬件上真实的、最小的发光二极管(LED/OLED 像素点)。
  • 特性: 出厂即固定。我们常说的屏幕分辨率(如 1170 x 25324K)指的就是物理像素的总数。
  • 决定了: 屏幕的绝对清晰度上限。

逻辑像素 (Logical Pixel / CSS Pixel / DIP)

  • 本质: 一个虚拟的、相对的单位。在 Web 开发中,它就是你写的 px;在移动端操作系统中,它被称为 dp (Android) 或 pt ( iOS)。
  • 特性: 由操作系统定义。它的存在是为了保证同一个 UI 元素在不同高低分辨率的屏幕上,**肉眼看到的物理尺寸(厘米/毫米)基本保持一致 **。
  • 决定了: 程序员和设计师排版时的坐标系。

为什么会诞生 DPR

在 iPhone 4 (Retina 屏幕) 问世之前,DPR 统统都是 1。1 个 CSS 像素对应 1 个物理像素。

但随着屏幕技术发展,手机物理尺寸没变,但屏幕里塞进去了多一倍的物理发光点。

  • 如果依然让 1 CSS像素 = 1 物理像素,那么以前画的一个宽 44px 的按钮,在视网膜屏幕上看起来只有原来的一半大,人类的手指根本点不到。
  • 操作系统的解决方案: 引入 DPR。系统强行规定,在 Retina 屏幕上,逻辑坐标系依然不变(比如屏幕宽度还是当作 320),但底层渲染时,用 2x2 = 4 个物理像素去画这 1 个逻辑像素。这就保证了按钮“物理大小不变”,但“清晰度翻倍”。

浏览器是如何“知道” DPR 的

这是一个从硬件到软件的信息传递链:

  1. 硬件层: 屏幕面板出厂时,固化了物理分辨率和物理尺寸信息。
  2. 系统层: 操作系统(如 iOS/Android)读取硬件信息,为了保证人眼阅读的舒适度,计算并设定了一个默认的“逻辑分辨率”,并得出了当前的缩放比(DPR)。
  3. 应用层(浏览器/Webview): 浏览器向操作系统查询当前的窗口/视口信息,拿到了 DPR 的值。
  4. 生效关键: 开发者必须在 HTML 的 <head> 中写入包含 <meta name="viewport" content="width=device-width"> 的标签,告诉浏览器严格按照操作系统的逻辑宽度去排版,DPR 机制才算真正生效。

如何在代码中获取和使用 DPR

JavaScript 获取

可以直接通过 window 对象获取当前运行环境的 DPR,这在写 Canvas 绘图代码时非常重要:

js
const dpr = window.devicePixelRatio;

CSS 媒体查询匹配

可以利用媒体查询,针对不同 DPR 的屏幕应用不同的样式(常用于加载不同精度的背景图):

css
/* 针对 DPR >= 2 的高清屏幕 */
@media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 2dppx) {
  .bg-icon {
    background-image: url('icon@2x.png');
  }
}

/* 针对 DPR >= 3 的超清屏幕 */
@media (-webkit-min-device-pixel-ratio: 3), (min-resolution: 3dppx) {
  .bg-icon {
    background-image: url('icon@3x.png');
  }
}

🤔 “1px 变粗”问题

在 DPR=2 的屏幕上写 border: 1px,浏览器会用 2 排物理像素去画。在极其细腻的文字和图片对比下,这条线显得比设计师预期(真正的 1 个物理发光点宽度)要粗重笨拙。

  • 使用 CSS 伪元素结合 transform: scale(0.5)。强行将元素尺寸缩小一半,逼迫浏览器只用 1 排物理像素渲染。

🤔 高清屏下的“图片模糊”问题

一张 200x200(物理像素)的普通图片(JPG/PNG),放在宽高设置了 200px(逻辑像素)的 <img> 标签里。在 DPR=2 的屏幕上,浏览器为了填满这块逻辑区域,会强行分配 400x400 的物理发光点去渲染。像素不够,只能强行拉伸插值,导致边缘发虚、模糊。

  • 准备多套分辨率的图片(如 @2x.png, @3x.png),并配合 HTML5 的 srcset<picture> 标签,让浏览器根据当前设备的 DPR 自动下载对应的高清图。