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);
});