这是一款效果非常炫酷的jQuery和CSS3 3D折纸面板展开页面特效插件。当用户点击某个导航按钮时,对应内容的面板会像折叠的纸张一样展开,关闭面板时,左右面板又会像纸张一样折叠回去。
纸张折叠效果是当前非常流行的一种网页特效,特别是在一些移动手机的APP中,例如iOS Peek Calendar app。现在,通过 CSS3 transformation 和 transitions,我们可以在浏览器中制作出相同的折纸特效。
制作方法
HTML结构
该折纸面板特效的HTML结构分为两个主要部分:一个无序列表,包含.cd-item
子元素,并且无序列表被包裹在一个<main>
元素中。另外一个是.cd-folding-panel
元素,它包含折纸面板的内容.cd-fold-content
和两个纸张面板(.left-fold
和.right-fold
)
<main class="cd-main"> <ul class="cd-gallery"> <li class="cd-item"> <a href="item-1.html"> <div> <h2>Title 1</h2> <p>Lorem ipsum dolor sit amet, consectetur.</p> <b>View More</b> </div> </a> </li> <li class="cd-item"> <!-- content here --> </li> <!-- additional list items here --> </ul> <!-- .cd-gallery --> </main> <!-- .cd-main --> <div class="cd-folding-panel"> <div class="fold-left"></div> <!-- this is the left fold --> <div class="fold-right"></div> <!-- this is the right fold --> <div class="cd-fold-content"> <!-- content will be loaded using javascript --> </div> <a class="cd-close" href="#0"></a> </div> <!-- .cd-folding-panel -->
CSS样式
为了制作折纸动画效果,插件在.left-fold
、.right-fold
、.cd-main
和.cd-item
元素上使用了CSS3 Transformations。
左右两面纸张的动画效果是在.left-fold
和.right-fold
元素的::after
伪元素制作动画。
在移动手机上,只有右边的面板会发生动画效果(左边的纸张面板.left-fold
会使用display: none
来隐藏)。默认情况下,.cd-folding-panel
元素和它的子元素.right-panel
是固定定位(fixed)的,并且覆盖整个屏幕(但是它的可见性被设置为hidden)。当用户点击.cd-item
的时候,.cd-main
的内容使用.fold-is-open
class移动到右边,.right-fold::after
被移动到屏幕的中间,并进行一定角度的旋转(在.cd-folding-panel
元素上使用.is-open
)。
.cd-main { overflow-x: hidden; } .cd-main > * { transition: transform 0.5s 0.4s; } .cd-main.fold-is-open > * { /* on mobile - translate .cd-main content to the right when the .cd-folding-panel is open */ transform: translateX(100%); transition: transform 0.5s 0s; } .cd-folding-panel { position: fixed; top: 0; left: 0; width: 100%; height: 100vh; visibility: hidden; overflow: hidden; transition: visibility 0s 0.9s; } .cd-folding-panel .fold-left, .cd-folding-panel .fold-right { /* the :after elements of .fold-left and .fold-right are the 2 fold sides */ width: 100%; height: 100vh; overflow: hidden; /* enable a 3D-space for children elements */ perspective: 2000px; } .cd-folding-panel .fold-right { perspective-origin: 0% 50%; } .cd-folding-panel .fold-left { /* on mobile only the right fold side is visible */ display: none; } .cd-folding-panel .fold-right::after { /* 2 fold sides */ content: ''; position: absolute; top: 0; left: 0; height: 100%; width: 100%; transform-origin: right center; transform: translateX(-100%) rotateY(-90deg); transition: transform 0.5s 0.4s, background-color 0.5s 0.4s; } .cd-folding-panel.is-open { visibility: visible; transition: visibility 0s 0s; } .cd-folding-panel.is-open .fold-right::after { transform: translateX(0); transition: transform 0.5s 0s, background-color 0.5s 0s; }
在桌面设备上(屏幕大于1100像素),左右纸张面板的::after
伪元素都被执行动画。.cd-folding-panel
被放置到屏幕的中间(宽度被设置为800像素)。.left-panel
和.right-panel
被设置为左浮动float: left
,并且它们的宽度都是400像素。它们的::after
伪元素都被旋转90度rotateY(-90deg)
,左面板向左移动translateX(100%)
,右面板向右移动translateX(-100%)
。
当用户点击.cd-item
的时候,它们会向左:nth-of-type(2n+1)
或向右:nth-of-type(2n)
进行移动。并且它们的::after
伪元素也被移动和旋转。
@media only screen and (min-width: 1100px) { .cd-item { width: 50%; float: left; transition: transform 0.5s 0.4s; } .fold-is-open .cd-item { transition: transform 0.5s 0s; transform: translateX(-400px); } .fold-is-open .cd-item:nth-of-type(2n) { transform: translateX(400px); } } @media only screen and (min-width: 1100px) { .cd-folding-panel { left: 50%; transform: translateX(-50%); width: 800px; } .cd-folding-panel .fold-left, .cd-folding-panel .fold-right { width: 50%; float: left; height: 100%; } .cd-folding-panel .fold-right { /* change perspective-origin so that the 2 fold sides have the same vanishing point */ perspective-origin: 0% 50%; } .cd-folding-panel .fold-right::after { transform-origin: right center; transform: translateX(-100%) rotateY(-90deg); } .cd-folding-panel .fold-left { display: block; /* change perspective-origin so that the 2 fold sides have the same vanishing point */ perspective-origin: 100% 50%; } .cd-folding-panel .fold-left::after { transform-origin: left center; transform: translateX(100%) rotateY(90deg); } .cd-folding-panel.is-open .fold-right::after, .cd-folding-panel.is-open .fold-left::after { transform: translateX(0); transition: transform 0.5s 0s, background-color 0.5s 0s; } }
需要注意的是,插件中修改了左右纸张面板的透视原点perspective-origin
。因为每一个::after
伪元素都有它自己的3d空间消失点,消失点是它的父元素的中心,在这个效果中,分别是.left-panel
和.right-panel
的中心。插件中将左右纸张的透视原点进行了修改,使它们的消失点都位于视口的中心位置。
.cd-folding-panel .fold-right { perspective-origin: 0% 50%; } .cd-folding-panel .fold-left { perspective-origin: 100% 50%; }
JAVASCRIPT
在index.html文件中,.cd-fold-content
元素初始化时设置为空元素。
当用户点击了一个.cd-item
按钮,插件是load()
方法在.cd-fold-content
元素中插入匹配的内容。
当新的内容被插入之后,插件回味各个元素添加相应的class,之后折纸动画特效被触发。
/* open folding content */ $('.cd-gallery a').on('click', function(event){ event.preventDefault(); openItemInfo($(this).attr('href')); }); function openItemInfo(url) { /* check if mobile or desktop */ var mq = viewportSize(); if( $('.cd-gallery').offset().top > $(window).scrollTop() && mq != 'mobile') { /* if content is visible above the .cd-gallery - scroll before opening the folding panel */ $('body,html').animate({ 'scrollTop': $('.cd-gallery').offset().top }, 100, function(){ toggleContent(url, true); }); } else { toggleContent(url, true); } } function toggleContent(url, bool) { if( bool ) { /* load and show new content */ $('.cd-fold-content').load(url+' .cd-fold-content > *', function(event){ $('body').addClass('overflow-hidden'); $('.cd-folding-panel').addClass('is-open'); $('.cd-main').addClass('fold-is-open'); }); } else { /* close the folding panel */ $('.cd-folding-panel').removeClass('is-open') $('.cd-main').removeClass('fold-is-open'); /* ...*/ } }
插件中只是提供了一个基本的load()
方法来加载内容。你可以自行修改,使用$.ajax
来加载内容,或进行一些其他的处理。