- 投稿日:2019-05-21T23:32:27+09:00
focusで高機能ドロップダウンメニュー(どこをタッチしても閉じる、CSSのみで簡単に)
この記事について
僕のサービスのテストユーザーから、「閉じるボタンでしかメニューが閉じられないのがストレス」と言われたので、どこを触っても閉じるドロップダウンメニューを作りました。
意外とCSSだけで簡単に作れました。(部活補助アプリClubCloudの開発を行っています。β版公開中です(宣伝)。)
通常のドロップダウンメニュー
ドロップダウンメニューの閉じ方は主に3つあります。
1はメニューの表示/非表示と紐づいているcheckboxがoffになることで、
2はページ遷移によって(厳密には閉じていない)、
3は主にJavaScriptの操作で
メニューが閉じます。しかし、1~3のように特定のボタンを押さないとメニューを閉じられないのは、ユーザーにとってストレスが大きいようです。
出来れば、画面の関係のない場所を触るだけでメニューが閉じて欲しい!
出来れば、1~3も併用したい!
出来れば、CSSだけで実装したい!出来ます。めちゃ簡単に。
以下、実装ベースの話なのでボタンをラベルと言い換えています。focusを使う!
さて、何を使うかというと、focus要素を使います。
focus要素を使えば、他の場所を触ることで元のfocusが外れるので、それをメニューを閉じるためのトリガーに出来るからです。
つまり、
開くラベル:focus ~ メニュー
というセレクタをうまく使います。ざっくり説明します。
1. 最初、メニューは画面外に隠しておきます。
2.「開くラベル」をクリックすると「開くラベル」にfocusが当たります。
2. 同時に、メニューが出現します。
2. さらに同時に、focusされた「開くラベル」は画面外に固定され、「閉じるラベル」が同じ位置に出現します。
3. メニューは、「開くラベル」にfocusが当たっているときのみ出現するので、画面内のどこをクリックしてもメニューは閉じます。「開くラベル」は画面外にあるのでどこかクリックすれば必ず他の要素にfocusが移るからです。コード
<label class="menu_label_open" tabindex="0">開く</label> <label class="menu_label_close">閉じる</label> <div class="menu"> <ul> <li><a href="http://google.com">メニュー1</a></li> <li><a href="http://google.com">メニュー2</a></li> <li><a href="http://google.com">メニュー3</a></li> <li><span>キャンセル</span></li> </ul> </div>label{ cursor: pointer; } .menu{ transform: translate3d(0,-200%,0); transition: .3s ease-in-out; -webkit-transition-delay: .1s; transition-delay: .1s; } .menu_label_open:focus ~ .menu{ transform: translate3d(0,0,0); } .menu_label_open:focus ~ .menu_label_close{ display: block; } .menu_label_open:focus{ position: fixed; top:-100%; } .menu_label_close{ display: none; } .menu ul{ display: inline-block; width:100%; padding:0; list-style: none; border:1px solid black; background-color: #fff; text-align: center; cursor: pointer; } .menu ul li:hover{ background-color: rgba(0,0,0,0.2); } .menu ul li:not(:last-child){ border-bottom:0.5px solid black; } .menu ul li span,a{ text-decoration: none; display: block; padding:20px 0; width:100%; }このドロップダウンメニューのキモをいくつか書いておきます。
<!--label要素にfocusを有効にするため--> <label class="menu_label_open" tabindex="0">開く</label>/*メニューを画面外に隠しておく*/ .menu{ transform: translate3d(0,-200%,0); }/*メニューを表示(元の位置に戻す)*/ .menu_label_open:focus ~.menu{ transform: translate3d(0,0,0); }/*メニューが開いているときは「閉じるラベル」を表示*/ .menu_label_open:focus ~ .menu_label_close{ display: block; }/*メニューが開いているときは「開くラベル」を画面外に隠す(display:noneだとfocusが強制的に外れてしまう)*/ .menu_label_open:focus{ position: fixed; top:-100%; }/*メニューが閉じるのを少し待ってあげないと、リンクのクリック終了時にはリンクの位置がズレていてリンクを踏んだことにならない*/ .menu{ -webkit-transition-delay: .3s; transition-delay: .3ms; }開いたままにしたいときは
ちなみに、特定の要素(特にメニューの中の要素)を触ったときにはメニューは開いたままに、という場合は、下記のjqueryコードをHTMLに入れてください。
その要素を触ったときに瞬時に「開くラベル」にfocusを戻すので、メニューは閉じません(transition-delayが効いているのでメニューは少しも動かないで済みます)。<script> $(document).on('click', '.hoge', function(){ $('.menu_label_open').focus() }) </script>まとめ
なかなかいい感じのドロップダウンメニューかなと思います。
checkboxを使うよりもHTMLはスッキリします。
閉じるボタンをずっと使い続けて、他の場所を触っても閉じることに気づくユーザーは少ないかもしれませんが…。
装飾は最低限にしてあるので、ラベルやメニューをいい感じにして使ってみてください!
- 投稿日:2019-05-21T23:14:30+09:00
CSSの圧縮
CSSの圧縮
Water.cssに感化されて開発を始めた私ですが、他の開発者のファイルが小さいのは何故かという素朴な疑問を持ちました。
○○○.min.×××?
ライブラリ等を使っているとしばしば見掛けるこの"○○○.min.×××"という名前。
正直気にもしませんでした。
jQueryにしろ何にしろ、そうあるからそう使っているだけでした。Water.cssを覗き見
すると、minは改行などの無駄な文字列を消し小さくしたものだと気付きました。
そして、これこそがファイルが小さく済む理由なのだと理解しました。実際にしてみる
「CSS 圧縮」
出てきたのは沢山のツールたち。
オンラインで使うものもあれば、コマンドで実行するものもありました。
取り敢えず私は、refresh-sf.comを使ってみました。
すると、1,000文字近く短くなったのです。
状態 行数 文字数 比率 圧縮前 244 3,587 1(△0%) 圧縮後 1 2,227 0.63(△37%) 行数については置いておいて、これはとても驚きました。
しかし納得はできなかった
だが、実際に圧縮後のソースを読んでみると、まだまだ小さくなれそうです。
オンラインなどは汎用的なシステムであるが故に、後から上書きするから取り敢えず最初に0にしておくだとか、そういった処理はなされません。
酷いとこにあっては、同じ値が6箇所も充てられていました。
それを無くすだけでも十分に小さくなります。自力で小さくしてみる
今回私が圧縮を試みたのは開発中のDoc.cssです。
一部の要素に対して作用し、可読性を高める目的で開発を始めました。
だからこそ、こういった規則性があるだとかは自分が一番知っています。
なので私は、自力で小さくしようと考えました。display値で絞る
今回、Doc.cssにより影響を受ける要素はそこまで多くなく、displayがblockであるものに関しては基本的に同じmarginやpaddingを与えています。
なのでまずはdisplayがblockか否かでグループ分けをしてみました。
displayの値 タグ block blockquote,button,code,h1,h2,h3,h4,h5,h6,hr,img,ol,p,table,textarea,ul blockじゃない a,li,tbody,td,tfoot,th,thead,tr tableに関しては諸事情でblockに分類されましたが、のちほど上書きするので気にしません。
特有の値を除外する
例えばcolorだとかoutlineだとか、意図的に一部の要素にのみ充てたい値があります。
それだけを選出し、一時的にファイルの後ろの方に追いやりました。
こうすることで特有でない値が残る
ので、どれが共用可能かがはっきりします。編集後
大分小さくなりました。
作業のために改行はしてありますが、ここで圧縮前後と比較してみます。
状態 行数 文字数 比率 圧縮前 244 3,587 1(△0%) 圧縮後 1 2,227 0.63(△37%) 編集後 38 1,716 0.48(△52%) 圧縮後のファイルから文字数を500近くの削減に成功しました。
では最後に、改行を処理したものも比較してみます。
状態 行数 文字数 比率 圧縮前 244 3,587 1(△0%) 圧縮後 1 2,227 0.63(△37%) 編集後 38 1,716 0.48(△52%) 最終版 1 1679 0.47(△53%) 最終的に、53%近くの削減に成功しました。
感想
共用化可能な部位を探すのは単純に頭の体操になるだけでなく、プログラムを組む上でも大分重要な観点だろうと思いました。
こことここは共用化できる、ここは無理そうだと、そういった判断は実際の仕事の上でも活用できます。
便利なツールに頼るのは楽ですが、たまにはこうして一手間かけてみるのも良いものだなと感じました。最後に
今回、私が開発を進めたCSSはDoc.cssと名付け、Github上に公開した。
特徴としては以下が挙げられる。
- 一部の要素に対し適用される。
- 圧縮版は2kB以下と小型である。
- ドキュメントとして読みやすい。(←私的見解)
サンプルはこちらから確認できるので、是非ともご覧頂き、感想や意見、指摘を頂きたい。
- 投稿日:2019-05-21T15:02:52+09:00
html要素にfont-size: 62.5%;を指定したのに1.6emが16pxにならなかった話
二度目の投稿です。
今回は失敗からなるほど!!!!!が生まれたので
反省含めて載せます
結論から言えば、何もおかしくないし当たり前でした一箇所だけだしなんでやと思いました
こちらコードです
(base.scss) html { font-size: 62.5%; } (header.scss) h1 { font-size: 3.6rem; margin: 1.6em 0 1.6em 12em; @include mq() { font-size: 2.4rem; margin-left: 1.6em; } }他の部分は思った通りになるんです、、、
検証ツールで実際何pxになっているのかみてみます
57.6px
どうしてええええええええええw
emのコンパイル後の値ってfont-size × emの値だから
emのコンパイル後の値 ÷ emの値で何倍かわかるのでは?57.6 ÷ 1.6 = 36
36…あ、font-size!?となりました
あれでも62.5%で指定したのになぜ、、、、、emとremの知識がごちゃ混ぜになってました
rem
文書のルート要素、つまりhtml要素のfont-sizeを基準にするremはroot要素
em
親要素のfont-sizeを基準に大きさを計算するemは親要素
つまり馬鹿だった
当たり前だった、h1ではfont-sizeを上書きしているから
font-size 36pxを基準にemも計算される
36 × 1.6 = 57.6
何もおかしくなかった
私が書いたコードを忠実に再現してくれただけだったそして学んだfont-sizeを親要素に指定してたらemが思う通りにならないってことは、、、
よく検証ツールとかでみてて疑問だったことがある
なんでいちいちテキスト系divタグとかで囲ってんの???
しかも空だし、わからない、、、これの謎が今回馬鹿をしたことでわかりました
親要素に左右されるので、親要素に当たるところにfont-sizeのrem指定があると良くない
だからdivタグで空の親要素を作ってたのか!!!!!
text系でmarginやpadding取らないようにしようと感じましたすごい初歩的な話ですが間違えて、馬鹿したことで理解が深まりました
これからも頑張ります!
ここまで読んでくれて、ありがとうございます
それでは、また!