最近坐地鐵發現“亞洲動物基金”在地鐵上做了很多公益廣告,比較吸引人的是一個月熊的廣告。做的很可愛。回去就搜了一下,發現這個網站是Html5做的,非常炫。
所以想學習一下,方法就是傳統的學習辦法,模仿、剖析,看看人家是怎麼做的。
這個網站提供的是了一個沉浸式的翻閱體驗,用戶可以在頁面切換時體驗到真實的3D翻書效果,非常的酷炫。而要實現這個效果,需要用到CSS3 3D transform和JavaScript,同時為了實現跨浏覽器和跨設備的統一體驗,用到hammer.JS庫去處理滑動操作。就是下面這個樣子的,非 常漂亮:

示例效果:

查看代碼發現,網頁的結構十分簡單,整個雜志是一個ID為magazine的div,子元素. page即頁面元素,其中還需要包含一層.page-content層。
<div id="magazine">
<div class="page">
<div class="page-content">
<!-- ... -->
</div>
</div>
<!-- pages -->
<div class="page">
<div class="page-content">
<!-- ... -->
</div>
</div>
</div>
CSS:
.page {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
overflow: hidden;
display: none;
}
.page-content {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
當用戶拖拽頁面時,我們會復制一份當前頁和下一頁,作為3D翻頁的元素存在,層之間的關系如下:
$currentPage -> 當前頁
$newPage -> 新的一頁(上一頁/下一頁)
$pageBack -> 克隆的$newPage
$pageFront -> 克隆的$currentPage

除了當前頁的其他頁面,為了只顯示頁面一半,需要將外層div的寬度設置為50%,同時將.page-content設為200%。
CSS:
.page.front,
.page.back,
.page.prev,
.page.next {
width: 50%;
}
.page.front .page-content,
.page.back .page-content,
.page.prev .page-content,
.page.next .page-content {
width: 200%;
}
當開始拖拽時,通過鼠標位置在屏幕的左邊或者右邊判斷翻頁的方向並復制頁面。然後在拖拽時,根據移動距離計算翻頁進度並轉換為角度應用到元素上。最後使用CSS transition完成余下動畫。
JS代碼關鍵部分:
$("#magazine").hammer({prevent_default: true}).on("dragstart", function(event) {
//開始拖拽
//根據指針的位置判斷新的一頁是上一頁還是下一頁
var pageX = event.gesture.center.pageX;
_.$newPage = pageX > centerX ? _.$currentPage.next(".page").addClass("next") : _.$currentPage.prev(".page").addClass("prev");
//復制當前頁和新的一頁
_.$pageFront = $("<div class='page front' />").append(_.$currentPage.children().clone());
_.$pageBack = $("<div class='page back/>").append(_.$newPage.children().clone());
$(this).on("drag", function(event) {
//拖拽中
//獲得手勢方向
var direction = event.gesture.direction;
//如果是左右滑動才繼續
if (direction != "left" && direction != "right") return;
//獲得鼠標x坐標,和窗口寬度相除獲得百分比和角度
var deltaX = Math.max((_.direction == "left" ? -1 : 1) * event.gesture.deltaX, 0),
progress = deltaX / winWidth,
angle = (direction == "left" ? -180 : 180) * progress;
//使用transform翻轉頁面
_.$pageFront.css("transform", "perspective(2200px) rotateY(" + angle + "deg)");
_.$pageBack.css("transform", "perspective(2200px) rotateY(" + (angle - 180) + "deg)");
}).on("dragend", function(event) {
//拖拽結束
var deltaX = Math.max((direction == "left" ? -1 : 1) * event.gesture.deltaX, 0),
time = event.gesture.deltaTime,
progress = deltaX / winWidth,
flipped = progress > 0.5 deltaX / time > 0.5, //如果滑動距離超過屏幕的一半或者速度大於0.5就認為頁面被翻過去了
duration = !flipped ? 1 - progress : progress,
angle = !flipped ? 0 : _.direction == "left" ? -180 : 180;
//通過css3 transition完成余下動畫
_.$pageFront.css({
"transition": "all " + duration + "s ease-out",
"transform": "perspective(2200px) rotateY(" + angel + "deg)"
});
_.$pageBack.CSS({
"transition": "all " + duration + "s ease-out",
"transform": "perspective(2200px) rotateY(" + (angel - 180) + "deg)"
});
});
});
如果你的頁面包含視頻或者Canvas等元素,那還需要再做一些額外的工作,因為這些元素並不能以同樣的狀態被直接復制。
最後如果你需要兼容不支持CSS3浏覽器。可以借助Modernizr判斷,以水平滑動的方式切換頁面。
if (Modernizr.csstransforms3d && Modernizr.CSStransitions) {
//支持
} else {
//不支持
};