对布局和视频加载的想法

March 24, 2021

最近上线了一个官网主题页,也是我的第一个对外页面,嗯,很符合活动页特点,开发周期短,逻辑含量低。但是毕竟以前没有接触过,写下来还是有不少感受的。

布局

布局最常见的方案就是居中布局 + 响应式布局。居中布局可选方案多,为了兼容 ie 9,选取的是 text-align: center 的方式;响应式布局为了提高维护性,以 pc 端设计稿的 100px 为 1rem。立马开工,只是没有一会就发现问题了:

  1. 设计稿除了居中,还要左对齐;
  2. 字体不能采用rem的形式,否则会出现渲染不清晰,甚至是低于12px的情况,而且字体是否需要响应式?
  3. 图片采用响应式,但是标准是多大,设计稿为 2560px 宽,难道按照 2560px 来吗?

对于第一个问题,设计稿里面的结构看似是居中的,但实际上只有 banner 以及第二模块主题是居中的,第三四模块都是和第二个模块左对齐而已,其大小不一,并非居中。对于这个问题好办,设置 pandding-left 即可,内部元素 float: left,再清除浮动即可实现左对齐了,或者是 text-align: left。 第二个问题和第三个问题要一起来看,首先字体是不能采用响应的,虽然当前现代浏览器已经支持 12px 以下的字体(Edge 丧心病狂,字体大小可以支持到 1px),但是设计稿的两边空白自然是可以随着响应布局裁剪的,而中间部分才是给用户看的核心。因此图片和文案是不可以采用简单的响应式的。在以前的主题版本里面中间部分是不做响应处理的,如此下来对整体视窗的最小尺寸 min-width 就要做要求,否则 inline 元素会滑到下一行。

再三考虑下,采用图片响应处理,以设计稿大小为基准,但是采用 三种媒体查询 1440px/1680px/1920px 。比如设计稿上是 4rem,在 1440px 的时候,则会变成 4 * (1920 / 1440)rem,这样在响应布局的时候,原本很大的图片就不会显的特别小,而在 1920px 以上的时候直接响应布局就好了。同样的字体也采用三种媒体查询,专门设定大小而不是采用响应的形式,保证图片和字体之间的协调,避免字体特别大的情况。

定下方案后,由于采用 less css预处理器,在媒体响应里面直接套用 mixin,很是方便,结束后让设计师过来看,结果立马提到字体为何这么小?看着不协调,虽然我做了媒体查询,但是在 设计师里面字体是处于不能改的范畴 。同时出现了另外一个问题,在小屏的时候,整体布局是偏右的,没有达到视觉上的居中。对于前者就采用字体大小按照设计稿来就好了。而后面的问题,则是在一开始设置 pandding-left 采用的是绝对的百分数。只是这个百分数,由于图片不是100%的 rem 布局,增加了媒体查询,并且字体也不是 rem 布局,是固定的尺寸,于是这个百分数就偏大,导致整体靠右。于是通过反复的计算固定布局、响应和媒体查询,最后得到:

padding-left: calc(22% - 170px + unit(2.5 + (@screenRate - 1) / 2, rem));

类似于上面的写法,感觉进入了死胡同,写法过于复杂,其实可以简单的采用 js 来计算处理,获取居中的 padding-left 值,但是能用 css 的为何不用 css 呢?

上面提到的四个屏幕格式,但是还漏了出来已经有三四年的 4k 屏。对于这样的屏幕,图片也采用响应,会比 2560 屏幕大上 50%,属于还是能够接受的范畴。至于居中问题,padding-left,由于采用的是具体的数值计算,也同样能够保持居中效果,只是由于图片和字体之间的间距采用了 max-with,所以最后效果还是会偏左一点。这里也可以采用媒体查询来解决掉偏左的情况。

视频加载

可以看到初进入页面是一个 video。视频高度和宽度占满整个屏幕,进来就立刻播放了,是个关键的关键。先看看这个页面,这是 UC 的官网,一进来的时候,是白屏的,尤其是在 fast-3G 的网速下,中间白屏大概在 4s 左右。这是由于初次进来,资源加载时间会过长,导致中间白屏。为了避免这样的问题,可以采用的是 video 的 poster,其表示在用户播放视频之前显示的内容,如果不设置,在第一帧之前,什么都不显示也就是白屏。于是我们很直接的 采用了视频的第一帧,作为 poster ,使得视频的播放就能够平滑过渡。

只是即便如此,视频的播放还是有比较明显的延迟,查看 network,发现 video 加载在 waterfall 中靠后,结合之前看的从Chrome源码看浏览器如何加载资源,作为 video 资源,其加载优先级自然是最低的,当然除了 prefetch 资源以外。banner 里面显示的视频出现速度影响着整个页面的出现的效果,于是这里 采用 preload 的形式 ,banner 的视频加载优先度也从底部上升到了顶部。只是效果并不明显,明明 700ms 不到就可以下载视频了,而结果却是接近 2s 的时刻,才开始播放视频。在观察 network 的时候发现一个很神奇的请求,banner 视频同时请求了两次,一次是 preload 的时候加载资源,一次是正常解析到 video 标签的时候的请求,而这个请求返回是 206,范围请求资源,只是不是请求过了吗?在控制台了给了提示表示 preload 的资源没有被使用上!

这就明显了,banner 的资源没有用上,所以重新请求了,只是为什么没有使用 preload 的资源?点开 mdn 上面的例子竟然发现也是同样的情况,preload 是作用了,但是视频会加载两次,虽然第二次的请求接口只有几kb 的大小?这个这个时候看看控制台的提示:

A preload for 'http://xxxxxx' is found, but is not used because the request headers do not match.

当把资源改为图片的来实现图片预加载的时候,也出现重复加载资源情况,这个时候控制台如下提示:

A preload for 'http://xxxxxx' is found, but is not used because the request credentials mode does not match. Consider taking a look at crossorigin attribute.

提示跨域的属性可能设置错误了。把跨域设置去掉不可以实现正常加载了。那视频 video 呢?其请求头是不一样的,chrome 里面的 link 里面的视频资源居然不是采范围分请求的形式加载,而是直接加载整个资源,但解析到 video 的时候,则采用范围加载。。。这个。。。请求头的 Accept-Encoding Range chrome-proxy 是不一样的。

在 caniuse 里面发现 opera 也是这支持 preload 的,结果情况类似,第二次请求的请求头也不一样,但是 opera 返回的响应是 304,不是 206,可以看出基本就是 206/304 了。

至于 edge 浏览器直接把 preload 标识当作 prefetch 了,直接挂起了。

stackoverflow 上只有一个类似的提问,但是没有人回答。倒是 developers.google 里面有一篇Fast Playback with Video Preload,总结:

HTTP Range requests are not compatible.

还是不兼容!

当网络速度慢的时候,banner 处的视频加载速度,直接影响了播放开始时间,这个时候用 preload 是有显著效果的。网页资源多,video 在首屏加载的时候就会处于落后的情况,这个时候用 preload 也是极好的。只是有如下限制:

  1. 资源的请求不能是范围请求;
  2. 若 preload 加载资源未完成,浏览器在加载 video 对应的资源时会再次请求,这就对资源大小有要求了;
  3. 浏览器表现不一,尤其是对 video;