- 投稿日:2019-11-28T21:10:13+09:00
初心者によるプログラミング学習ログ 171日目
100日チャレンジの171日目
twitterの100日チャレンジ#タグ、#100DaysOfCode実施中です。
すでに100日超えましたが、継続。100日チャレンジは、ぱぺまぺの中ではプログラミングに限らず継続学習のために使っています。
171日目は
おはようございます
— ぱぺまぺ@webエンジニアを目指したい社畜 (@yudapinokio) November 27, 2019
webサイトコーディング課題
オブジェクトの位置とか修正#100DaysOfCode #早起きチャレンジ#駆け出しエンジニアと繋がりたい
- 投稿日:2019-11-28T13:24:00+09:00
年末まで毎日webサイトを作り続ける大学生 〜41日目 要素が画面内に入るとふわっとフェードインさせる〜
はじめに
こんにちは!@70days_jsです。
要素が画面内に入るとふわっとフェードインする機能を作りました。
今日は41日目。(2019/11/28)
よろしくお願いします。サイトURL
https://sin2cos21.github.io/day41.html
やったこと
今回はJavaScriptとCSSを併用するので、
まずJavaScriptで要素が画面内に入るのを検知する機能を作りました。
そのあとCSSでふわっとする機能をつけました。ではJavaScriptの方から説明していきます。
要素が画面内に入ったのを検知する(JavaScript)
まず考え方ですが、要素が画面内に入ったのを検知する機能というのは、「要素が任意の位置までくれば検知する」機能を作ればカバーできます。
というわけで、とりあえず画面の半分を越えれば要素の色が変わるコードを書きました。
画面の半分を越えれば青色が赤色に変わっているのが分かると思います。
ではhtmlからいきます。
html <body> <div class="blank">空白</div> <div class="fade-out"> test </div> <div class="blank">空白</div> <div class="fade-out"> test2 </div> <div class="blank">空白</div> </body>.fade-outクラスのついたdivの背景色を変えていました。
次はcss↓css body { margin: 0; } .blank { height: 200vh; background-color: yellow; } .fade-out { background-color: blue; } .fade-in { background-color: red; }画面の半分を越えれば.fade-inクラスをつける事で、背景色が青色から赤色に変わります。
次はJavaScript↓##メモ //色を変えたい要素(.fade-outクラスのついた要素)を取得する変数 let contents = document.querySelectorAll('.fade-out'); //画面の高さを取得する変数 let windowIn = window.innerHeight; //現在位置を格納する変数 let nowPosition; //付け加えるクラス名を格納する変数 let myClassName = 'fade-in'; //querySelectorAllは配列を返すので、for文で要素を1つずつ取り出します for (var i = 0; contents.length > i; i++) { //取り出した要素を格納します let content = contents[i]; //取り出した要素の位置を取得します let contentPosition = content.getBoundingClientRect().top; //スクロールが行われると関数を実行するイベントリスナーをつけます window.addEventListener('scroll', function () { //現在位置を取得します nowPosition = window.pageYOffset; //要素に.fade-inクラスがなければ実行します。あれば実行しません(これはやる必要ないかも) if (content.classList.contains(myClassName) === false) { //画面の高さ + 現在位置 が、要素の位置+画面の半分を越えれば.fade-inクラスをつけて色を変更します if (windowIn + nowPosition > contentPosition + (windowIn / 2)) { content.classList.add(myClassName); } } }, false) }大体のことはコメントに書いておきました。
最後の方にある(windowIn / 2)が画面の半分を表しています。
この部分を好きな位置に変更すれば、好きな位置で要素に何かしらの変化を与えることができるようになりますふわっと表示する機能をつける(CSS)
transformとtransitionを使って実装します。
今回は海外のウェブサイトでよくみる「要素が画面内に入ったらふわっとフェードインするあれ」の実装方法 | imasashi.net さんのサイトで紹介されていた書き方を使います。↓.fade-out { opacity : 0.1; transform : translate(0, 50px); transition : all 500ms; } .fade-in { opacity : 1; transform : translate(0, 0); }opacityで最初は薄い表示にしていますね。
特定の位置までくればopacityを1にして、translateを0にして、はっきりと元の位置で要素を表示するようになっていますね。組み合わせて、画面内に入るとふわっとフェードインさせる機能を作る
あとは上でやったことを組み合わせるだけでOKです。
body> <div class="blank"> <h1>Awesome Site</h1> <p>fugafuga</p> </div> <div class="box-wrapper"> <div class="box fade-out">box1</div> <div class="box fade-out">box2</div> <div class="box fade-out">box3</div> <div class="box fade-out">box4</div> <div class="box fade-out">box5</div> <div class="box fade-out">box6</div> <div class="box fade-out">box7</div> <div class="box fade-out">box8</div> <div class="box fade-out">box9</div> <div class="box fade-out">box10</div> </div> <div class="blank">空白</div> </body>フェードインするには長さが必要なので、場所取りのために.blankクラスのついたdivを書いています。
cssは何も変わりません。↓
.fade-out { opacity : 0.1; transform : translate(0, 50px); transition : all 500ms; } .fade-in { opacity : 1; transform : translate(0, 0); }次はJavaScriptですが、プラスアルファで何かしたくて、要素の背景をランダムで設定する機能をつけたりしました。↓
let contents = document.querySelectorAll('.fade-out'); let windowIn = window.innerHeight; console.log('windowの高さ: ' + windowIn); let nowPosition; let myClassName = 'fade-in'; for (var i = 0; contents.length > i; i++) { let content = contents[i]; let contentPosition = content.getBoundingClientRect().top; console.log('contentの位置: ' + contentPosition); randomColor(content); window.addEventListener('scroll', function () { nowPosition = window.pageYOffset; console.log('現在位置: ' + nowPosition); if (content.classList.contains(myClassName) === false) { if (windowIn + nowPosition > contentPosition + (windowIn / 4)) { content.classList.add(myClassName); } } }, false) } function randomRGB() { let r = Math.floor(Math.random() * 256); let g = Math.floor(Math.random() * 256); let b = Math.floor(Math.random() * 256); let rgb = [r, g, b]; return rgb; } function randomColor(element) { let rgb = randomRGB(); let r = rgb[0]; let g = rgb[1]; let b = rgb[2]; element.style.backgroundColor = 'rgba(' + r + ', ' + g + ',' + b + ', .5)'; }要素がフェードインする場所も、(windowIn / 4)で1/4に変えています。
ここはロジックとかではなく、試してみていい感じのところにしました。感想
サイトに動きがあると華がでるというか、なんかいいですね。。。
最後までお読みいただきありがとうございます。明日も投稿しますのでよろしくお願い致します。
参考
- 海外のウェブサイトでよくみる「要素が画面内に入ったらふわっとフェードインするあれ」の実装方法 | imasashi.net (https://imasashi.net/element-fadein.html)
とても分かりやすかったです。ありがとうございます!
- 投稿日:2019-11-28T09:58:09+09:00
各ブラウザを判定してCSSを適用する方法
ブラウザ毎にCSSのバグがあって、それらの対応方法を探していたら以下の記事が参考になりました。
ネタ元
https://www.kimagure-weblog.net/css/ie001/#IE大きく問題になるのはIE10-11でしょうが。早く消えろって感じです。
以下がIE対応方法。メディアクエリと同様の書き方です。
ネタ元にはFireFox,Chrome,Safariへの方法も書いてあります。@media all and (-ms-high-contrast: none){ /*ここにCSSを書く*/ }
- 投稿日:2019-11-28T01:01:40+09:00
CSSでスライドショーを作る
animationを初めて使って感動した
ページ↓ GitHub
https://kngy0306.github.io/SlideSample/
<body> <div class="slider"></div> </body>*{ padding: 0; margin: 0; background: #34495e; } .slider{ width: 800px; height: 550px; background: url(1.jpg); margin: 50px auto; animation: slide 15s infinite; } @keyframes slide{ 25%{ background: url(2.jpg); } 50%{ background: url(3.jpg); } 75%{ background: url(4.jpg); } 100%{ background: url(1.jpg); } }使用した画像 (Unsplashより)
1.jpg
https://images.unsplash.com/photo-1522383225653-ed111181a951?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1355&q=80
Photo by AJ on Unsplash2.jpg
https://images.unsplash.com/photo-1570896168675-7338d1e857cb?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1050&q=80
Photo by Mateus Elias Reis on Unsplash3.jpg
https://images.unsplash.com/photo-1506202687253-52e1b29d3527?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1050&q=80
Photo by Timothy Eberly on Unsplash4.jpg
https://images.unsplash.com/photo-1543802700-8a647cc92bd4?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1267&q=80
Photo by Aleksandra Rupar on Unsplash
CSSだけでもできることたくさんあってまだまだ驚くばかり
- 投稿日:2019-11-28T00:41:49+09:00
UIをきちんと考えた実装 - モーダルダイアログ (モーダルウィンドウ)
Webサイトやアプリなどのソフトウェア開発において、ユーザーのアクション・操作に対して何らかのレスポンスを返す、という相互的なUIを実装する機会があります。
こうしたUIに対し見た目先行で仕組み・機能への理解が足りないのか、疑問符のつく使われ方を見ることが割とあります。デザイナーであっても開発実装者であっても、そのUIの原型がどういった目的や仕様で生み出されたものなのかを調べるなどして、適用前に一度問い直してみることは大事かなと思います。
モーダルダイアログ (モーダルウィンドウ)とは?
なかでもよく誤用されるパーツの例として、今回は「モーダルダイアログ(モーダルウィンドウ)」を取り上げます。以下が大まかなモーダルダイアログの基本仕様です。
- アクションを実行すると画面最前面にウィンドウが現れ、選択肢を選ぶ、文字入力する、閉じるなど何かの操作をユーザーにさせる
- 別ウィンドウが表示され操作が終わるまでの間、操作の起点となった画面(背景または親画面)は操作を受け付けない
「モーダルウィンドウ」での検索ボリュームのほうが大きいのですが「モーダルダイアログ」名称のほうがこのUIの機能や役割がよりつかみやすいため、本記事ではモーダルダイアログとします。
モーダルダイアログUIのサンプル画像名称の定義
「モーダル」が正式名称かのような場面に多く出会います。モーダル(modal)とは英語で「形式上の~」、コンピューター用語としては「モードを持つ~」といった意味の形容詞で、モノ(名詞)のように呼ぶのは略称だとしても変です。
「ダイアログ」または「ダイアログボックス」とするのが適切でしょう。ダイアログ(dialog)は「対話」(名詞)を意味し、システムとユーザーによる対話形式のUIととらえるとしっくり来ます。
「ポップアップ(pop-up)」や「ライトボックス(Lightbox)」と呼ぶケースにも遭遇したことがあるのですが、それらよりもダイアログの名称がふさわしいでしょう。
OOUIにおけるモーダル、モードレス
せっかくモーダルという単語が出ているので、ソフトウェア開発において重要なOOUI(オブジェクト指向ユーザーインターフェース/オブジェクトベースUIとも)の考え方と併せて、このUIの定義を考えていきます。
コンピューターアプリケーションのインターフェース設計において、モードレス(modeless)とモーダル(modal)という2つの対比的な思想が存在します。以下、その意味についてソシオメディアの用語集から引用します。
モードレス
modeless
モードがない状態。ユーザーインターフェースをデザインする際に目指すべき状態。状況に依存した機能制限がなく、自由な手順でタスクを進行することができ、かつ特定の操作がシステムによって常に一定に解釈される状態。モーダル
modal
モードがある状態。つまり、システムが特定の機能の使用に制限された状態。ユーザーが自由に操作を行えなくなることと、モード別に機能の意味や振る舞いが変化することから、ユーザーインターフェースのデザインでは、できる限りモードを設けないほうがよいとされる。引用元:ソシオメディア | モードレス、ソシオメディア | モーダル
モードレスとは、コンピューターまたはWebサイト・アプリを操作する際に操作を限定されない自由な状態を指し、モーダルはその逆でシステム側から操作を限定された状態を指します。
まずユーザーが目的(オブジェクト)を選び、次に自由な操作・アクションが選択できることがGUI(グラフィカル・ユーザー・インターフェース)の基本思想であり、ソフトウェアデザインの出発点です。このオブジェクトベースなUIにおいて、モーダルは極力避けるべき状態とされています。
私たちはGUIユーザーとして、ときどき運営者都合で操作を制限された状態に遭遇します。それはビジネス側・売る側のロジックという強制力が働いた、不自由で押しつけがましいものになってはいないでしょうか。
画面を開いた際に即出現して「ぐぬぅ...」となるモーダルダイアログ例。ユーザーの行動の選択肢を狭めストレスを感じてしまう。disってないよモードレスダイアログという選択肢、あるいは...
モーダルダイアログがこの形態のUIの通名になっている感がありますが、モードレスダイアログも当然存在します。ダイアログがモーダル(モードが存在して制限されている)か、モードレス(モードが存在せず自由度が高い)かという状態の両軸を表しているだけです。
そして、よほどユーザーの操作を限定する必要がなければモーダルではなく、モードレスダイアログを検討・選択しても良いのかもしれません。ただでさえ不意に画面を遮って現れるのです。操作の自由はなるべくユーザーに委ねるほうがストレスにもつながらないでしょう。
モーダル(操作を絞る)がユーザーにとって有効なケース(必須の確認事項や限定されたプロセスなど)も確かに存在するので、使い分けやそもそもダイアログを利用しないことを慎重かつ適切に判断していきたいところです。
モードレスダイアログの例
Excelの「検索と置換」ダイアログは開いていても、背景画面の操作が可能。同様の機能はWebでも見ます機能定義と実装
それではここまでの流れを踏まえてモーダルダイアログの機能要件を定義し、Web UIとしての実装に入っていきたいと思います。
機能定義
- ボタンアクションで画面最前面にダイアログボックス(疑似的な別ウィンドウ)が現れる
- ダイアログが開いたら自身にフォーカスし、次のタブ操作でダイアログ内1番目のインタラクティブ要素にフォーカスする
- ダイアログ内では選択肢を選ばせるなどの限定的な操作にする
- ダイアログ表示中は、起点となる画面(背景または親画面)に対する操作やフォーカスを受け付けない ※
- ダイアログを閉じるボタンを設定する
- ダイアログ外をクリック・タッチした場合、ダイアログを閉じる ※
- [Esc](Escape)ボタン押下でダイアログを閉じる
- ユーザーが操作を終えたらダイアログを閉じ、何らかの値を返す
※マークのついた項目は、モードレスダイアログである場合は不要な機能を表します
実装方針
- HTMLの
dialog
要素(open
属性)とJavaScript APIのHTMLDialogElementを用いて実装する- 上記の技術は現状一部の主要ブラウザ(Chrome、Edge)しか実装対応していないため、Polyfill(dialog-polyfill)を組み込んで対応外ブラウザ(Firefox、Safari)にも対応する
- ダイアログが開いた際の背景または親画面は、明度を下げ操作不能を示す。暗い背景レイヤーはCSS
::backdrop
疑似要素で実装※ サンプルコードでは、
role
属性やaria-*
属性を用い支援技術による適切な情報伝達を意識しています。キーボード操作などで必要なフォーカス管理をJSで補い、CSSに構造依存しないUI実装を心がけていますコード
HTML・head内<script src="https://cdnjs.cloudflare.com/ajax/libs/dialog-polyfill/0.5.0/dialog-polyfill.min.js" defer></script> <script src="main.js" defer></script>HTML・body内<div id="modal-dialog" class="modal-dialog"> <h1>モーダルダイアログ</h1> <button type="button" id="dialog-open" class="dialog-open"> モーダルダイアログ<br> (モーダルウィンドウ)を開く </button> <dialog id="dialog-panel" class="dialog-panel" role="dialog" aria-describedby="d-message"> <p id="d-message" class="dialog-panel__message" role="document"> モーダルダイアログ(モーダルウィンドウ)<br> とはどんなものか知っていますか? </p> <div class="dialog-panel__buttons"> <button type="button" id="dialog-yes" class="dialog__button">はい</button> <button type="button" id="dialog-no" class="dialog__button">いいえ</button> </div> <button type="button" id="dialog-close" class="dialog__close" aria-label="このモーダルダイアログを閉じる"> × </button> </dialog> <p class="dialog-response"> ダイアログの返り値:<span id="return-value"></span> </p> </div>JavaScriptclass ModalDialog { constructor() { this.wrap = document.getElementById('modal-dialog'); this.open = document.getElementById('dialog-open'); this.dialog = document.querySelector("[role='dialog']"); this.yes = document.getElementById('dialog-yes'); this.no = document.getElementById('dialog-no'); this.close = document.getElementById('dialog-close'); this.returnSpan = document.getElementById('return-value'); // Polyfillを読み込む関数 dialogPolyfill.registerDialog(this.dialog); this.showDialog(); this.hideDialog(); this.respondValue(); } showDialog() { this.open.addEventListener('click', () => { this.dialog.showModal(); this.dialog.style.visibility = 'visible'; this.dialog.classList.remove('is-motioned'); this.dialog.setAttribute('tabindex', '0'); this.dialog.focus(); }); } hideDialog() { this.yes.addEventListener('click', () => { this.hideProcess('はい'); }); this.no.addEventListener('click', () => { this.hideProcess('いいえ'); }); this.close.addEventListener('click', () => { this.hideProcess('きみ、閉じるボタンを押したね...'); }); this.dialog.addEventListener('cancel', () => { this.hideProcess('Escapeボタン押しました?'); }); this.dialog.addEventListener('click', (event) => { if (event.target === this.dialog) { this.hideProcess('きみ、ウィンドウの外を押したね...'); } }); } hideProcess(resText) { this.dialog.close(resText); this.dialog.classList.add('is-motioned'); this.wrap.setAttribute('tabindex', '0'); this.wrap.focus(); setTimeout(() => { this.dialog.style.visibility = 'hidden'; }, 250); } respondValue() { this.dialog.addEventListener('close', () => { this.returnSpan.innerHTML = this.dialog.returnValue; }); } } const modalDialog = new ModalDialog();CSS/* 最低限のスタイル */ .modal-dialog { width: 100%; max-width: 64.25rem; margin: 2rem auto; } .dialog-open { display: block; width: 300px; margin: 4rem auto; padding: 1rem; border: 1px solid hsla(0, 0, 40%, 1); text-align: center; border-radius: 5px; } .dialog-panel { position: absolute; width: -moz-fit-content; width: -webkit-fit-content; width: fit-content; height: -moz-fit-content; height: -webkit-fit-content; height: fit-content; top: 15%; left: 0; right: 0; margin: auto; padding: 0; border: 2px solid hsla(0, 0, 40%, 1); background: hsla(0, 0, 100%, 1); border-radius: 5px; } /* native backdrop */ .dialog-panel::backdrop { background-color: rgba(0, 0, 0, .5); } /* polyfill backdrop */ .dialog-panel + .backdrop { position: fixed; top: 0; right: 0; bottom: 0; left: 0; background-color: rgba(0, 0, 0, .5); } .dialog-panel__message { margin: auto; padding: 4rem 3rem 0; } .dialog-panel__buttons { text-align: center; padding: 2rem 0 2.5rem; } .dialog__button { display: inline-block; min-width: 5rem; padding-top: .625rem; padding-bottom: .525rem; border: 1px solid hsla(0, 0, 40%, 1); border-radius: 5px; text-align: center; line-height: 1.5; } .dialog__button:not(:first-of-type) { margin-left: 1.75rem; } .dialog__close { position: absolute; top: 1rem; right: 1rem; width: 2.3rem; height: 2.3rem; background-color: hsla(0, 0, 20%, 1); font-size: 2rem; color: hsla(0, 0, 100%, 1); border-radius: 50%; }
HTMLDialogElement
Web APIのshow()
showModal()
close()
メソッドやプロパティなどのコードや仕様についても細かく解説したかったのですが、それ以外の説明がやや長くなってしまい、力尽きたのでここで終わります。実装の詳細については上記コードと下記参考URLをご参照ください。
参考URL