起点中文网 3D 书封之最佳实践

2,346 阅读13分钟
原文链接: mp.weixin.qq.com

原创声明

本文为阅文体验设计 YUX 成员出品,请尊重原创,转载请联系阅文体验设计微信公众号 ( id: YUX_design ) 获取授权,并注明作者、出处和链接。


前言

官网,一个作为网站第一入口的页面。直接影响着用户进入站点的第一印象。但纵览国内的所有文学类、小说类网站,大多都以推内容为主。在书本的视觉表现上都千篇一律 —— 一张简单的书封面,或是带有外边框的书封面,又或者是带有投影的书封面。其实到目前为止至少我见过的此类网站,都只是一张运营图片。而本文今天所要介绍的就是,在2016年起点中文网改版中对整体视觉进行优化的一个环节 —— 可被运营的《3D书封面》效果。《起点中文网》作为一个文学类网站的领导者,我们希望他是一个富有创新精神的面貌,在不影响业务的前提下,我们做出了在书本上优化视觉的尝试,赶紧来看一下是如何实现的吧!体验链接:http://www.qidian.com

索引
  1. HTML 结构的思路 -  1分钟阅读

  2. 透视与 3D空间 - 2分钟阅读

  3. 书封旋转的具体实现 - 4分钟阅读

  4. 兼容性 - 6分钟阅读

普通书封 与 3D书封

一、HTML结构的思路

也许你曾经在搜索引擎中找到过类似的 3D书本效果,并且他可能还带有很炫的翻书特效:

但以上这个例子,作者用了2组 ul 和多个 li(至少5个以上),并且带有各种 before 和 after 伪元素来实现层叠的纸张和翻书效果。这可能适合某个运营专题类网页的创意特效,但这显然是不适合放在官网维护。作为官网的 3D书封,我们并不希望它需要大量的 HTML 标签来实现,并且我们还需要对老浏览器进行优雅降级。


以下是起点中文网3D书封的结构

<!-- 书封容器 -->
<div class="book-cover">    <!-- 链接 -->    <a class="link" href="//book.qidian.com/info/1004608738" target="_blank">        <img src="//qidian.qpic.cn/qdbimg/349573/1004608738/90" alt="圣墟">    </a>    <!-- 阴影 -->    <span></span>    <!-- 灰色部分纸张厚度填充 -->    ::after
</div>
二、透视与 3D空间

在我们说 CSS 思路之前,先让我们来熟悉一下这个单词:perspective。字典中的解释:远景、透视图,透视的等含义。


也就是说,无论你如何的用 CSS3 的 transform,如果不给父级元素加透视属性,它始终是一张方方正正的平面 2D图。反之,一旦某个容器被加上了这个 perspective 透视属性,你就会打开一个 3D空间概念,如下图:

3D书封的实现是利用了 CSS3 中的旋转(rotate),所以先让我们来直观地看一下 CSS3 种 3D旋转的动图:

你会发现,3D旋转和 2D旋转不同之处就是,它有 3个轴 的方向,即上图中的 xyz 轴,并且每一轴都有对应的正负极。


而以上的 HTML 结构中的书封容器、阴影、和 after 纸张伪元素,他们都加上了 transform: perspective


这里值得提一下 perspective 的特点:


如果一个最上层父容器加上 transform: perspective,子元素会全部按照父级元素的视角来透视,虽然旋转值都是 45deg,但是每个旋转的角度在父元素的透视下都不一样,如下图第一排,但如果是各自加上 transform: perspective,表示自己独立成一个透视视角,如下图;

因此,我们在实现 3D书封时更适合用第二种,给各元素独立加上透视属性。

三、书封旋转的具体实现(代码 + 注释解说)

我们先来拆解一下最终的实现效果:

图中3个元素:
1. 往Y轴负极旋转的书封
2. 往Y轴正极旋转的纸张
3. 旋转变形过的 box-shadow 阴影


要实现3D书封并且要兼顾良好的兼容性,我们必须区分两类浏览器阵营:
1: chrome、火狐、IE10-IE11、或其他 webkit 内核浏览器
2: IE7-IE9


对于第1类浏览器,我们使用 :root{ } 方法来让其渲染,第2类浏览器则不会执行透视和 CSS3 的代码,保持原来的平面风格。

/*
 *SASS代码:demo 只列出关键属性,其余个性样式以及 CSS3 前缀不做一一列出
 */

//两类浏览器通用代码
.book-cover {
   //其他元素需要用absolute来调整位置,所以这里必须用relative。    position: relative;    
   //3d运营图宽度需要52px(具体原因看下方)    width: 52px;    height: 91px;    
   //a标签链接    .link {        position: relative;        
       //最上层链接        z-index: 3;    }    
   //运营图    img {        width: 60px;        height: 87px;    } }
   
//第一类浏览器代码(书封旋转、纸张可见、阴影可见)
:root {    .book-cover {
       //加透视60px(图片原始宽度),Y轴负值旋转10度        transform: perspective(60px) rotateY(-10deg);
       /* 白色书页填充 */        &:after {            position: absolute;            
           //第二层元素            z-index: 2;            top: 2%;            left: 100%;            
           //白色书页的厚度            width: 10%;            
           //白色书页的高度(注:不能超过img的高度,否则纸张会比封面长,与现实世界的透视视角不符)            height: 92%;            content: ' ';            
           //Y轴正值旋转30度(注:始终和你的书封反向轴旋转,否则会出现纸张还原度不真实)            transform: perspective(60px) rotateY(30deg);            
           //你需要加上一点背景和内阴影,让纸张显得有点质感,而不是纯纯的白色            background-color: #EFEFEF;            box-shadow: inset 0 0 5px #333;        }        
       /* 投影 */        span {            position: absolute;            
           //底层元素            z-index: 1;            
           //位置信息,可根据当时实际情况微调            top: 84.1%;            left: 7px;            
           //尽量设置偏小,让旋转变形出箭头三角状            width: 20px;            height: 10px;            content: '';            
           //反复调试的结果,按照接近设计稿为准            box-shadow: 25px 0 5px 5px #ADADAD;            
           //透视和旋转角度需反复调试,按照接近设计稿为准,也可尝试用transform:skew来调整            transform: perspective(74px) rotateX(-70deg) rotateY(-5deg);        }        img {            
           //(原始运营图宽度是60,但在3d旋转时需要改小,这是因为书封旋转后太宽会遮住纸张)            width: 52px;        }    } }

四、兼容性

介于国内浏览器分布的情况,一旦你做出比较创新的布局就很容易带来一系列的兼容性问题,当然 3D书封也不例外,而某些浏览器用户数量还是比较多的,我们并无法完全抛弃。在项目迭代的过程中,我们发现了一些怪异问题,总结如下:
1. 火狐运营图出现锯齿
2. 使用 :root{}后,IE9 也执行了代码,但是 IE9 并不能做到 3D旋转,导致阴影外露,图片宽度也变成了 52px。
3. 我们这次改版是兼容所有 Mac 设备的,在 Safari下出现了一个奇特的穿透问题。我们从简到繁,先从第一条开始分析


第一:火狐锯齿:


先来看一下火狐下的情况

一开始觉得有点费解,火狐虽然不是 Webkit 内核,但基本在渲染上也是接近Chrome 的浏览器,为什么会出现那么难看的锯齿?经过一番研究,发现火狐只要是进行过透视渲染的元素,都会出现锯齿,比如这个翻开效果也会:

思考:问题出在 img 标签上,能否在 CSS 上加一些样式修复掉这个问题?我们尝试了给 img 加上了边框,border: 1px solid #FFF;(经实践,必须是淡色,深色依然有锯齿)。效果如下:

似乎锯齿问题解决了,但是 border 会增加宽高各两个像素,并且你无法保证始终让 border 的颜色和运营图的边缘一样,不管怎样都会露出边框线。这时候我们想到了另外一个更适合的属性:outline。(IE8+支持)


outline 是轮廓属性,不会影响宽高,但是如果你依然用淡色边框色,在某些背景不是白色的容器上,依然会出现锯齿,所以我们这里如果用 transparent 边框透明色就能完美地解决问题。

//运营图
img {    width: 60px;    height: 87px;    
   //处理火狐锯齿    outline: 1px solid transparent; }

第二:IE9 不支持旋转,导致阴影外露和宽度不正确的问题


刚刚有提到,我们使用了:root{} 方法区分了两类浏览器阵营,但是 IE9 是一个中间地带,他支持 :root{},但 transform 对他无效,同时他又支持 box-shadow,所以在 IE9 下 3D书封是长这样的:

虽然调研数据,官网的IE9用户不多,但是作为一个开发者,这样的效果显然是无法接受的,但 IE9 并没有单独的 CSS hack。所以我们只能针对IE9的一些特定属性来对露出的一些元素进行优化:
1. 阴影:-ms- 是 IE 的 CSS3 前缀,同时 IE9 又支持 scale 缩放,所以我们用 -ms-transform: scale(0) 就可以将阴影设置成看不见,而 ie10 和 ie11 不受影响。
2. 书封宽度问题,width 就没有那么理想的方案了,加\9\0都会影响其他IE浏览器,所以我们选择的方案是用js重新改变 CSS 宽度为60。经测试,如果用 IE9 查看官网的话,这个重新改变尺寸的行为,用户是无感知的。


第三:Safari 中奇特的层级穿透问题(无视 z-index)


先来看一下这个奇特的问题吧,书封穿透了一个 fixed 元素,而阴影又穿透了书封 >_<,看起来似乎很难搞定啊!

刚开始我在遇到这个「bug」的时候完全不能理解,Safari 虽然是独立引擎,但他至少也是 apple WebKit,为什么会出现这种怪异的现象?不管问题是如何产生的,这种还原度依然是无法接受的,上来先按照处理 IE6 那些年的经验,给父级元素来个 overflow:hidden 看看,,如下图:

果然问题可以解决!但是某些页面中的情况比较复杂,不能用 overflow:hidden 怎么办?比如在这里投影也被裁切掉了,显然这个方法治标不治本。


然后我抛弃了 overflow:hidden 方法,尝试用 z-index 来控制层级,试图把 fixed 元素盖住它,但被 Safari 完全忽视,经过一番疯狂的胡乱调试,我决定要从根源了解问题,了解现象是如何产生的,最后得出以下几个结论:
1. Safari 的 3D变形 transform 会忽略 z-index,哪怕你被穿透的元素提高到 9999 还是无效。
2. Safari 出现的这个现象并不能称之为 bug,其实是以真实世界来渲染页面元素的。
为了能让读者更直观的理解以上2点,我画了两张示意图:


我们现在遇到的这个穿透问题是这样的

而其实我们所希望的是这样的


这时,让我们来看一个 Demo:http://fangyexu.com/tool-CSS3Inspector.html。 原来,我们在做 3D旋转变换时,一直都在关注 X和 Y轴,在此demo中有一个 translateZ 属性,是可以控制透视元素的远近(模拟真实视角远近)的属性。而其他浏览器如果你用上了 z-index,他会按照 z-index 层级来安排元素的层级,但 Safari,刚有提到它是按照真实世界来渲染的,所以z-index在这里完全无效,必须通过 translateZ 来控制。知道以上原理,兼容性的代码就很容易实现了。


首先,先解决隐隐穿透书封:span(阴影)穿透了 a 和 img 标签(书封),那我们尝试在a标签上加上 transfor:translateZ (50px),问题解决,如下图:

剩下的定位 fixed 元素想要盖住书封就更容易了,给 fixed 元素加上属性 transfor:translateZ(10px),还原度和 chrome 浏览器终于保持一致了。

写在最后

记得刚从事前端行业开始,想必每个攻城狮几乎都被 IE6 的各种怪异 bug 给虐过,随着技术发展 IE6 终于退出了历史舞台,各大领先行业的网站几乎都开始不支持 IE7 和 IE8了。原以为可以摆脱那些烦人的兼容性问题,但是按照目前的形势看来,浏览器的标准还是没有得到很好的统一,包括 CSS3 布局中的一些比较流行的 flex 和其他自适应布局,在移动端的 UC浏览器中完全无效,甚至出现了某些 IE6 年代的问题。一方面,我由衷的希望浏览器的开发商能在这一方面带给我们开发者更多的便利,也可以更好的推动 WEB 展现,让 CSS3 和 HTML5 大放异彩。另一方面,浏览器兼容性是我们开发者永恒的话题,我们必须不断的学习和积累、并且经常地进行问题总结,才能更好的应对将来。



本文作者:杨晔

转载请向阅文体验设计微信公众号 ( id: YUX_design ) 获取授权,并注明作者、出处和链接。