flip
HTML
<div class="container">
<div class="page_elements">
<div class="elem" id="1">1</div>
<div class="elem" id="2">2</div>
<div class="elem" id="3">3</div>
<div class="elem" id="4">4</div>
<div class="elem" id="5">5</div>
<div class="elem" id="6">6</div>
<div class="elem" id="7">7</div>
<div class="elem" id="8">8</div>
<div class="elem" id="9">9</div>
<div class="elem" id="10">10</div>
<div class="elem" id="1">1</div>
<div class="elem" id="2">2</div>
<div class="elem" id="3">3</div>
<div class="elem" id="4">4</div>
<div class="elem" id="5">5</div>
<div class="elem" id="6">6</div>
<div class="elem" id="7">7</div>
<div class="elem" id="8">8</div>
<div class="elem" id="9">9</div>
<div class="elem" id="10">10</div>
</div>
<div class="flip-super">
<div class="flip-container" ontouchstart="this.classList.toggle('hover');">
<div class="flipper">
<div class="front">
<!-- front content -->
</div>
<div class="back">
<!-- back content -->
</div>
</div>
</div>
</div>
</div>
CSS
.container {
width: 200px;
height: 400px;
position: relative;
}
.page_elements{
overflow-y:scroll;
height:100%;
}
.elem {
display: inline-block;
width: 200px;
height: 100px;
background-color: red;
color: white;
text-align: center;
border: 1px solid #ffffff;
}
.front {
background-color: blue;
z-index: 2;
}
.back {
background-color: green;
transform: rotateX(180deg);
}
/* entire container, keeps perspective */
.flip-container {
perspective: 1000;
position: absolute;
bottom: 0;
left: 0;
}
.flip-super{
display: inline-block;
position: aboslute;
top: 0;
left: 0;
}
.flip-container, .front, .back, .flipper {
width: 200px;
height: 50px;
}
/* flip speed goes here */
.flipper {
transform-style: preserve-3d;
position: relative;
}
/* hide back of pane during swap */
.front, .back {
position: absolute;
top: 0;
left: 0;
width: 200px;
height: 50px;
backface-visibility: hidden;
}
JavaScript
var delay = 20;
var timeout = null;
var scroll = 0;
var scroll_offset = 0;
var last_time = 0;
var scroll_focus = $('.page_elements');
var speed_in_px_per_ms = 0;
function rotate() {
var translate = 'rotateX(' + scroll + 'deg)';
$('.flipper').css('transform', translate);
}
function rotate_back(goal_angle, rotate_speed) {
setTimeout(function () {
scroll--;
rotate();
if (scroll > goal_angle) {
rotate_back(goal_angle, rotate_speed * 0.1);
}
}, rotate_speed);
}
function rotate_forward(goal_angle, rotate_speed) {
setTimeout(function () {
scroll++;
rotate();
if (scroll < goal_angle) {
rotate_forward(goal_angle, rotate_speed*1.1);
}
}, rotate_speed);
}
function finish_rotation() {
var smaller_multiple = 180 * Math.floor(scroll / 180);
var larger_multiple = 180 * Math.ceil(scroll / 180);
if (scroll < larger_multiple / 2) {
rotate_back(smaller_multiple, speed_in_px_per_ms);
} else {
rotate_forward(larger_multiple, speed_in_px_per_ms);
}
}
scroll_focus.scroll(function (event) {
clearTimeout(timeout);
var delay_in_ms = event.timeStamp - last_time;
var offset = scroll_focus.scrollTop() - scroll_offset;
speed_in_px_per_ms = offset / delay_in_ms;
last_time = event.timeStamp;
scroll_offset = scroll_focus.scrollTop();
scroll = scroll_focus.scrollTop();
rotate();
timeout = setTimeout(finish_rotation, delay);
});