モバイル対応しました。 – コーディング編

モバイルメニューの作り方

前回紹介したスマホ用のメニューのコーディングについて紹介します。
初心者向けの備忘録的な記事になりますが、途中でつまずいた部分の解決策も書きますので、同じように悩んでいる方の助けに少しでもなれれば幸いです。

【前の記事はこちら】
  1. モバイル対応しました。 – デザイン編
  2. モバイル対応しました。 – コーディング編

紹介する部分

今回紹介する部分はこちらの画面下固定メニューになります。

下固定モバイル用メニューモバイルメニュー二層目モバイルメニュー検索フォーム

内容としては常に画面下に固定表示されて、メニューをタップすればメニュー一覧が出てきて、サイト内検索をタップでテキストフォームが出てくる。TOPに戻るボタンをタップでそのページの最上部までスクロール。
メニューとサイト内検索の2階層目には「閉じる」ボタンは設置せず、他のメニューをタップするかメニュー以外の領域をタップすると閉じるようにします。(ここが苦労しました)

HTML + CSS

CSSがゴチャゴチャするのでHTMLはPC用のものとは別に用意してメディアクエリーで表示を切り替えています。が、同じソースを利用しても問題なく再現出来ます。

ここでは特に難しいこともしていません。全部見えた状態にコーディングしていって、最後にdisplay: noneで見えなくするだけです。
そしてjQueryのクリックイベントで表示非表示を切り替えます。

CSSで作る三角形

CSSについて書くとするならばフキダシのようにするために付けた三角形くらいでしょうか。とても有名で簡単なテクニックなのでご存じの方も多いかと思いますが仕組みと共に紹介します。

まず、のちに三角形となる「空の要素」を作ります。これはあくまで見た目の飾りであって意味を持たないので、HTMLにdivなんかで作るのは不適切です。なのでCSSのbeforeやafterの疑似要素+content属性を使いましょう。

空要素が出来ました。これにボーダーを使って三角形を作ります。
仕組みは至って簡単です。

CSSで三角を作る1ボーダーです。
CSSで三角を作る2ボーダーは上下左右それぞれ別にプロパティを設定できます。
色を変えてみましょう。
CSSで三角を作る3ボーダーを太くしてみましょう。
ボーダーの境界はこのようになっています。
CSSで三角を作る4次に要素が大きさを持たなかったらどうでしょう。
形が見えてきましたね。
CSSで三角を作る51辺だけ残して他のボーダーの色を透明にすれば三角形の完成です!
CSSで三角を作る5三角形の大きさはボーダーの太さで調節してください。それぞれの太さを変えることで色々な形の三角形が作れます。

このようにしてCSSのみで三角形が作れるわけです。ソースコードは以下の様になります。

これはあくまで一例なので実際には色んな書き方が出来ます。
このままだと少し冗長な感じもするので以下の方がいいですかね。

位置は状況に応じてpositionを使うなりして調整してくださいね。
また、当ブログのモバイルメニューのようにこの三角形にボーダー(境界線)を付けたいという場合は三角形をbefore疑似要素とafter疑似要素で色違いで2つ作って、ずらすように重ねれば再現出来ます。
フキダシなどが簡単に作れますね。

CSSでフキダシの作り方

jQuery

クリックでサブメニューが現れるようにする。

普通にclickイベントを使い、ボタンをクリックした時にslideToggleエフェクトで2階層目が現れるようにするだけです。

ただ、これだけだとメニューボタンをクリックしてメニュー一覧を開き、そのままサイト内検索ボタンを押すとテキストフォームも現れ、この2つが重なってしまいます。

これを回避するために、それぞれのボタンをクリックした時に、もう一方の要素をhideエフェクトで隠れるようにします。要素が元から隠れている場合は何も起こらないのでif構文で条件分岐させなくとも、これだけで問題ありません。

以下の様になりました。

ちなみにslideToggleは通常、スライドダウンで現れ、スライドアップで隠れるようになっています。画面上固定のメニューの様に「上から下に要素が現れる場合」にしっくり来るアニメーションです。

しかし今回作りたかったのは逆。下から上にニュッと現れるメニュー(アニメーション)です。
ではこれをどうやって逆にすればいいのか。

答えは簡単、CSSの位置指定をtopではなくbottomで指定するだけで自動的に逆になってくれます。賢い奴です、jQuery…。

どこを触ってもサブメニューが閉じるようにする。

これは「指定した領域外をクリックしたら、その領域を閉じる」と考えがちなのですが、逆に作ります。
どこをクリックしても指定した領域が隠れるようにして、その領域内をクリックした時だけはそのイベントが起きないようにするんです。

ソースを見てみましょう。

ドキュメントをクリックしたらメニューが隠れるようにしています。

stopPropagationにより、メニュー自身をクリックしたときは、そのクリックイベントが親要素に伝わらないようにしています。これで、上で設定した「ドキュメントをクリックした時の挙動」が.menu内では起こらなくなります。

しかし、これだけだとまだ不十分です。この状態で試してみると、メニューボタンを押した時にメニュー一覧が開かなくなってしまいました。
勘の良い方はお気づきかもしれませんが、メニューボタン自体もドキュメントですので、ボタンも「要素を閉じるクリックイベント」から除外しなければいけません。

書き方は同じなので最終的に以下の様になります。

TOPに戻るボタン(スムーススクロール)

ついでにTOPに戻るボタン(ページ最上部に戻るボタン)の作り方を。

まずHTMLでボタンを作ります。

ここはなんでも良いです。pじゃなくてdivでもいいですし。aだけでもいいですし。
ちなみにa要素のhref属性が#topとなっていますが、これはid名やname名に”top”と付けられた要素がなければ、ドキュメントの先頭に移動するようHTML5では正式に決められています。
もし他に#topの要素があれば、そちらが優先されてそこまで移動します。

そして肝心なjQueryです。

これで.toTopをクリックした時にドキュメントのトップまでスクロールするようになりました。
しかし、これだけでは#topは使っていませんね。

せっかくなのでTOPへ戻るボタン以外のページ内アンカーリンクもスムーススクロールにしちゃおうと言うことでhref属性が#から始まるa要素全てをターゲットにして、その移動先をそのアンカー名が付いた要素にするわけです。
やってみましょう。

はい、これで先ほどのボタンを押してみてもスムースに移動しません。一瞬で移動してしまいます。

何が起きているのかと言うと、至極当然です。5行目では、そのid名を持った要素を見つけてターゲットとするわけですが、id名topの要素なんて作ってません。結局topに戻るボタンのhref属性には、bodyなりheaderなりに付けたid名を指定しなければならないのです。もしくはbodyなりheaderなりにtopとid名を付けるか。
スクリプトをtop用にもう一つ書いてもいいですし、#topの場合~なんて条件分岐させてもいいですが無駄なので、最上部にある要素にid名を付けるのが手っ取り早いでしょう。

遠回りしてしまいました、すみません。
スピードを変えたい場合は500の部分を任意の数字にしてください。単位はミリ秒です。
イージングはswingの部分を。プラグインを読み込まないとlenearとswingしか使えませんが。
(他のイージングを使いたい場合はjQuery Easing Pluginのサイトからどうぞ。)

スムーススクロールとハッシュの利用

上記のスムーススクロールの記述では、return falseでa要素の本来のリンク機能をとめているのでページの遷移が起こらずURLの最後に「#id名」がつきません。これは僕にとってプラスなのですが、人によってはマイナスになります。
例えば:targetの疑似クラスを使いたい場合や、ブラウザの戻るボタンで元の位置まで戻したい場合です。

そのような場合は次のようにします。

8行目でページを遷移させています。これで通常のリンクで飛ばしたようにハッシュがURLの最後に付きます。

あとがき

以上です。こんなへんてこな記事をここまで読んで頂いてありがとうございます。
自分のひっかかった部分だけ書こうと思っていたのに、基礎部分から書いてしまったりと長くなってしまいました…。文章を書くって本当に難しいですね。そういった面でもブログの運営って勉強になる気がします。

余談ですが本日、淹れたてのコーヒーを丸ごと落としてしまい悲惨な目に遭いました…。この記事を書いている途中だったのですが多少キーボードにもかかってしまい、言うことを聞かなくなってしまいました。
なので気をつけてはいますが誤字脱字が多いかもしれません。相当悲惨な状況です。Shiftは効かないわ、キーによっては2文字打たれたり違うキーになったりBackSpaceになったりめちゃくちゃです。Shiftキーはintuos(ペンタブ)のキーを利用しています…。笑

コーヒーはブラック派だったことがせめてもの救いです。
泣きたい。

コメント

この記事にはまだコメントがありません。

コメントする

メールアドレスが公開されることはありません。
* が付いている欄は必須項目です。

▲ Top of the page