Help us understand the problem. What is going on with this article?

Turn.jsを用いて雑誌や本のようなページを作成してみよう!

Turn.jsとは

こんな風に雑誌や本のようにページをめくるエフェクトをつけられるプラグインです。

公式サイトはこちら

output.gif

必要なもの

jQuery ver 1.3以上
turn.js(公式サイトからダウンロード)

作成したもの(宣伝)

Turn.jsを使用して自己紹介ページを作成してみました。(一番最初のgifアニメのやつです)是非ご覧ください

https://masibw.github.io/portfolio/

また、このサイトのソースコードもこちらにあります。参考になれば幸いです。

https://github.com/masibw/portfolio

基本

まずは1番シンプルなものを作成してみましょう

simple.gif

example.html
<!DOCTYPE html>
<head>
<link rel="stylesheet" href="example.css" />
<script src="https://code.jquery.com/jquery-3.4.1.min.js"
    integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" 
    crossorigin="anonymous"></script> <!--jQueryをCDNから取得-->
<script type="text/javascript" src="turn.js"></script>
</head>
<body>
<div id="flipbook">
    <div>page1</div>
    <div>page2</div>
    <div>page3</div>
    <div>page4</div>
    <div>page5</div>
    <div>page6</div>
</div>
</body>
<script type="text/javascript">
    $("#flipbook").turn({
    });
</script>
</html>
example.css
div {
  color: white; /* 文字色を白色に */
}

.odd {
  background-color: blue;/* 奇数ページを青色に */
}
.even {
  background-color: green;/* 偶数ページを緑色に */
}

#flipbook {
  width: 400px; /* flipbook自体の横幅なので各ページは200px */
  height: 400px;
  margin: 10% 20%; /* 一番左端だとたまに見切れるので適当に移動 */
}

指定したdiv要素の中に含まれる第一階層のdiv要素をページとして認識してくれます。

oddやevenクラスを指定することで奇数ページや偶数ページ用の指定もできます。

サイズは上記のようにCSSでも設定できますし下記のようにJavaScriptで指定することもできます。(jsでの単位はpx)

example.html
<script type="text/javascript">
    $("#flipbook").turn({
          width:400,
          height:400,
    });
</script>

様々なクラス

hard

ページをめくるエフェクトがハードカバーのようになります

fixed

ページをめくっても残ります

own-size

指定したページに独自の大きさを設定できます

これらを組み合わせると表紙が大きく中身は一回り小さいものが作れるのでこんな感じになります。

fixed.gif

example.html
<!DOCTYPE html>
<head>
<link rel="stylesheet" href="example.css" />
<script src="https://code.jquery.com/jquery-3.4.1.min.js"
    integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script>
<script type="text/javascript" src="turn.js"></script>
</head>
<body>
<div id="flipbook">
    <div class="hard own-size">page1</div>
    <div class="hard own-size">page2</div>
    <div>page3</div>
    <div>page4</div>
    <div class="hard own-size">page5</div>
    <div class="hard own-size">page6</div>
</div>
</body>
<script type="text/javascript">
    $("#flipbook").turn({
        when:{
            turning: function(e,page,view){
                const book = $(this),
                pages=book.turn("pages");
                 if (page >= 2) $("#flipbook .p2").addClass("fixed");
                else $("#flipbook .p2").removeClass("fixed");

                if (page < book.turn("pages"))
                    $("#flipbook .p5").addClass("fixed");
                else $("#flipbook .p5").removeClass("fixed");

            }
        }
    });


</script>
</html>
example.css
div {
  color: white;
}

.odd {
  background-color: blue;
}
.even {
  background-color: green;
}

.p1,
.p2,
.p5,
.p6 {
  width: 250px;
  height: 500px;
  background-color: brown;
}

#flipbook {
  width: 400px;
  height: 400px;
  margin: 10% 20%;
}

各ページについては自動的にp(ページ数)クラスが付与されるためこちらを使用してcssやjsで操作します。

インデックスタブをつける

特定のページに飛ぶインデックスタブを付けるにはタブ用のdiv要素を作成しignore="1"を付与します。

スクリーンショット 2019-07-23 21.12.58.png

example.html
<!DOCTYPE html>
<head>
<link rel="stylesheet" href="example.css" />
<script src="https://code.jquery.com/jquery-3.4.1.min.js"
    integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script>
<script type="text/javascript" src="turn.js"></script>
</head>
<body>
<div id="flipbook">
    <div ignore="1" class="tabs">
        <div class="left"></div>
    </div>
    <div class="hard own-size">page1</div>
    <div class="hard own-size">page2</div>
    <div>page3</div>
    <div>page4</div>
    <div class="hard own-size">page5</div>
    <div class="hard own-size">page6</div>
    <div ignore="1" class="tabs">
        <div class="right"></div>
    </div>
</div>
</body>
<script type="text/javascript">
    function updateTabs() { //タブ更新用
        var tabs = {
            2: "page2", //左にページ数右にタブに表示される文字を記載
            3: "page3",
            4: "page4",
            5: "page5"
        },
            left = [],
            right = [],
            book = $(" #flipbook"),
            actualPage = book.turn("page"),
            view = book.turn("view");

        for (var page in tabs) {
            var isHere = $.inArray(parseInt(page, 10), view) != -1;

            if (page > actualPage && !isHere)
                right.push('<a href="#page/' + page + '">' + tabs[page] + "</a>");
            else if (isHere) {
                if (page % 2 === 0)
                    left.push(
                        '<a href="#page/' + page + '" class="on">' + tabs[page] + "</a>"
                    );
                else
                    right.push(
                        '<a href="#page/' + page + '" class="on">' + tabs[page] + "</a>"
                    );
            } else left.push('<a href="#page/' + page + '">' + tabs[page] + "</a>");
        }

        $(" #flipbook .tabs .left").html(left.join(""));
        $(" #flipbook .tabs .right").html(right.join(""));
    }

    $("#flipbook").turn({
        when:{
            turning: function(e,page,view){ //ページがめくられ始めたとき
                const book = $(this),
                pages=book.turn("pages");
                 if (page >= 2) $("#flipbook .p2").addClass("fixed");
                else $("#flipbook .p2").removeClass("fixed");

                if (page < book.turn("pages"))
                    $("#flipbook .p5").addClass("fixed");
                else $("#flipbook .p5").removeClass("fixed");

            },
            turned: function(e,page,view){ //ページがめくられ終わったとき
                var book=$(this);
                if(page!=1&& page!=book.turn("pages")) //1ページ目と最後のページの場合はタブを消す
                $(" #flipbook .tabs").fadeIn(500);
                else $("#flipbook .tabs").hide();
                updateTabs(); //タブの更新を呼ぶ
            }
        }
    });
</script>
</html>
example.css
div {
  color: white;
}

.odd {
  background-color: blue;
}
.even {
  background-color: green;
}

.p1,
.p2,
.p5,
.p6 {
  width: 250px;
  height: 500px;
  background-color: brown;
}

#flipbook {
  width: 400px;
  height: 400px;
  margin: 10% 20%;
}
/* タブについて*/
.tabs .left {
  -webkit-writing-mode: vertical-lr; /*縦書き 参考 https://qiita.com/RinoTsuka/items/3e3eaaba8cddb6ff08e9 */
  -ms-writing-mode: tb-lr;
  writing-mode: vertical-lr;
  display: block;
  z-index: 10000; /* 一番上に表示されるように(いらないかも?)*/
  position: relative;
  left: -40px;
  text-orientation: upright;
  width: 30px;
  text-align: left;
}

.tabs .right {
  -webkit-writing-mode: vertical-rl;
  -ms-writing-mode: tb-rl;
  writing-mode: vertical-rl;
  display: inline-block;
  z-index: 100000;
  position: relative;
  right: -40px;
  width: 30px;
  float: right;
  text-orientation: upright;
}

.tabs a {
  text-decoration: none;
  color: #333;
  margin: 5px;
  border: 1px solid;
  background-color: #98fb98;
  display: inline-block;
  padding: 5px;
}

/* 角丸にする*/
.tabs .left a {
  border-top-left-radius: 10px;
  border-bottom-left-radius: 10px;
}

.tabs .right a {
  border-top-right-radius: 10px;
  border-bottom-right-radius: 10px;
}

.tabs a:hover {
  /* マウスオーバー時透明度を0.8にしポインターカーソルにする*/
  cursor: pointer;
  opacity: 0.8;
}

公式のサンプルには横書きで本の上部につけるインデックスタブも用意されているので是非参考にしてください。

スマホ用表示について

現在のように両開きはスマホなどでは非常に見にくいですので単ページ表示にしましょう

display:'single'

このオプションを追加すればOKです

スマホではタブなどもせまくて必要ないと思いますので再度シンプルな状態に戻したいと思います。

single.gif

注意: single表示ではhard,fixed,own-size,odd,even クラスを使用しているとうまく動作しなくなります。

ですので実際はwindowsizeを取得して

$('.hard').removeClass("hard").removeClass("fixed").removeClass("own-size");
などで条件分岐により削除する必要があります

CSSもodd,evenを使用しないものに変更する必要があります。

example.html
<!DOCTYPE html>
<head>
<link rel="stylesheet" href="example.css" />
<script src="https://code.jquery.com/jquery-3.4.1.min.js"
    integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script>
<script type="text/javascript" src="turn.js"></script>
</head>
<body>
<div id="flipbook">
    <div>page1</div>
    <div>page2</div>
    <div>page3</div>
    <div>page4</div>
    <div>page5</div>
    <div>page6</div>
</div>
</body>
<script type="text/javascript">
    $("#flipbook").turn({
        display:'single',
    });
</script>
</html>
example.css
div {
  color: white;
}

.p1,
.p2,
.p3,
.p4,
.p5,
.p6 {
  width: 250px;
  height: 500px;
  background-color: brown;
}

#flipbook {
  width: 400px;
  height: 400px;
  margin: 10% 20%;
}

おわりに

今回はTurn.jsを使用して詰まったところを中心に記載しました。中々日本語での解説記事もなく解決に時間がかかったので誰かの役に立てば幸いです。

最後になりましたがこれらのコードや解説は動くことを重点に置いており、効率や使用方法が適切であるとは言い切れませんのでご注意ください。また、アップデートなどにより執筆時とは違う可能性もあります。

何か内容に問題等ありましたら連絡ください

公式サイトにもドキュメント・サンプルが充実しているため是非ご覧ください。

参考サイト及びライセンス表示

CSS3で縦書きにする方法と挙動

Turn.js

/**
* turn.js 4th release
* turnjs.com
* turnjs.com/license.txt
*
* Copyright (C) 2012 Emmanuel Garcia
* All rights reserved
**/

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away