8.响应式网页设计(responsive web design & mobile first)

为什么是移动设备优先?(mobile first)

(1)随着移动设备的普及,移动设备的通信量及使用频率已经极大的超过传统的PC设备;
(2)传统的桌面浏览器优先的(desktop-first)响应式的设计会导致小型设备中网页的加载速度很慢,因为即使我们通过CSS媒体查询根据不同的屏幕宽度去适配了不同的样式文件。但是存在一个问题,那就是在小型设备中,当加载一些图片的时候,这些图片仍然是那些原本准备给桌面浏览器使用的图片,而实际上,小型设备根本不需要如此高清晰度的图片(高清晰度意味着图片容量更大),这就造成了带宽浪费以及网页加载缓慢的问题;这也涉及到一个原则:We don’t want anyone to have download extra data that they won’t even use.We want to build efficient websites that load as quickly as possible for everyone.这也是为什么移动设备优先的原因。

那么实际开发中如何构建移动设备优先的网站呢?

具体来说,就是在进行项目开发时,以移动设备屏幕宽度为基准进行默认样式的设置,然后使用媒体查询,当设备屏幕变大时,再应用其他的样式。

在进行移动设备优先的CSS样式设计时,Mixins能够有效的帮助我们复用样式代码,那么首先我们应当通过NPM在项目文件中引入mixin插件来支持。

npm install postcss-mixins --save-dev

然后通过var mixins = require(postcss-mixins);引入,并将其添加到postCSS([])的数组中。

gulp.task("styles",function(){ 
	return gulp.src("./app/assets/styles/styles.css")
		.pipe(postcss([cssImport, mixins, cssvars, autoprefixer, nested]))
		.on("error",function(errorMessage){ 
			console.log(errorMessage.toString());
			this.emit("end");
		})
		.pipe(gulp.dest("./app/temp/styles"));
});

然后,我们在项目文件中新建一个_mixins.css用于存放媒体查询的代码:

@define-mixin atSmall {
    @media (min-width: 530px) {
        @mixin-content;
    }
}

@define-mixin atMedium {
    @media (min-width: 800px) {
        @mixin-content;
    }
}

@define-mixin atLarge {
    @media (min-width: 1200px) {
        @mixin-content;
    }
}

并在主样式文件中通过@import "base/_mixins"引入,之后就可以在其他样式表中去添加媒体查询代码了,例如:

.large-hero {
    position: relative;
    

    &__text-content {
        width: 100%;
        position: absolute;
        top: 50%;
        left: 0;
        transform:translateY(-50%);
        text-align: center;
    }

    &__title {
        font-weight: 300;
        color: $mainBlue;
        font-size:1.1rem;
        margin: 0;

        
        @mixin atSmall {
            font-size: 4.8rem;
        }
        
        @mixin atMedium {
            font-size: 8.8rem;
        }

        @mixin atLarge {
            font-size: 10.8rem;
        }
    }
}

响应式图片(responsive images)

1.不同屏幕设备中图片加载的两个问题
(1)就是前面所提到的移动端小型设备加载不必要大图所造成的带宽浪费以及网页加载缓慢的问题;
(2)一个在桌面浏览器中正常显示的图片在小型移动设备中查看必然会使用户产生极大地不协调的感觉;

所以我们需要找到一种方式向不同屏幕大小的设备发送对应大小尺寸的图片文件,这就称为响应式图片。

2.应用响应式图片的两种情景以及相应的措施:

(1)情景一:Art direction(美术设计) & cropping situation(使用picture标签)
所谓的Art direction就是:在一个特定的转效点(breakpoint,比如某个屏幕宽度),需要显示一个特定的图片。

在这种情景下,我们需要使用 picture 元素,picture标签会作为图片及其源的容器。当然了,在picture标签中我们仍需要添加一个img标签,用来表明要加载的图片,如果没有img,依旧什么都不会渲染。而source标签则为浏览器提供了要显示图像的供选版本。

例子如下:

<picture>
	<!--注意source标签元素也是单标签元素-->
	<source srcset="images/dog-crop-large.jpg" media="(min-width: 1200px)">
	<source srcset="images/dog-crop-medium.jpg" media="(min-width: 760px)">
	<img src="images/dog-crop-small.jpg" alt="Puppy in the sand.">
</picture>

这种方式不仅可用于加载响应式图片,还可以应用在不同的屏幕宽度下加载不一样的图片的情景(比如屏幕宽度大于1200px时,显示一张猫的图片;大于760px时显示一张狗的图片;小于760px时,也就是默认情况下,显示一张人的图片)。

(2)情景2:Image resolution(图片分辨率) & file size situation(faster load times)

在这种情景下,我们可以通过在img标签中一次性引入所有不同大小的同一张图片。

例如:

<img srcset="images/dog-resolution-small.jpg , images/dog-resolution-medium.jpg , images/dog-resolution-large.jpg">

这种方式不用书写任何媒体查询(media query)代码,浏览器能够自动根据屏幕的大小来选择加载哪张图片(self-aware),因为浏览器知道自己的屏幕宽度以及屏幕的像素密度(pixel density)。但是这种方式有一个极大的缺点,就是浏览器只有将所有不同大小的图片下载下来才能分辨其大小,然而我们并不希望浏览器下载所有的不同大小的同一张图片(显然这很糟糕,可能解决了不同屏幕宽度下浏览器中图片的显示问题,但是成倍的增加了带宽的压力,网页将会加载的更加缓慢)。

因此,在此基础上,我们需要给浏览器更多的关于图片的信息,我们需要告知浏览器每张图片的大小,例子如下:

<img srcset="images/dog-resolution-small.jpg 570w, images/dog-resolution-medium.jpg 1200w, images/dog-resolution-large.jpg 1920w" alt="Puppy in the sand.">

可以看到我们在每张图片后面分别添加了570w,1200w以及1920w,这几个值分别告诉浏览器对应图片的宽度分别是570px、1200px和1920px。这样浏览器就可以根据img标签中的信息,以及自己的当前屏幕宽度来选择下载哪个大小版本的图片进行加载。

而在谷歌浏览器中,若通过这种方式来引用响应式图片,当浏览器处于较大宽度比如2000px时,会自动下载最大的那张1920px的图片来进行渲染,然后如果我们逐渐将浏览器宽度缩小至1200px甚至是570px以下时,可以发现浏览器仍然使用的是最大的那张图片(1920px)。

这是因为谷歌浏览器足够聪明,它知道既然已经加载并使用了最大的那张图片,那么把这张图片用在较小的宽度下也不会出现显示的问题,所以完全没必要再去下载那些尺寸较小的图片来浪费带宽。(然而浏览器这种聪明的举动可能会让想要看到对应的响应式效果的开发者感到沮丧,不过这也不是什么问题,我们可以通过将浏览器屏幕宽度调小然后清除浏览器缓存之后再将浏览器屏幕宽度调大来观察不同尺寸图片的加载过程;此外还可以通过匿名浏览模式打开一个新的窗口,这样该大图也不会存在于此缓存中)

3.项目中具体应用(采用picture标签的方式)

代码如下:

<picture>
      <source srcset="assets/images/hero--large.jpg" media="(min-width: 1380px)">
      <source srcset="assets/images/hero--medium.jpg" media="(min-width: 990px)">
      <source srcset="assets/images/hero--small.jpg" media="(min-width: 640px)">
      <img src="assets/images/hero--smaller.jpg" alt="Coastal view of ocean and mountains.">
</picture>

以上代码基本满足我们网页对于响应式图片的需求。但是还有一种情况就是针对某些HiDPI显示器的情况,简单点的描述就是在此种显示器中显示的像素数量翻倍,比如某个图标或者图片是64px的虚拟像素,但是在HiDPI的显示器中会以128个物理像素进行绘制(总共是4倍的像素,因为在每个方向上都是都是原来的两倍)这使得图标或图片在任何角度都变得两倍清晰,或者说容纳了了两倍的细节。
(具体细节可以查看这篇博客:https://www.robberphex.com/2017/02/627

那么我们如何在项目中解决此类显示问题呢,显然在HiDPI的显示器中,一般图片的像素数是不够的。这时我们可以准备相应的hi-dpi版本的图片,引入方式也很简单,直接将图片路径添加到对应图片的后面即可。例如:

<picture>
      <source srcset="assets/images/hero--large.jpg 1920w, assets/images/hero--large-hi-dpi.jpg 3840w" media="(min-width: 1380px)">
      <source srcset="assets/images/hero--medium.jpg 1380w, assets/images/hero--medium-hi-dpi.jpg 2760w" media="(min-width: 990px)">
      <source srcset="assets/images/hero--small.jpg 990w, assets/images/hero--small-hi-dpi.jpg 1980w" media="(min-width: 640px)">
      <img srcset="assets/images/hero--smaller.jpg 640w, assets/images/hero--smaller-hi-dpi.jpg 1280w" alt="Coastal view of ocean and mountains.">
</picture>

已上值得注意的地方有两点:

一.当我们针对同一图片引入不同版本时,仍然需要以像素值的形式告知浏览器图片大小,避免浏览器下载所有对应的版本。
二.img标签中应当改为使用srcset属性,而不再是src属性。

发表评论

电子邮件地址不会被公开。 必填项已用*标注