HTML5之CSS3 3D transform 剖析式學習之一

最近坐地鐵發現「亞洲動物基金」在地鐵上作了不少公益廣告,比較吸引人的是一個月熊的廣告。作的很可愛。回去就搜了一下,發現這個網站是HTML5作的,很是炫。javascript

因此想學習一下,方法就是傳統的學習辦法,模仿、剖析,看看人家是怎麼作的。css

這個網站提供的是了一個沉浸式的翻閱體驗,用戶能夠在頁面切換時體驗到真實的3D翻書效果,很是的酷炫。而要實現這個效果,須要用到CSS3 3D transform和JavaScript,同時爲了實現跨瀏覽器和跨設備的統一體驗,用到hammer.js庫去處理滑動操做。就是下面這個樣子的,很是漂亮:java

 

示例效果:css3

 

查看代碼發現,網頁的結構十分簡單,整個雜誌是一個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翻頁的元素存在,層之間的關係以下:app

$currentPage -> 當前頁學習

$newPage -> 新的一頁(上一頁/下一頁)動畫

$pageBack -> 克隆的$newPage網站

$pageFront -> 克隆的$currentPagethis

 

除了當前頁的其餘頁面,爲了只顯示頁面一半,須要將外層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 {

    //不支持

};

 

今天暫時寫到這裏吧,想看效果的同窗,能夠本身去 http://moonbear.animalsasia.org/ie/ 看一下。真的是很是漂亮,明天我會繼續剖析一下其餘效果的實現。

相關文章
相關標籤/搜索