WEBサイトでよく見かける「スクロールすると浮かび上がってくるmenuボタン」、これの実装はJavaScriptで可能です。
今回は、その作成方法をまとめてみようと思います。
※完成はこんな感じです。↓
作成のおおまかな流れとしては、
・htmlにボタンを作成
・JavaScriptでscrollのイベント処理を記述
・cssのanimetionでふわっと感を演出
なお、JavaScriptついてはライブラリを使用しません。基本ネイティブなJavaScriptで作成します。
html
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 |
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link rel="stylesheet" href="css/style.css"> <title>target</title> </head> <body> <header> <div class="top"> <h1>Hallo!!</h1> <p id="target">menu</p> </div> <nav id="nav" class="closed"> <div id="la1">target1</div> <ul id="menu1" class="close"> <li>target1-2</li> <li>target1-3</li> <li>target1-4</li> </ul> <div id="la2">target1</div> <ul id="menu2" class="close"> <li>target1-2</li> <li>target1-3</li> <li>target1-4</li> </ul> <div id="la3">target1</div> <ul id="menu3" class="close"> <li>target1-2</li> <li>target1-3</li> <li>target1-4</li> </ul> <div id="la4">target1</div> <ul id="menu4" class="close"> <li>target1-2</li> <li>target1-3</li> <li>target1-4</li> </ul> </nav> <div id="back"></div> </header> <warapper> <main> <div class="kiji"> <img src="#"> <p>あかかかkっヴぃおdんヴぃおdんしおdんこdんc:おいんvc:dんcv:いんcv:いんv:おんヴぉvんv:んv</p> </div> <div class="kiji"> <img src="#"> <p>あかかかkっヴぃおdんヴぃおdんしおdんこdんc:おいんvc:dんcv:いんcv:いんv:おんヴぉvんv:んv</p> </div> <div class="kiji"> <img src="#"> <p>あかかかkっヴぃおdんヴぃおdんしおdんこdんc:おいんvc:dんcv:いんcv:いんv:おんヴぉvんv:んv</p> </div> <div class="kiji"> <img src="#"> <p>あかかかkっヴぃおdんヴぃおdんしおdんこdんc:おいんvc:dんcv:いんcv:いんv:おんヴぉvんv:んv</p> </div> <div class="kiji"> <img src="#"> <p>あかかかkっヴぃおdんヴぃおdんしおdんこdんc:おいんvc:dんcv:いんcv:いんv:おんヴぉvんv:んv</p> </div> <div class="kiji"> <img src="#"> <p>あかかかkっヴぃおdんヴぃおdんしおdんこdんc:おいんvc:dんcv:いんcv:いんv:おんヴぉvんv:んv</p> </div> <div id="ura" class="uramenu">menu</div> <div id="move" class="topmove">top</div> </main> <side> <div class="kiji2"> <img src="#"> <p>あかかかkっヴぃおdんヴぃおdんしおdんこdんc:おいんvc:dんcv:いんcv:いんv:おんヴぉvんv:んv</p> </div> <div class="kiji2"> <img src="#"> <p>あかかかkっヴぃおdんヴぃおdんしおdんこdんc:おいんvc:dんcv:いんcv:いんv:おんヴぉvんv:んv</p> </div> <div class="kiji2"> <img src="#"> <p>あかかかkっヴぃおdんヴぃおdんしおdんこdんc:おいんvc:dんcv:いんcv:いんv:おんヴぉvんv:んv</p> </div> </side> </warapper> <footer>footer </footer> <script src="js/menu.js"></script> <script src="animejs/anime.min.js"></script> </body> </html> |
main閉じタグ前の「div id ura」がmenuボタンとなります。
main閉じタグ前の「div id move」がtopへ戻るボタンとなります。
他の記述は適当にかいているので、無視してください。
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 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 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 |
body { padding: 0; margin: 0; } header { background: orange; } header h1 { margin: 0; padding: 10px; } .top { display: flex; } .top p { margin-left:auto; padding:10px; z-index: 1000; } .closed { position: fixed; top: 0; bottom: 0; right :0; width: 0; overflow: hidden; background: yellow; transition: 0.5s; z-index: 20; } .opened { width: 50%; overflow: auto; } .backs { position: fixed; top: 0; bottom: 0; left: 0; right: 0; background: black; opacity: 0.8; transition: 0.5s; } li { list-style: none; padding: 10px; text-align: center; border: solid 1px; background: skyblue; } nav { padding: 70px 0; } ul { padding: 0; margin: 0; } #la1, #la2, #la3, #la4 { padding: 10px; text-align: center; border: solid 1px; background: green; } .close { max-height: 0; overflow: hidden; transition: 0.5s; } .open { max-height: 100vh; z-index: 50; } main { background: skyblue; } main img { width: 120px; height: 100px; padding: 10px; } .kiji { display: flex; border: solid 1px; margin: 10px; } .kiji2 { border: solid 1px; margin: 10px; } .uramenu { position: fixed; bottom: 20px; right: 20px; background: white; padding: 10px; opacity: 0; visibility:hidden; cursor: pointer; } .topmove { position: fixed; bottom: 20px; left: 20px; background: white; padding: 10px; opacity: 0; visibility:hidden; cursor: pointer; } .uraopen { animation: menu 3s; animation-fill-mode: forwards; visibility:visible; } @keyframes menu { 33% { opacity: 0.3; } 66% { opacity: 0.6; } 100% { opacity: 1; } } side { background: pink; display: block; width: 100%; } side img { display: block; width: 120px; height: 100px; padding: 10px; margin-left: auto; margin-right: auto; } side p { padding: 0 10px; } footer { background: green; text-align: center; padding: 10px 0; } @media screen and (min-width: 601px) { body { max-width: 1000px; } header p { display: none; } warapper { display: flex; } main { width: 70%; } side { width: 30%; } } |
.uramenu(menuボタン).topmove(topへ戻るボタン)でボタンの位置と形を整えます。position:fixed;は指定した位置を固定しスクロールに追従するので必須です。
画面がページのTOPにある場合(初期の状態)はボタンを消しておきたいので、「visibility:hidden;」を記述しておきます。また、「opacity:0;」で透明にしておきます。
後にJavaScriptでスクロールのイベント処理を発生させたとき、.uraopenを付与し、menu名のアニメーションを実行させます。また、「visibility:visible;」を記述し、この段階で消していた要素を出現させておきます。
アニメーションの長さは3秒とし、1秒ごとに背景が濃くなるようにしています。
アニメーションが終わると、実行された内容が消えてしまう(今回の場合だと浮かび上がったボタンが消えてしまう)ので、.uraopenに「animation-fill-mode: forwards;」を記述しておきます。これでアニメーション後も変化した状態が続くようになります。
そのほかの記述は無視でOKです。
JavaScript
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 |
const target = document.getElementById("target"); const nav = document.getElementById("nav"); const back = document.getElementById("back"); const la1 = document.getElementById("la1"); const la2 = document.getElementById("la2"); const la3 = document.getElementById("la3"); const la4 = document.getElementById("la4"); const manu1 = document.getElementById("manu1"); const manu2 = document.getElementById("manu2"); const manu3 = document.getElementById("manu3"); const manu4 = document.getElementById("manu4"); const ura = document.getElementById("ura"); const px = 100; const move = document.getElementById("move"); addEventListener('scroll', function() { //ここからスクロールイベント if (scrollY > px) { ura.classList.add("uraopen"); move.classList.add("uraopen"); } else { ura.classList.remove("uraopen"); move.classList.remove("uraopen"); } }); //スクロールイベントここまで move.addEventListener("click", () => { anime({ targets: "html, body", scrollTop: 0, dulation: 600, easing: 'easeOutCubic', }); }); target.addEventListener("click", () => { if (nav.className === ("closed")){ nav.classList.add("opened"); back.classList.add("backs"); target.textContent = "閉じる"; }else {nav.classList.remove("opened"); back.classList.remove("backs"); target.textContent = "menu"; } }); back.addEventListener("click", () => { back.classList.remove("backs"); nav.classList.remove("opened"); target.textContent = "menu"; }); la1.addEventListener("click", () => { menu1.classList.toggle("open"); }); la2.addEventListener("click", () => { menu2.classList.toggle("open"); }); la3.addEventListener("click", () => { menu3.classList.toggle("open"); }); la4.addEventListener("click", () => { menu4.classList.toggle("open"); }); ura.addEventListener("click", () => { nav.classList.add("opened"); back.classList.add("backs"); target.textContent = "閉じる"; }); |
スクロールイベントの場合は、
window.addEventListener(“scroll”, function() {処理内容});
と記述します。
windowは省略可能なので、addEventListener(“scroll”, function() {処理内容});でもOKです。
処理内容にifを使って分岐させていますが、これは「scrolly(縦方向のスクロール)>px」は真。つまり、定数pxに100が入っているので、縦方向のスクロール位置が100pxを超えれば真の処理、となります。
真の処理では、前途したボタンのclassにuraopen classを付与するので、アニメーションが開始する仕組みです。
偽の場合は、縦の位置が100px未満の場合となるので、removeでuraopen classを外しています。つまり、ボタンの表示は消えます。