Fullscreen Pageflip Layout

Demo     Download

The demo contains excerpts form the hilarious “The Funny Side of Physic” by A. D. Crabtre from Project Gutenberg.

The following libraries and jQuery plugins will be used:

  1. BookBlock by Pedro Botelho
  2. Custom jQuery++ by Bitovi
  3. jScrollPane by Kevin Luck
  4. jQuery Mouse Wheel Plugin by Brandon Aaron
  5. Custom Modernizr (peek inside to see what this build includes)

So, let’s get started!

The Markup

Let’s have a main container for all our elements. Inside, we’ll add a division for the sidebar menu which we’ll give the class “menu-panel”, and the wrapper for the BookBlock with the class “bb-custom-wrapper”. The BookBlock will contain the wrapper (that we’ll apply the plugin to) and the structure that the plugin needs. Inside of each item, we’ll add a content wrapper with a division that we’ll need for the custom scroll functionality:

<div id="container" class="container">	

  <div class="menu-panel">
    <h3>Table of Contents</h3>
    <ul id="menu-toc" class="menu-toc">
      <li class="menu-toc-current"><a href="#item1">Self-destruction</a></li>
      <li><a href="#item2">Why we die</a></li>
      <li><a href="#item3">The honeymoon</a></li>
      <li><a href="#item4">A drawing joke</a></li>
      <li><a href="#item5">Commencing practice</a></li>
    </ul>
  </div>

  <div class="bb-custom-wrapper">

    <div id="bb-bookblock" class="bb-bookblock">

      <div class="bb-item" id="item1">
        <div class="content">
          <div class="scroller">
            <h2>Self-destruction</h2>
            <p>...</p>
          </div>
        </div><!-- /content -->
      </div><!-- /bb-item -->

      <div class="bb-item" id="item2"><!-- ... --></div>

      <div class="bb-item" id="item3"><!-- ... --></div>

      <div class="bb-item" id="item4"><!-- ... --></div>

      <div class="bb-item" id="item5"><!-- ... --></div>

    </div><!-- /bb-bookblock -->
    
    <nav>
      <a id="bb-nav-prev" href="#">←</a>
      <a id="bb-nav-next" href="#">→</a>
    </nav>

    <span id="tblcontents" class="menu-button">Table of Contents</span>

  </div><!-- /bb-custom-wrapper -->

</div><!-- /container -->

The menu items will point to the respective BookBlock pages (bb-item). We’ll also add navigation arrows and a button for toggling the opening and closing of the menu.

Let’s move on to the style

The CSS

let’s set the main wrappers’ widths and heights to 100% and add a transition to the container:

.container,
.bb-custom-wrapper,
.bb-bookblock {
  width: 100%;
  height: 100%;
}

.container {
  position: relative;
  left: 0px;
  transition: left 0.3s ease-in-out;
}

When we click on the menu button, we will add another class to the container which will set the left to 240 pixels (width of the sidebar menu):

.slideRight {
  left: 240px;
}

Without JavaScript enabled, we won’t be able to do this, so let’s add a left padding instead:

.no-js .container {
  padding-left: 240px;
}

By default, we want the sidebar menu to be fixed to the left side:

.menu-panel {
  background: #f1103a;
  width: 240px;
  height: 100%;
  position: fixed;
  z-index: 1000;
  top: 0;
  left: 0;
  text-shadow: 0 1px 1px rgba(0,0,0,0.1);
}

When JS is enabled, we’ll set the position to absolute and the left to -240 pixel:

.js .menu-panel {
  position: absolute;
  left: -240px;
}

Let’s style the elements of the menu:

.menu-panel h3 {
  font-size: 1.8em;
  padding: 20px;
  font-weight: 300;
  color: #fff;
  box-shadow: inset 0 -1px 0 rgba(0,0,0,0.05);
} 

.menu-toc {
  list-style: none;
}

.menu-toc li a {
  display: block;
  color: #fff;
  font-size: 1.1em;
  line-height: 3.5;
  padding: 0 20px;
  cursor: pointer;
  background: #f1103a;
  border-bottom: 1px solid #dd1338;
}

.menu-toc li a:hover,
.menu-toc li.menu-toc-current a{
  background: #dd1338;
}

The navigation will be positioned absolutely on top of everything:

.bb-custom-wrapper nav {
  top: 20px;
  left: 60px;
  position: absolute;
  z-index: 1000;
}

The arrow links and the menu button will also be positioned absolutely and we’ll make them round by setting the border-radius to 50%:

.bb-custom-wrapper nav span,
.menu-button {
  position: absolute;
  width: 32px;
  height: 32px;
  top: 0;
  left: 0;
  background: #f1103a;
  border-radius: 50%;
  color: #fff;
  line-height: 30px;
  text-align: center;
  speak: none;
  font-weight: bold;
  cursor: pointer;
}

.bb-custom-wrapper nav span:last-child {
  left: 40px;
}

.bb-custom-wrapper nav span:hover,
.menu-button:hover {
  background: #000;
}

The menu button will be positioned in the top left corner and we’ll hide its text:

.menu-button {
  z-index: 1000;
  left: 20px;
  top: 20px;
  text-indent: -9000px;
}

Let’s create a little menu icon by using a pseudo-element with a double box shadow for the upper and lower line:

.menu-button:after {
  position: absolute;
  content: '';
  width: 50%;
  height: 2px;
  background: #fff;
  top: 50%;
  margin-top: -1px;
  left: 25%;
  box-shadow: 0 -4px #fff, 0 4px #fff;
}

In case that there is no JS enabled, we don’t need any of those elements, so we’ll simply hide them:

.no-js .bb-custom-wrapper nav span,
.no-js .menu-button {
  display: none;
}

Let’s move to the inner parts of the BookBlock items. The content division needs to be absolute and we’ll set the overflow to hidden. This is important because we want to apply our custom scroll here and we’ll only do that when a page was turned. If we wouldn’t set the overflow to hidden, we’d see the content overflowing. Again, this only makes sense when we have JS enabled, so we’ll add the “js” class:

.js .content {
  position: absolute;
  top: 60px;
  left: 0;
  bottom: 50px;
  width: 100%;
  overflow: hidden;
}

The scroller div is the one that will grow with content, so let’s set some paddings here:

.scroller {
  padding: 10px 5% 10px 5%;
}

Using percentages as lateral padding will make the layout adjust liquidly to the screen size.

Let’s hide those sharp edges when we scroll by adding pseudo-elements with a white to transparent gradient to the top and the bottom of the content div:

.js .content:before,
.js .content:after {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 20px;
  z-index: 100;
  pointer-events: none;
  background: 
    linear-gradient(
      to bottom, 
      rgba(255,255,255,1) 0%, 
      rgba(255,255,255,0) 100%
    );
}

.js .content:after {
  top: auto;
  bottom: 0;
  background: 
    linear-gradient(
      to top, 
      rgba(255,255,255,1) 0%, 
      rgba(255,255,255,0) 100%
    );
}

This will make the text appear slightly faded out.

Let’s style the text elements:

.content h2 {
  font-weight: 300;
  font-size: 4em;
  padding: 0 0 10px;
  color: #333;
  margin: 0 1% 40px;
  text-align: left;
  box-shadow: 0 10px 0 rgba(0,0,0,0.02);
  text-shadow: 0 0 2px #fff;
}

.no-js .content h2 {
  padding: 40px 1% 20px;
}

.content p {
  font-size: 1.2em;
  line-height: 1.6;
  font-weight: 300;
  padding: 5px 8%;
  text-align: justify;
}

Finally, let’s add some media queries. Without JavaScript enabled, we don’t want to show the menu anymore from 800 pixels on. This is just an example of how we can control these elements under certain conditions.

The last media query will resize the font a bit, for smaller devices. Using ems makes things easier for these cases.

@media screen and (max-width: 800px){
  .no-js .menu-panel {
    display: none;
  }

  .no-js .container {
    padding: 0;
  }
}

@media screen and (max-width: 400px){
  .menu-panel,
  .content {
    font-size: 75%;
  }
}

The JavaScript

We will start by caching some elements and initializing the BookBlock plugin. We need to set some things after each page flip, mainly the current item’s index and the jScrollPane behavior. This is specified in the onEndFlip callback passed to the BookBlock.

var $container = $( '#container' ),

  // the element we will apply the BookBlock plugin to
  $bookBlock = $( '#bb-bookblock' ),

  // the BookBlock items (bb-item)
  $items = $bookBlock.children(),

  // index of the current item
  current = 0,

  // initialize the BookBlock
  bb = $( '#bb-bookblock' ).bookblock( {
    speed : 800,
    perspective : 2000,
    shadowSides	: 0.8,
    shadowFlip	: 0.4,
    // after each flip...
    onEndFlip : function(old, page, isLimit) {
      
      // update the current value
      current = page;

      // update the selected item of the table of contents (TOC)
      updateTOC();

      // show and/or hide the navigation arrows
      updateNavigation( isLimit );

      // initialize the jScrollPane on the content div for the new item
      setJSP( 'init' );

      // destroy jScrollPane on the content div for the old item
      setJSP( 'destroy', old );

    }
  } ),
  // the navigation arrows
  $navNext = $( '#bb-nav-next' ),
  $navPrev = $( '#bb-nav-prev' ).hide(),

  // the table of content items
  $menuItems = $container.find( 'ul.menu-toc > li' ),

  // button to open the TOC
  $tblcontents = $( '#tblcontents' ),

  transEndEventNames = {
    'WebkitTransition': 'webkitTransitionEnd',
    'MozTransition': 'transitionend',
    'OTransition': 'oTransitionEnd',
    'msTransition': 'MSTransitionEnd',
    'transition': 'transitionend'
  },

  // transition event name
  transEndEventName = transEndEventNames[Modernizr.prefixed('transition')],

  // check if transitions are supported
  supportTransitions = Modernizr.csstransitions;

First, let’s bind the events to some of the elements initialized before. Also, we need to initialize the jScrollPane for the first (current) item.

function init() {

  // initialize jScrollPane on the content div of the first item
  setJSP( 'init' );
  initEvents();

}

Since we’ll eventually need to initialize, reinitialize and destroy the jScrollPane, let’s define a function for this:

function setJSP( action, idx ) {
    
  var idx = idx === undefined ? current : idx,
    $content = $items.eq( idx ).children( 'div.content' ),
    apiJSP = $content.data( 'jsp' );
  
  if( action === 'init' && apiJSP === undefined ) {
    $content.jScrollPane({verticalGutter : 0, hideFocus : true });
  }
  else if( action === 'reinit' && apiJSP !== undefined ) {
    apiJSP.reinitialise();
  }
  else if( action === 'destroy' && apiJSP !== undefined ) {
    apiJSP.destroy();
  }

}

We will need to bind several events:

  1. We will call the BookBlock’s next() and prev() methods when we click the navigation arrows or when swiping the page
  2. The TOC will be shown / hidden when we click the $tblcontents (menu) button
  3. We will call the BookBlock jump() method when we click a TOC item
  4. The jScrollPane will be initialized on window resize

So, here we go:

function initEvents() {

  // add navigation events
  $navNext.on( 'click', function() {
    bb.next();
    return false;
  } );

  $navPrev.on( 'click', function() {
    bb.prev();
    return false;
  } );
  
  // add swipe events
  $items.on( {
    'swipeleft'		: function( event ) {
      if( $container.data( 'opened' ) ) {
        return false;
      }
      bb.next();
      return false;
    },
    'swiperight'	: function( event ) {
      if( $container.data( 'opened' ) ) {
        return false;
      }
      bb.prev();
      return false;
    }
  } );

  // show TOC
  $tblcontents.on( 'click', toggleTOC );

  // click a menu item
  $menuItems.on( 'click', function() {

    var $el = $( this ),
      idx = $el.index(),
      jump = function() {
        bb.jump( idx + 1 );
      };
    
    current !== idx ? closeTOC( jump ) : closeTOC();

    return false;
    
  } );

  // reinit jScrollPane on window resize
  $( window ).on( 'debouncedresize', function() {
    // reinitialise jScrollPane on the content div
    setJSP( 'reinit' );
  } );

}

The navigation arrows’ visibility will depend on the current page. If we are on the first page we’ll only see the next arrow and if we are on the last page we’ll only see the previous arrow:

function updateNavigation( isLastPage ) {
  
  if( current === 0 ) {
    $navNext.show();
    $navPrev.hide();
  }
  else if( isLastPage ) {
    $navNext.hide();
    $navPrev.show();
  }
  else {
    $navNext.show();
    $navPrev.show();
  }

}

When we open the TOC we want to hide the navigation arrows and we just show them again after closing the TOC.
We will animate the sidebar menu with a CSS transition. If there’s no support for transitions then a simple show/hide fallback will be used:

function toggleTOC() {
  var opened = $container.data( 'opened' );
  opened ? closeTOC() : openTOC();
}

function openTOC() {
  $navNext.hide();
  $navPrev.hide();
  $container.addClass( 'slideRight' ).data( 'opened', true );
}

function closeTOC( callback ) {

  $navNext.show();
  $navPrev.show();
  $container.removeClass( 'slideRight' ).data( 'opened', false );
  if( callback ) {
    if( supportTransitions ) {
      $container.on( transEndEventName, function() {
        $( this ).off( transEndEventName );
        callback.call();
      } );
    }
    else {
      callback.call();
    }
  }

}

Demo     Download

courtesy:http://tympanus.net

Fullscreen Pageflip Layout

| Animation, CSS3, HTML5, Javascript, jQuery Animation, Responsive, SVG, Uncategorized | 0 Comments
About The Author
- Thank you for visiting my profile page. I have over 8+ years experience in web development. Product quality, Client service, and results are my priority. I offer unparalleled expertise and services in web design and front-end development, including responsive websites (Using Twitter bootstrap framework) and Hybrid Mobile Application (Using IONIC Framework) . I am proficient in a wide spectrum of technologies and learn new ones fast. I am seeking new opportunities to design, build and extend websites and web applications.