高 DPI 网站(第一部分)

在未来几年,Web 设计的一个重要领域将是高 DPI。对于我们这些在 WebKit 上工作的人来说,这也将成为 WebKit 应用程序和 Dashboard 小部件的一个问题。

DPI 是什么?

DPI 代表“dots per inch”(每英寸点数),指显示器在一英寸内可以容纳的像素数量。例如,MacBook Pro 在 15 英寸屏幕上具有 1440×900 的分辨率。然而,笔记本电脑存在具有相同物理尺寸(15 英寸)但却在相同空间中塞入更多像素的屏幕。例如,我的戴尔 XPS 笔记本电脑具有 1920×1200 的分辨率。

这为什么重要?

考虑一个为 800×600 分辨率设计的网页。假设我们渲染这个网页,使 CSS 中(以及 img 标签等页面元素中)指定的像素映射到屏幕上的一个像素。

在 1920×1200 分辨率的屏幕上,该网站将非常小,占用屏幕宽度的不到 50% 和屏幕高度的一半。就绝对大小而言,文本会小得多,难以阅读。

现在这可能还不是一个大问题,但随着显示器在相同空间中塞入越来越多的像素,如果网页浏览器(或任何其他应用程序)天真地继续认为应用程序概念中的一个像素与屏幕上的一个像素相同,那么最终你会看到文本和图像变得如此之小,以至于难以轻松查看。

如何解决这个问题?

解决这个“高 DPI”问题的自然方法是自动放大内容,使其保持可读性,并易于用户查看。当然,仅仅选择一个令人满意的默认值是不够的,因为个人的偏好可能差异很大。目光敏锐的开发者可能喜欢在相同空间中打开许多窗口,但我们中的许多人希望应用程序大小或多或少保持不变,不希望为了阅读文本而眯着眼睛。

因此,解决这个问题的完整方案是允许用户界面进行缩放,并且缩放比例可由用户配置。这意味着网页内容必须可缩放,整个页面根据用户选择的放大倍数正确缩放。

CSS px 到底是什么?

大多数网站作者传统上将 CSS 像素视为设备像素。然而,随着我们进入这个整个 UI 可能被放大的高 DPI 新世界,一个 CSS 像素最终可能在屏幕上对应多个像素。

例如,如果我将缩放倍数设置为 2 倍,那么 1 个 CSS 像素实际上将由 2×2 的设备像素方块表示。

这就是为什么 CSS 中的像素被称为相对单位,因为它的值是相对于观看设备(例如,您的屏幕)的。

CSS 2.1 描述了 px 单位应如何在需要时重新缩放。

http://www.w3.org/TR/CSS21/syndata.html#length-units

缩放有什么问题?

缩放现有网页使其更容易查看具有一些直接好处。文本保持可读。图像不会变得太小而无法查看。

然而,进行简单的缩放将导致一个网页——在缩放后——看起来更糟。(例如,尝试看看当你在 Windows 的 Internet Explorer 中将操作系统 DPI 设置从 96 更改为 120 时,图像会发生什么。)这里有几个因素在起作用。

例如,对于文本,你不需要也“不应该”对其进行“缩放”。换句话说,你不会像缩放图像一样,获取每个字符的实际像素并对其进行缩放。相反,你只需使用更大的字体大小。这将允许文本在高 DPI 显示器上具有更高的细节水平,并最终越来越像你在印刷书籍中看到的文本。

对于图像,首先最重要的是你需要一个好的缩放算法。你希望图像在以相同物理尺寸渲染时,看起来与在较低 DPI 显示器上差不多好。然而,缩放现有图像的问题在于,你所做的只是保持了现状,而你本可以设计一个在这些更高 DPI 显示器上看起来更好的网站。

如何让图像看起来更好?

考虑一个常见的网站示例:使用图像来制作带有圆角和花哨背景的 UI 元素,如按钮。假设网页设计师为按钮使用了一个 50×50 像素的图像。圆角和背景在较低 DPI 显示器上可能看起来相当不错,甚至当图像按 2 倍缩放但在较高 DPI 显示器上以相同物理尺寸渲染时,也继续看起来不错。

如果你能使用 200×200 的图像呢?或者,更好的是,如果你使用的图像格式一开始就没有硬编码所有的像素信息呢?使用更高分辨率的图像(具有更多细节)或可缩放图像格式,可以创建在更高 DPI 显示器上渲染时看起来更好的图像。

SVG 登场

Safari 实际上支持 PDF 作为图像格式(Dashboard 小部件中的时钟指针就是这方面的一个例子)。然而,其他浏览器不支持这种格式。网络上可伸缩图形的公认标准是 SVG。

了解 SVG

SVG 代表可伸缩矢量图形(Scalable Vector Graphics),是一种用于将二维图像描述为矢量图形的 XML 语言。以这种方式描述图形允许创建在相同物理尺寸下,在高 DPI 显示器上看起来更好的图像。

我们 WebKit 的目标是使 SVG 成为一流的图像格式,以便它可以在任何你可能使用 PNG、GIF 或 JPG 的地方使用。换句话说,所有以下情况都应该可能:

<img src="tiger.svg"/>

div {
  background-image: url(tiger.svg)
}

li {
  list-style-image: url(bullet.svg)
}

我们目前关于以这种方式使用的 SVG 图像的想法是它们将是非交互式的(换句话说,你不能命中测试 SVG 的 DOM 内部的元素)。当 SVG 以这种方式使用时,是否应该允许脚本执行还有待商榷。

这些是我们希望解决的一些问题,因为我们认为这种 SVG 的使用与显式包含在复合 XHTML 文档中,或通过使用 <iframe> 或 <frame> 元素(其中支持脚本和交互性)包含的 SVG 非常不同。

大小很重要

除了支持像 SVG 这样的可伸缩图像格式,我们还希望让网页设计师能够继续使用他们熟悉的图像格式(如 PNG、JPG 和 GIF),同时赋予他们有条件地包含更高分辨率图像的能力。

这种方法背后的思想是,可以指定一个分辨率高得多的图像,然后仅当检测到分辨率足够高时才使用它,或者在较低 DPI 显示器上缩小它。

为了使这种方法可行,图像今天可以使用的每个地方都必须支持指定 CSS 像素尺寸,以便更高分辨率的图片可以在相同空间中渲染更多细节。(下面的示例将清楚地说明这一点。)

此外,我们希望这些方法在尚不支持高 DPI 网站的浏览器中能优雅地降级。

让我们回顾一下图像目前可以使用的所有地方。

img 元素

img 元素已经支持指定明确的尺寸,因此现在你可以指定宽度和高度,如果图像更大,它将按比例缩小。在高 DPI 系统中,如果 1 个 CSS 像素不等于 1 个设备像素,则可以渲染更多的细节。

换句话说,你如何缩放图像是基于比较设备像素而不是 CSS 像素。例如,如果你有一个 2 倍的缩放因子,一个 img 标签指定了 100 CSS 像素的宽度和高度,以及一个内部尺寸为 200×200 的图像
设备像素,那么该图像不会缩放,因为 100×2 = 200。然而,在可能没有设置任何缩放因子的较低 DPI 显示器上,200×200 的图像将正确地缩小到 100×100。

如果元素没有指定 CSS 大小,那么 <img> 元素在 CSS 像素中的大小就简单地是图像在设备像素中的大小。这将导致图像遵循缩放规则。

这种方法可以优雅地降级,唯一的缺点是较高分辨率的图片在低 DPI 显示器上加载会更慢,而这些显示器无论如何也无法渲染所有细节。

背景

对于背景,问题在于你需要能够指定背景平铺的 CSS 像素尺寸。CSS3 有一个新的属性,我们现在在 WebKit 中支持,叫做 background-size。这个属性允许你以 CSS 像素指定平铺的尺寸,因此背景也能支持更高 DPI 的图片。

如果没有指定平铺尺寸(如今天网页上的情况),则使用的尺寸是图像的 CSS 像素固有尺寸。网页上现有的背景图像将自动遵循缩放规则。

但是,一旦您可以在 CSS 像素中指定平铺大小,那么图像的缩放方式就可以使用设备像素来完成。在背景简写中使用 background-size 属性可以实现一种可降级的方法,这种方法在其他浏览器中不会出错。

例如,假设你有一个图像tiger-low.png其尺寸为 100×100,还有一个图像tiger-high.png其尺寸为 200×200。这是一个示例,说明你如何编写一个 CSS 声明,该声明可以为不理解 background-size 的浏览器使用低分辨率图像,并为理解的浏览器使用更高分辨率图像。

div {
  background: url(tiger-low.png);
  background: url(tiger-high.png) (100px 100px);
}

在上述示例中,两个声明都导致了 CSS 像素中大小相同的平铺,但在高 DPI 机器上,缩放因子为 2 时,你将能够看到高分辨率图像的所有额外细节。

不理解简写中指定的 background-size 的浏览器将丢弃整个第二个声明。理解它的浏览器将覆盖之前的背景声明。

列表项目符号

与背景一样,使用图像的列表项目符号的问题在于,在 CSS2 中你无法指定列表项目符号的大小。幸运的是,CSS3 也为这个问题提供了一个解决方案。

::marker伪元素可用于设置列表项目符号的样式。我们计划增加对该伪元素的支持,以提供对项目符号所用图像的更多控制。

一旦你可以指定标记的大小,那么与前面示例中相同的规则也适用。

li {
  list-style-image: url(bullet-low.png);
}

li::marker {
  content: url(bullet-high.png);
  width:10px;
  height:10px;
}

在上面的例子中,假设bullet-low.png是 10×10 像素,并且bullet-high.png是 20×20 像素。使用这种方法,只有当浏览器理解 CSS3 列表标记伪元素时,图像才会被更高分辨率的版本替换,因此在高 DPI 显示器上缩放时将显示更多细节。

边框图像

Safari 支持 CSS3 的 border-image 属性。这个属性基本上已经可以工作了,因为在使用了平铺的地方,平铺会缩放到与边框宽度匹配。

目前唯一悬而未决的问题是中心平铺,因为目前规范规定中心平铺不进行缩放。希望会选择某种启发式方法,根据边框宽度(例如,使用左/上边框宽度)来缩放中心平铺。这个问题可以通过仅使用 border-image 来渲染边框,并使用带有 background-size 的 background 在中心平铺高分辨率图像来解决。

条件包含

上述方法允许你混合使用低分辨率和高分辨率规则,但这种方法可能会有些混乱。此外,这种方法只适用于两种不同的图像。如果你想提供多于 2 种版本的图像,例如低/中/高图像,该怎么办?

我们为这个问题提出的解决方案是扩展 CSS 媒体查询,增加一个新的媒体查询特性:CSS 像素缩放因子。

媒体查询允许网站作者编写规则,这些规则应仅根据设备的特性(如视口宽度/高度、屏幕尺寸、屏幕 DPI 等)进行条件匹配。不幸的是,媒体查询不包括根据缩放因子进行查询的能力。为了真正理解图像将发生什么,此功能是必要的。

媒体查询

我们计划增加一项新功能,device-pixel-ratio,可以查询以了解 CSS 像素与设备像素的关系。该特性也可支持最小值和最大值版本。

然后你可以这样构造查询:

<link rel="stylesheet" media="screen and min-device-pixel-ratio: 2"
         href="highres.css"/>

借助 CSS3 媒体查询,您可以根据 CSS 像素与设备像素的像素比,构建具有完全不同 CSS 文件的网站,并根据需要包含更高分辨率的图像。

这种方法也能优雅降级,因为你可以指定低分辨率的 CSS 文件,然后在媒体查询中包含高分辨率的 CSS 文件,而这些文件将被不理解它们的浏览器忽略。

反馈

这是关于如何以一种将更高分辨率图像干净地融入现有设计的方式创建出色高 DPI 网站的初步提案。

我们欢迎您的反馈(可以在本博客或发送至 webkit-dev@opendarwin.org),并希望其他浏览器厂商也能参与此讨论,以便在该领域制定具体的标准。