jQueryでマテリアルデザイン風の一覧からの詳細表示
マテリアルデザインでは一覧から詳細情報の画面に遷るときに、
選択した一覧の中の要素が画面いっぱいに広がっていくように詳細の画面が表示されることが推奨されています。
マテリアルデザインでなくても、スマホのアプリなどでは見かける機会は増えてきていると思います。
この動きをjQeuryで表現するにはどうすればいいのか、検討してみました。
検討して作ってみたものがこちら↓
方法
今回検討してみた方法では、以下の様な手順を踏みます。
- 一覧のリンクをクリックしたときに、リンク先のページ内のコンテンツをAjaxで取得
- クリックした要素の位置と大きさを取得し、その上に、Ajaxで取得したコンテンツを被せる
- 被せた要素を画面いっぱいに広げ、URLにハッシュ(#で始まるページ内のリンク)を追加
- 戻るボタンが押されたら、詳細の要素を一覧の元の位置に戻して、詳細の要素を削除
コードは以下のとおり
HTML(head内)
1 2 | <script src="js/jquery-1.11.3.min.js"></script> <script src="js/jquery.ba-hashchange.min.js"></script> |
今回はjQueryに加えて、戻るボタンの動きをハッシュから読み取るために「jquery.ba-hashchange.min.js」という以下のページでダウンロードできるjQueryプラグインを読み込んでいます。
Ben Alman >> jQuery hashchange event
このプラグインを使うことで、以下の様な形式で、ハッシュの変更があったタイミングでスクリプトを実行することができます。
1 2 3 | $(window).hashchange(function(){ //スクリプト }); |
ただ、元のコードだと、比較的新しいjQueryでユーザーエージェントの判定でエラーが出るため、
以下のコードをプラグインのコメントの後に追加し、
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | /* * jQuery hashchange event - v1.3 - 7/21/2010 * http://benalman.com/projects/jquery-hashchange-plugin/ * * Copyright (c) 2010 "Cowboy" Ben Alman * Dual licensed under the MIT and GPL licenses. * http://benalman.com/about/license/ */ //↓↓ここから追加↓↓ var userAgent = window.navigator.userAgent.toLowerCase(), appVersion = window.navigator.appVersion.toLowerCase(), isIe = false; if (userAgent.indexOf('msie') > -1 || userAgent.indexOf('trident') > -1) { /*IE6.7.8.9.10.11*/ isIe = true; } //↑↑ここまで追加↑↑ |
本体のコードの以下の部分を変更します
1 | $.browser.msie |
↓
1 | isIe |
HTML(body内)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <main> <section class="newsArchiveSection"> <h2>News</h2> <ul> <li> <a href="detail.html"> <figure><img src="images/image01_sp.jpg" alt="イメージ"></figure> <h3>タイトルタイトルタイトルタイトル</h3> <p class="date">2015.10.13</p> <p class="description">詳細内容詳細内容詳細内容詳細内容詳細内容詳細内容詳細内容詳細内容詳細内容詳細内容</p> </a> </li> ・・・ </ul> </section> </main> |
一覧のHTMLコードは以上のようなコードです。
CSS
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | main { max-width: 960px; padding: 30px 0; margin: 95px auto 0; } /*一覧の要素の表示*/ .newsArchiveSection ul li { list-style: none; } .newsArchiveSection ul li a { display: block; padding: 15px; border-bottom: solid 1px #ccc; } .newsArchiveSection ul li a:hover { background: #f6f6f6; } .newsArchiveSection ul li:first-child a { border-top: solid 1px #ccc; } .newsArchiveSection ul li figure { width: 135px; padding-right: 15px; float: left; } .newsArchiveSection ul li figure img, .detailSection figure img { max-width: 100%; } .newsArchiveSection ul li h3 { font-size: 1.25em; } /*通常の詳細の表示*/ .detailSection { padding: 15px; } .detailSection h3 { margin-bottom: 0.5em; font-size: 2em; } .detailSection .date { margin-bottom: 1em; } .detailSection .description { line-height: 2; } .detailSection figure { width: 33.3%; padding-right: 15px; padding-bottom: 15px; float: left; } /*遷移中の詳細の表示*/ .detailSection.active { background: #fff; position: absolute; top: 0; left: 0; z-index: 50; box-shadow: 0 1px 1px rgba(0, 0, 0, 0.3); overflow: hidden; } .detailSectionInner { max-width: 960px; margin: 0 auto; } .detailSection.active h3 { margin-bottom: 0; font-size: 1.25em; } .detailSection.active .date { margin-bottom: 0; } .detailSection.active .description { line-height: 1.5; } .detailSection.active figure { width: 135px; padding-right: 15px; float: left; } |
CSSで一覧と詳細のスタイルを設定します。
ここでのポイントは、
Ajaxで読み込まれる予定の.detailSectionの要素にactiveというクラスがあった場合は、
一覧と同じような見た目で表示しておくことです。
jQuery
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 | $(function() { //ユーザーエージェントの判定 var userAgent = window.navigator.userAgent.toLowerCase(), body = "body"; if (userAgent.indexOf("msie") > -1 || userAgent.indexOf("trident") > -1 || userAgent.indexOf("firefox") > -1 ) { /*IE6.7.8.9.10.11*/ body = "html"; } //一覧要素の位置と大きさの変数を初期化 var posX = 0, posY = 0, width = 0, height = 0, scrollTopPos = 0; //一覧のリンクをクリックしたら実行 $(".newsArchiveSection a").on("click", function() { var thisElm = $(this), //クリックした要素を変数に格納 href = thisElm.attr("href"); //クリックした要素のリンク先を取得 //一覧要素の位置と大きさの情報を取得 posX = thisElm.position().left; posY = thisElm.position().top; width = thisElm.outerWidth(); height = thisElm.outerHeight(); scrollTopPos = $(body).scrollTop(); //リンクをクリックしたときのスクロール位置を保存 //詳細を表示 $(".newsArchiveSection").after("<div class='detailSection active'></div>"); $(".detailSection").load(href + " .detailSectionInner", function() { //詳細を一覧のクリックした要素に被せるように表示 $(".detailSection").css({ "width": width + "px", "height": height + "px", "left": posX + "px", "top": posY + "px" }); //詳細ページの見た目にアニメーションで近づける $(".detailSection").animate({ "width": "100%", "height": $("main").outerHeight() + $("h2").outerHeight() + "px", "padding": $("h2").outerHeight() + 110 + "px 15px 15px", "left": 0, "top": 0 }, 500); $(body).animate({ scrollTop: 0 }, 500); $(".detailSection h3").animate({ "margin-bottom": "0.5em", "font-size": "2em" }, 500); $(".detailSection .date").animate({ "margin-bottom": "1em" }, 500); $(".detailSection .description").animate({ "line-height": "2em" }, 500); $(".detailSection figure").animate({ "width": "33%", "padding-bottom": "15px" }, 500, function() { $(".detailSection").css("box-shadow", "none"); $("header .back").fadeIn(200); location.href = "#/" + href; //ハッシュをURLに追加 }); }); return false; }); //headerの戻るボタンが押されたら、ブラウザの戻るボタンが押されたときと同じ動作をする $("header .back").on("click", function() { history.back(); return false; }); //ブラウザの戻るボタンが押されたら、詳細を一覧の場所に戻して削除 $(window).hashchange(function(){ //戻った先で、詳細が残っていて、尚且つ、ハッシュがないときだけ実行 if($(".detailSection").size() > 0 && String(location.href).indexOf("#") < 0) { $(".detailSection").css("box-shadow", "0 1px 1px rgba(0, 0, 0, 0.3)"); //詳細の見た目と位置を、アニメーションで一覧に近づける $(".detailSection").animate({ "width": width + "px", "height": height + "px", "padding": "15px", "left": posX + "px", "top": posY + "px" }, 500); $(".detailSection h3").animate({ "margin-bottom": "0", "font-size": "1.25em" }, 500); $(".detailSection .date").animate({ "margin-bottom": "0" }, 500); $(".detailSection .description").animate({ "line-height": "1.5em" }, 500); $(".detailSection figure").animate({ "width": "140px", "padding-bottom": "0" }, 500, function() { $("header .back").fadeOut(200); $(".detailSection").remove(); }); //スクロール位置も遷移前に戻す $(body).animate({ scrollTop: scrollTopPos }, 500); } }); }); |
ポイントは、実際にはページ移動せずに、移動しているように見せることで、
ブラウザの戻るボタンが押されたときに、一覧へ戻るアニメーションを実現することです。
実際のページに利用する時はもう少し調整が必要だと思いますが、
ヒントとしてご活用ください。
参考にさせていただいたサイト
Author Profile
NINOMIYA
Webデザイナー兼コーダー出身のフロントエンド開発者です。 UXデザインやチーム開発の効率化など、勉強中です。
SHARE