CSSでローディング画面を追加しないといけなくなって色々調べて悩んだので、まとめておきます。こういうのです。
つまり
いいたいことは以下のHTMLで全てです。
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>ローディングサンプル</title> <style> /* ローディングアイコンを含んだ全体の領域 */ #base-area{ position: relative; /* これを指定することでローディングアイコンの起点にする */ display: flex; /*ここから下はただレイアウト整えるだけ必須ではない*/ justify-content: center; flex-direction: column; } /* ローディングアイコン */ #loading { position: absolute; /* 親要素からの相対位置になるようにする */ z-index: 99; /* z軸を上げる */ top: 0; /* marginまでセットでいい感じに親要素の真ん中になる */ bottom: 0; left: 0; right: 0; margin: auto; width: 50px; /* ローディングアイコンのサイズになる */ height: 50px; border-radius: 50%; /* 50% 丸めるとまるくなる */ border: 8px solid #00FF00; /* 先の太さや色になる */ border-right-color: transparent; /* 右側を透過することで1/4だけ空いた円になる */ animation: spin 1s linear infinite; /* 1秒ごとのアニメーションの指定 */ } /* アニメーションの設定 */ @keyframes spin { 0% { transform: rotate(0deg); /* 0度回す */ } 50% { transform: rotate(180deg); /* 180度回す */ } 100% { transform: rotate(360deg); /* 360度回す */ } } #loading-button { height: 30px; } </style> </head> <body> <h1 style="text-align:center;">サンプルローディング画面</h1> <div id='base-area'> <!-- 初期時点ではローディングアイコンは非表示にする --> <div id='loading' style='display:none;'></div> <!-- このボタンを押したらロードして入力欄が更新されることにする --> <button id='loading-button' type='button'>リロード</button> <!-- 更新される入力欄 --> <textarea id='input-area' rows=20 cols=30 placeholder="サンプル入力欄"></textarea> </div> <script> // ボタンを押した際の処理を追加 var buttonNode = document.querySelector('#loading-button'); buttonNode.addEventListener('click', function(e){ // ボタン押された時点でローディングを表示 showLoding(); // 本来はここでWEB APIを呼び出して結果をまつ fetch('/') .then(function(res){ // 結果を得たらローディングを消す // ローディングが見えるように今回は1秒ずらしている setTimeout(hideLoading, 1000); }); }, false); function showLoding(){ var loadingNode = document.querySelector('#loading'); loadingNode.style.display = ''; } function hideLoading(){ var loadingNode = document.querySelector('#loading'); loadingNode.style.display = 'none'; } </script> </body> </html>
コメントみれば分かる話ですが、もう少し順をおってみていきます。
ローディングアイコン
CSSでローディングアイコンを作るには、まず丸いノードを作ります。
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>ローディングサンプル</title> <style> /* ローディングアイコン */ #loading { width: 50px; /* ローディングアイコンのサイズになる */ height: 50px; border: 8px solid #00FF00; /* 先の太さや色になる */ } </style> </head> <body> <div id='loading'></div> </body> </html>
こうすると、<div id='loading'></div>
の部分が以下の様に太枠の四角になります。
続いてborder-right-color: transparent;
を追加すると右辺が消えます。
さらにborder-radius: 50%;
で一片の空いた丸ができます。
これでローディング時に回すアイコンができました。次は回しましょう。animation: spin 1s linear infinite;
をまず追加します。1s
部分はアニメーションのサイクルを何秒で回すか、linear
は処理の速度を指定するもので、一定の速度でアニメーションを行うというものです。またinfinite
はアニメーションを無限にループするようにする指定です。
この指定に基づきspin
というアニメーションが適用されます。合わせて指定すると以下のようになります。
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>ローディングサンプル</title> <style> /* ローディングアイコン */ #loading { width: 50px; /* ローディングアイコンのサイズになる */ height: 50px; border: 8px solid #00FF00; /* 先の太さや色になる */ border-right-color: transparent; border-radius: 50%; animation: spin 1s linear infinite; /* 1秒ごとのアニメーションの指定 */ } /* アニメーションの設定 */ @keyframes spin { 0% { transform: rotate(0deg); /* 0度回す */ } 50% { transform: rotate(180deg); /* 180度回す */ } 100% { transform: rotate(360deg); /* 360度回す */ } } </style> </head> <body> <div id='loading'></div> </body> </html>
これでぐるぐる回る円ができました。あとはこれをタイミングに合わせて表示、非表示を切り替えるだけでローディング画面が実現できます。
ローディングのタイミング
大体は外部APIに処理を投げてその結果を待っている間に表示することが多いと思います。そのため、以下のようにボタンが押された時点でまずローディングアイコンを表示し、APIからレスポンスが戻った際のコールバックの中でローディングアイコンを非表示にすれば良いわけです。
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>ローディングサンプル</title> <style> /* ローディングアイコン */ #loading { width: 50px; /* ローディングアイコンのサイズになる */ height: 50px; border: 8px solid #00FF00; /* 先の太さや色になる */ border-right-color: transparent; border-radius: 50%; animation: spin 1s linear infinite; /* 1秒ごとのアニメーションの指定 */ } /* アニメーションの設定 */ @keyframes spin { 0% { transform: rotate(0deg); /* 0度回す */ } 50% { transform: rotate(180deg); /* 180度回す */ } 100% { transform: rotate(360deg); /* 360度回す */ } } </style> </head> <body> <button id='loading-button' type='button'>リロード</button> <div id='loading' style="display:none"></div> <script> // ボタンを押した際の処理を追加 var buttonNode = document.querySelector('#loading-button'); buttonNode.addEventListener('click', function(e){ // ボタン押された時点でローディングを表示 showLoding(); // 本来はここでWEB APIを呼び出して結果をまつ fetch('/') .then(function(res){ // 結果を得たらローディングを消す // ローディングが見えるように今回は1秒ずらしている setTimeout(hideLoading, 1000); }); }, false); function showLoding(){ var loadingNode = document.querySelector('#loading'); loadingNode.style.display = ''; } function hideLoading(){ var loadingNode = document.querySelector('#loading'); loadingNode.style.display = 'none'; } </script> </body> </html>
うまく動いています。あとはローディングアイコンの位置等を調整するだけでいいでしょう。