兼容 Retina 的网页设计

苹果在近期宣布的 Retina(视网膜)屏幕的 MacbookPro,其屏幕的分辨率达到之前产品的两倍之多,这是苹果在为下一代显示标准开始铺路了。在 2010 年,iPhone 4 让我们尝到了“非 Retina”的网页,而直到 New iPad 发布之后,我们才意识到那些过时的图像在这两者上变得多么的模糊不清。

在苹果自身的生态范围内,在统一的 SDK 和详细的说明文档帮助下,主流的应用都及时更新适配了 Retina 屏幕。相比之下,网页是开放的,其受众极为广泛,因此在适配 Retina 的过度中显得极为缓慢和困难。在没有行业标准的情况下,每个网页设计师和开发者唯一要做的就是确保用户无论再怎样的显示器上都可以获得最佳的体验。

在一头冲进这些令人烦恼的小点(像素)之前,让我们先来介绍一些基本的概念,以此来了解为不同分辨率的显示器设计时需要面对的挑战和约束。

设备像素

设备像素(或者物理像素)是显示器上最小的物理单位。每个像素的颜色和亮度都由操作系统发出,由于像素简极为细小的间距以至于肉眼很难察觉,所以我们看到的图像是一个连贯的整体。


分辨率是指在设备屏幕上所包含的像素数量。它主要是通过像素密度(PPI)来衡量的。为了迎合市场,苹果将其双密度显示器称为“Retina(视网膜)”技术,再这样的屏幕上,肉眼是无法分辨屏幕上的像素点的。

CSS 像素

CSS 像素是一个用在浏览器上抽象单位,它通过浏览器来解读并将内容绘制在网页上。通常情况下,CSS的像素是参考了与设备无关(Device-Independent)的像素(DIPs)的。对于标准密度的显示器,1 CSS 像素等于 1 设备像素。

<div height="200" width="300"></div>

这段代码将使用 200×300 的设备像素来绘制。但是在 Retina 显示器上,同样的 div 则会使用 400×600 的设备像素来进行绘制,以此保证绘制出元素的物理尺寸保持一致。Retina 会使用四倍之多的像素来绘制,如下图所示。

在 Retina 显示器上,绘制同样大小的元素需要使用四倍的设备像素。

设备像素和 CSS 像素的比例可以使用下面的媒体查询(mediaquery)和特定的供应商来获得。

device-pixel-ratio,
-o-device-pixel-ratio,
-moz-device-pixel-ratio,
-webkit-device-pixel-ratio {
… 
}

或者你也可以使用这些比较有保障的:

device-pixel-ratio,
-o-min-device-pixel-ratio,
min--moz-device-pixel-ratio,
-webkit-min-device-pixel-ratio {
…
}

在 JavaScript 中,window.devicePixelRatio 也可以获得相同的比例,但是浏览器对此的支持也是有限的。这两种技术将会在文章后面进行深入讨论。

位图像素

位图像素是栅格图片(PNG,JPG,GIF 等)中最小的数据单位。每一个像素都包含了显示信息,包括这个像素在图片中的坐标以及颜色。一些图片格式可以为每个像素储存更多的数据,比如不透明度(即 Alpha 通道)。

除了栅格分辨率,图片在网页上有一个以 CSS 像素为单位的抽象尺寸。浏览器在渲染图片的时候,会根据图片在 CSS 中规定的高度或宽度来挤压或者拉伸。

当图片全尺寸显示在一个标准密度的显示器上的时候,1 位图像素对应 1 设备像素,这样输出的结果即为高保真的。因为位图是不可细分的,为了显示相同物理大小的图像,Retina 显示器需要以四倍的像素进行渲染,这样以来,图片的细节就是严重丢失。

每个位图像素都被放大了四倍填充在 Retina 的显示器上。

工具箱

即使这样重大的转变兑现而言还尚早,但是对于优化 Retina 的网页显示技术却如雨后春笋般的涌现,就在我们讨论这期间,不知道又多了多少新的技术。但是每个方法在某种程度上对于浏览器性能和易用性以及跨浏览器支持都产生了妥协。因此,应当根据个人定量和定性的情况来挑选。

使用 HTML 和 CSS 调整尺寸

兼容Retina显示器最简单的方法就是通过 HTML 和 CSS,手动输入或者通过程序添加,将你的栅格资源压缩为原来的 50%。例如,一张 200×300 像素(记住,这里说的是 CSS 像素)的图片,你需要上传到服务器的位图分辨率应该是 400×600px,然后通过 CSS 属性或者 HTML 属性来将尺寸设置为 50%。在标准密度的显示器中,输出的结果是完整位图大小的 1/4,这个过程通常被称为缩减像素采样。

CSS 调整过的图片在渲染过程中尺寸减少了一半。

相同的图片,在 Retina 屏幕上显示的时候会使用四倍多的物理像素,而要显示高保真的图片,每个位图像素只能对应一个物理像素。

还有一些其他的方法:

使用 HTML

调整图片最简单的方法莫过于在 img 标签中使用 widthheight

<img src="example@2x.png" width="200" height="300" />

要注意,即使指定高度是可选的,但是浏览器加载的时候人会为其预留出空间,以防止图片加载时改变页面的排版。

应用环境:有少量图片的单页面网站。

使用 JavaScript

使用 JavaScript 也可以得出同样的结果,将兼容 Retina 屏幕的图像的尺寸减半。在 jQuery 下是这样的:

$(window).load(function() {
    var images = $('img');
    images.each(function(i) {
        $(this).width($(this).width() / 2);
    });
});

**应用环境:**有少量图片的网站。

使用 CSS(SCSS)

如果你希望应用到所有的网页中,最常用的方法就是将图片设为一个 HTML 元素(div)的背景,然后指定其背景的尺寸(background-size)。如果 HTML 元素已经被指定了大小,你还可以设置背景图片的宽高值,或者内容尺寸。但值得注意的是,背景尺寸(background-size)不支持 IE 7 或者 IE 8。

.image {
    background-image: url(example@2x.png);
    background-size: 200px 300px;
    /* Alternatively background-size: contain; */
    height: 300px;
    width: 200px;
}

你也可以使用伪元素 :before 或者 :after 来代替:

.image-container:before {
    background-image: url(example@2x.png);
    background-size: 200px 300px;
    content:'';
    display: block;
    height: 300px;
    width: 200px;
}

这种技术同样适用于 CSS 精灵,只要 background-position 相对于 CSS 尺寸指定了值(本案例中为 200×300 px)

.icon {
    background-image: url(example@2x.png);
    background-size: 200px 300px;
    height: 25px;
    width: 25px;

    &.trash {
        background-position: 25px 0;
    }

    &.edit {
        background-position: 25px 25px;
    }
}

在使用 CSS 精灵的时候,应当考虑各操作系统的限制

**应用环境:**使用了有限的 background-image 的网站,通常是使用了一张单独图片的作为 CSS 精灵。

HTML 和 CSS 调整的好处

  • 轻松维护
  • 跨浏览器兼容

HTML 和 CSS 调整的弊端

  • 非 Retina 显示器的设备需要下载更大的资源
  • 由于不同的屏幕算法,缩减像素采样同样也会丢失一些图片的细节

Background-size 属性不支持 IE 7 和 IE 8.

查询像素密度

目前比较流行的兼容 Retina 显示器网页图像技术是通过查询设备像素密度。然后再调用相应的资源。这种技术同样可以使用 CSS 和 Javascript。

使用 CSS 媒体查询(media query)

目前为止,几个主要的浏览器都是用了带前缀的属性,比如 device-pixel-ratio 和他的两兄弟 min-device-pixel-ratio 以及 max-device-pixel-ratio。这些媒体查询可以和 background-image 属性一同用来兼容 Retina 显示器以及高像素密度的显示器:

.icon {
    background-image: url(example.png);
    background-size: 200px 300px;
    height: 300px;
    width: 200px;
}

@media only screen and (-Webkit-min-device-pixel-ratio: 1.5),
only screen and (-moz-min-device-pixel-ratio: 1.5),
only screen and (-o-min-device-pixel-ratio: 3/2),
only screen and (min-device-pixel-ratio: 1.5) { 
    .icon {
        background-image: url(example@2x.png);
    }
}

使用比例为 1.5 而不是 2,你可以同样兼容那些同等水平非苹果的设备。

**应用环境:**任何可以使用 background-image 属性的网站和应用。不适用于内容图片。

CSS 媒体查询的益处:

  • 任何设备都只会下载适配的素材
  • 跨浏览器支持
  • 精确的像素控制

CSS 媒体查询的弊端:

  • 难以维护,特别是在大型的网站上
  • 使用背景来代替内容图片在HTML 语义上是不正确的。

使用 Javascript

屏幕的像素密度也可以在 Javascript 中使用 window.devicePixelRatio 来查询,效果和在 CSS 中使用的相同。但显示器是高分辨率的时候,你就是随时将图片替换为兼容 Retina 显示器的:

$(document).ready(function(){
    if (window.devicePixelRatio > 1) {
        var lowresImages = $('img');
        images.each(function(i) {
            var lowres = $(this).attr('src'); 
            var highres = lowres.replace(".", "@2x.");
            $(this).attr('src', highres);
        });
    }
});

Retina.js 是一个实现同样效果的 JavaScript 插件,实现技术和上文提到的大致相同。一个额外的功能就是可以跳过有 @2x元素的图片。

不过,应该注意的是,devicePixelRatio不能完全兼容所有浏览器

**应用环境:**任何有图片的网站,目标页面或者博客。

JavaScript 查询的益处:

  • 轻松维护
  • 非Retina 显示器不会下载较大的素材
  • 精确的像素控制

JavaScript 查询的弊端:

  • Retina 设备将会同时下载标准和高分辨率图像
  • 会在 Retina 设备上看到图片被切换的效果
  • 不支持一些主流的浏览器(比如 IE 和 Firefox)

可缩放矢量图形(SVG)

无论使用什么方法,栅格图像依然受到位图的限制;他们不能无限的放大。而这是矢量图形的优势,也是未来在 Retina 网页应用中的发展趋势。

在撰写本文时,基于 XML 的 SVG 格式的矢量图形已经有超过 70% 的浏览器支持了,而且也很多使用方法。SVG 图像可以在多个矢量图象编辑器中创建,比如 Adobe Illustrator 以及免费的替代品—— Inkscape

对于网页设计而言,最简单的使用方法莫过于直接在 HTML 的 img 标签中调用,或者在 CSS 中使用 background-images 或者在内容中使用 url() 属性。

<img src="example.svg" width="200" height="300" />

如上所示,一个 SVG 图像就可以作为一个通用的素材,达到无限缩放的需求。这不仅节省了带宽(多数 SVG 文件会比标准分辨率的 PNG 图片体积更小),也是的你的图片素材更容易维护。如果可以应用在 CSS 中:

/* Using background-image */
.image {
    background-image: url(example.svg);
    background-size: 200px 300px;
    height: 200px;
    width: 300px;
}

/* Using content:url() */
.image-container:before {
    content: url(example.svg);
    /* width and height do not work with content:url() */
}

如果你需要兼容 IE 7,IE 8 或者 Android 2.x,那么你还需要一个将 SVG 和 PNG 互换的解决方案。你可以使用 Modernizr 来轻松完成:

.image {
    background-image: url(example.png);
    background-size: 200px 300px;
}

.svg {
    .image {
        background-image: url(example.svg);
    }
}

为了更好的兼容各浏览器,避免在 Firefox 和 Opera 中出一些让人头疼的栅格化,要确保每个 SVG 图片的尺寸都不小于其父元素(HTML)。

在 HTML 中,你可以通过自定义一个 data 属性来当作一个备用的解决方案:

然后继续在 jQuery 和 Modernizr 中处理:

$(document).ready(function(){
    if(!Modernizr.svg) {
        var images = $('img[data-png-fallback]');
        images.each(function(i) {
            $(this).attr('src', $(this).data('png-fallback'));
        });
    }
});

不过这样做,并不能防止不支持 SVG 的浏览器下载 SVG 素材文件。

**应用环境:**任何网站和应用。特别是图标、Logo 和简单的矢量图形。

SVG 的益处:

  • 一张图解决所有设备的兼容问题
  • 轻松维护
  • 前瞻性:可无限缩放的矢量图形

SVG 的弊端:

  • 因为抗锯齿而没有精确的像素大小
  • 由于文件体积,无法适用于复杂的图形
  • 无法原生支持 IE 7 和 IE 8 以及早期的 Android 版本

图标字体(IconFonts)

在 Twitter 的 Bootstrap 的推广下,基于图标的字体可以使用 @font-face 的技术,并以其不受分辨率影像的特性,创造一个用来替代位图图标的方法。这项基于网络字体的技术,通过使用单色图标来替换掉字母表来创建一个新的字体,并且可在CSS中使用样式,就像普通的字体一样。

现在,网络上有很多高质量的图标字体,总有一款可以满足你的需要。有人说,当你只需要其中几个字符但是要载入整个字体是很不爽的。所以你也可以考虑使用 FontelloFont Builder 或则 Inkscape 来建立自己的字体。

在网站上使用图标字体最常用的方式是把一个 .icon 或者 .glyph 指定给一个特定的 HTML 元素——通常是 <span> 或者 <i> 然后使用所需的图标来对应字母。

<span class="icon">a</span>

使用 @font-face 你可以这样声明:

.icon {
    font-family: 'My Icon Font';
}

另外一种方法是为每个类的元素使用伪元素 :before 和 content 属性

<span class="glyph-heart"></span>
[class^="glyph-"]:before {
    font-family: 'My Icon Font';
}

.glyph-heart:before {
    content: 'h';
}

**应用环境:**拥有大量图标的网站和应用,以及原型图中。

图标字体的益处:

  • 前瞻性:可无限缩放的矢量图形
  • 跨浏览器兼容
  • 比图片更加灵活:可以使用在文本和表单中

图标字体的弊端:

  • 因为抗锯齿而没有精确的像素大小
  • 难以维护,即使更改一个图标也需要重新生成整个字体
  • 语义上不正确(除非是用伪元素 :before 或者 :after

Favicons

Favicons 现在也得到很大的关注度,他们正在很多浏览器,比如Chrome作为展示网站的图标。如果你想要兼容Retina显示器,那么需要到处 16- 和 32- 两个版本。如果你在使用Mac,你可以通过苹果的 Icon Composer(已经内置在了 Xcode 的图像工具中),或者你也可以使用第三方付费的 Icon Slate

未来愿景

除了上面介绍的技术外,一些独立的组织和个人也都在为此而努力,苹果就在去年介绍了自己的 -webkit-image-set 属性。这个属性允许在一个图片元素中存在多个文件,你可以在CSS 中这样声明:

.image {
    background-image: -Webkit-image-set(url(example.png) 1x, url(example@2x.png) 2x);
    background-size: 200px 300px;
}

但是这相机是就像它自身声明的那样,仅支持 webkit 内核的浏览器。

<div data-picture>
    <div data-src="example.png"></div>
    <div data-src="example@2x.png" data-media="(min-device-pixel-ratio: 1.5)"></div>

    <!-- Fallback content for non-JS browsers -->
    <noscript>
        <img src="example.png" >
    </noscript>
</div>

另外一个值得注意的是 Scott Jehl 的 Picturefill 插件,通过HTML和JavaScript使重度使用data 属性的媒体查询变得更快捷。

如果你只是处理几个图片,虽然说会有点延迟,但是它却不失为一个不错的跨浏览器解决方案。

最后,多数人提议使用 picture 元素,通过多张图片来解决响应式图片,然后根据访问的设备给出相应的图片素材。

结语

就象其他行业一样,网页也在发生着重大改变,这件事一段漫长的过程。作为网页设计和开发人员,我们可以坐等所有的标准被一一公布,或者我们可以开始思考如何为用户带来更棒的视觉体验。动手吧!

作者:Reda Lemeden
**翻译:**Max Cheung
原文链接:Towards A Retina Web