IMUZA.com

Xserver<<WordPress(ConoHa)<<はてなブログ

ホーム / はてなテーマ / はてなブログテーマ開発(8)スマホ用 offcanvasmenu の作り方

はてなブログテーマ開発(8)スマホ用 offcanvasmenu の作り方

2018/10/11 はてなテーマ, はてなブログ

はてなブログテーマ開発(8)スマホ用 offcanvasmenu の作り方

別ブログ「@半径とことこ60分」のテーマ変更を機に、はてなブログのテーマ開発について書いています。今回はスマホ用のナビゲーションメニューを作ります。

はてなブログテーマ開発(1)
はてなブログテーマ開発(2)
はてなブログテーマ開発(3)
はてなブログテーマ開発(4)
はてなブログテーマ開発(5)
はてなブログテーマ開発(6)(Javascript 記載の漏れがありました)
はてなブログテーマ開発(7)

  • スマホのナビゲーションメニュー
    • ナビゲーションメニュー実装の構想
  • サイドバーにナビゲーションメニューを作成
  • Javascript で要素を移動する
  • CSS

スマホのナビゲーションメニュー

ブログは、日々記事を書き連ねていきますので、どうしてもサイト内の見通しが悪くなります。特にスマホですと、新着情報などの、デスクトップではサイドバーに表示しているものが記事の下にいってしまいます。

そのため、何らかのボタンをタップしますと上下左右のいずれかからナビゲーションメニューが飛び出してくる offcanvas menu を使う場合が多いようです。はてなブログにも実装しようと思います。

実装方法はいろいろありますので、その一例です。このサイトでも過去に他の方法を記事にしたことがあります。

  • デスクトップはメニューバー、スマホはオフキャンバスメニュー cms-style(2) – IMUZA.com
  • はてなブログテーマ=Simple Responsive with Menubar – IMUZA.com
  • はてなブログテーマ=とことこ with Menubar – IMUZA.com
  • スクリプトなし :target でアニメーションをスタートさせる – IMUZA.com

まだ他にもあるような気がしますが、思い出せません(笑)。

なお、以下の内容は「@半径とことこ60分」に実装しています。

ナビゲーションメニュー実装の構想

以下、ブレイクポイントを 768px ひとつで作成していますので、768px 以上をデスクトップと表示しています。

  • スマホでは、タップで右から飛び出す offcanvas menu 、デスクトップでは、ブログタイトル右に常時表示
  • サイドバーにナビゲーションメニューの HTML コードを書き、javascript で #blog-title-content 内に移動する
  • サイドバーのカテゴリーモジュールを javascript でナビゲーションメニュー内に移動する
    (直書きでもいいが、カテゴリーを追加変更する予定があるため)
  • デスクトップではカテゴリーリストをサブメニューとしているので、タッチデバイス用にタッチで hover クラスを追加する

サイドバーにナビゲーションメニューを作成

今回は、タイトルブロックに移動してしまいますのでどこに入れてもいいのですが、ヘッダのタイトル下は他の用途に使う予定があり、フッタもあれこれ詰め込んでいますのでサイドバーに作成しています。

<a class="offcanvastoggle" href="javascript:void(0);" onclick="javascript:toggleoffcanvas();return false;">MENU</a>
<ul class="offcanvasmenu">
<li>
<a class="search-title" href="#">検索</a>
<div class="search-body">
<!-- 検索モジュールのコードを直書きしている -->
<form class="search-form" role="search" action="サイトアドレス/search" method="get">
<input type="text" name="q" class="search-module-input" value="" placeholder="記事を検索" required>
<input type="submit" value="検索" class="search-module-button" />
</form>
<!-- ここまで -->
</div>
</li>
<li id="category-wrapper">
<a class="category-title" href="#">カテゴリー</a>
</li>
<li>
<ul class="sub-offcanvasmenu">
<li><a href="/archive">記事一覧</a></li>
<!-- フッタへスムーズスクロールする -->
<li><a href="javascript:void(0);" onclick="javascript:scrollToContent('#contactus');return false;">Contuct Us</a></li>
<!-- ここまで -->
</ul>
</li>
</ul>

サイドバーの HTML モジュールに放り込みます。

Javascript で要素を移動する

<script>
function toggleoffcanvas(){
if( !document.body.classList.contains('offcanvas')) {
document.body.classList.add('offcanvas');
// iPhoneの場合、背景のスクロールを止める
var elem = document.getElementsByClassName('offcanvasmenu')[0]; // このクラス名を間違えていました(下記参照)
elem.addEventListener('touchmove', function(e) {
var scroll = elem.scrollTop;
var range = elem.scrollHeight - elem.offsetHeight - 1;
if (scroll < 1) {
e.preventDefault();
elem.scrollTop = 1;
} else if(scroll > range) {
e.preventDefault();
elem.scrollTop = range;
}
});
} else {
document.body.classList.remove('offcanvas');
}
}
(function(){
// サイドバーのひとつ目の要素をブログタイトルボックスに移動する
var elements = document.getElementById('box2-inner').children;
var titleDiv = document.getElementById('blog-title-content');
titleDiv.appendChild(elements[0]);
// メニュー内にカテゴリーを移動する
// [2]はサイドバー内で3つ目のモジュール、ただし、上でひとつ移動させているので実際は4つ目
var catWrap = document.getElementById('category-wrapper');
catWrap.appendChild(elements[2].getElementsByClassName('hatena-urllist')[0]);
// メニュー内の li 全てに touch または mouseover イベントを付加し、hover クラスをトグル設定する
var menulists = document.getElementsByClassName('offcanvasmenu')[0].getElementsByTagName('li');
Array.prototype.forEach.call(menulists, function(menulist){
if((('createTouch' in document) || ('ontouchstart' in document)) && ('orientation' in window)) {
menulist.addEventListener('touchstart', function(e) {
menulist.classList.toggle('hover');
});
} else {
menulist.addEventListener('mouseover', function(e) {
menulist.classList.add('hover');
});
menulist.addEventListener('mouseout', function(e) {
menulist.classList.remove('hover');
});
}
});
}());
</script>

フッタに入れます。

「iPhoneの場合、背景のスクロールを止める」は、以下の記事の時はうまくいっていたのですが、今確認したところうまくいっていません。背景がスクロールしていしまいます。iPhone は面倒くさい(涙)。

(2018.10.14)iPhoneの件は勘違いでした。クラス名を offcanvasmenu に変更したことを忘れていただけでした(ペコリ)。上のスクリプトで背景はスクロールしません。

iPhoneでモーダルの背景のスクロールを止める – IMUZA.com

CSS

.offcanvastoggle {
display: block;
color: #fff;
background: #fff;
height: 50px;
width: 50px;
border-radius: 50%;
position: relative;
}
.offcanvastoggle:hover {
color: #fff;
}
.offcanvastoggle::before, .offcanvastoggle::after {
content: "";
background: #87140d;
position: absolute;
right: 0;
left: 0;
top: 0;
bottom: 0;
margin: auto;
width: 30px;
height: 3px;
-webkit-transition: all 300ms;
transition: all 300ms;
}
.offcanvastoggle::before {
-webkit-box-shadow: 0px -10px 0px #87140d;
box-shadow: 0px -10px 0px #87140d;
}
.offcanvastoggle::after {
-webkit-box-shadow: 0px 10px 0px #87140d;
box-shadow: 0px 10px 0px #87140d;
}
@media (min-width: 768px) {
.offcanvastoggle {
display: none;
}
}

まず、ハンバーガーメニューです。

  • テキストは text-indent: -9999px; で飛ばす方法もありますが、ハンバーガーメニューにイメージを使いませんので色を背景と同じにしています。SEO 上はよくないのか? でも、MENU ですからね…。
  • ハンバーガーメニューのボーダーは、before, after の疑似要素を使い、box-shadow で3本にしています。
  • タップで、box-shadow を消し、ボーダーを 45度回転させています。
  • デスクトップでは、要素自体を非表示にしています。

.offcanvasmenu {
margin: 0;
position: fixed;
overflow-y: auto;
height: 100%;
display: block;
right: -100vw;
z-index: 10;
padding: 50px 20px;
-webkit-box-sizing: border-box;
box-sizing: border-box;
width: 100vw;
background: #fff;
-webkit-transition: right 500ms;
transition: right 500ms;
}
@media (min-width: 768px) {
.offcanvasmenu {
display: block;
position: relative;
right: auto;
width: auto;
background: transparent;
padding: 0;
overflow-y: visible;
}
}
.offcanvasmenu li {
list-style: none;
}
@media (min-width: 768px) {
.offcanvasmenu li {
display: inline;
}
.offcanvasmenu li a {
padding: 5px 10px;
text-decoration: none;
color: #454545;
}
}
@media (min-width: 768px) {
.offcanvasmenu li.hover > div {
-webkit-transform: scale(1);
transform: scale(1);
}
}
.offcanvasmenu > li {
position: relative;
}
.offcanvasmenu .search-title {
display: none;
}
@media (min-width: 768px) {
.offcanvasmenu .search-title {
display: inline-block;
}
}
@media (min-width: 768px) {
.offcanvasmenu .search-body {
position: absolute;
width: 50vw;
max-width: 350px;
right: 0;
background: rgba(135, 20, 13, 0.8);
padding: 30px;
border-radius: 10px;
-webkit-transform: scale(0);
transform: scale(0);
-webkit-transition: all 300ms;
transition: all 300ms;
-webkit-transform-origin: top right;
transform-origin: top right;
}
}
.offcanvasmenu .search-body .search-form {
background: #fff;
}
.offcanvasmenu #category-wrapper {
margin: 0;
padding: 0;
margin: 20px 0 40px;
}
.offcanvasmenu #category-wrapper .category-title {
text-align: center;
pointer-events: none;
display: block;
text-decoration: none;
color: #454545;
font-weight: 700;
}
@media (min-width: 768px) {
.offcanvasmenu #category-wrapper .category-title {
display: inline-block;
pointer-events: auto;
font-weight: 100;
}
}
@media (min-width: 768px) {
.offcanvasmenu #category-wrapper .hatena-urllist {
position: absolute;
width: 300px;
background: rgba(135, 20, 13, 0.8);
right: 0;
border-radius: 10px;
padding: 20px;
-webkit-transform: scale(0);
transform: scale(0);
-webkit-transition: all 300ms;
transition: all 300ms;
-webkit-transform-origin: top right;
transform-origin: top right;
}
}
@media (min-width: 768px) {
.offcanvasmenu #category-wrapper .hatena-urllist li {
display: block;
}
}
@media (min-width: 768px) {
.offcanvasmenu #category-wrapper .hatena-urllist li a {
display: block;
color: #fff;
}
}
@media (min-width: 768px) {
.offcanvasmenu #category-wrapper .hatena-urllist li a:hover {
background: rgba(135, 20, 13, 0.8);
color: rgba(255, 255, 255, 0.5);
text-decoration: none;
}
}
@media (min-width: 768px) {
.offcanvasmenu #category-wrapper.hover .hatena-urllist {
-webkit-transform: scale(1);
transform: scale(1);
}
}
.offcanvasmenu .sub-offcanvasmenu {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-ms-flex-pack: distribute;
justify-content: space-around;
}
@media (min-width: 768px) {
.offcanvasmenu .sub-offcanvasmenu {
display: -webkit-inline-box;
display: -ms-inline-flexbox;
display: inline-flex;
padding: 0;
}
}
.offcanvasmenu .sub-offcanvasmenu li:first-child a::before {
content: "\f022";
font-size: 55px;
}
.offcanvasmenu .sub-offcanvasmenu li:last-child a::before {
content: "\f04b";
font-size: 45px;
margin-top: 10px;
}
.offcanvasmenu .sub-offcanvasmenu li a {
display: block;
text-decoration: none;
}
.offcanvasmenu .sub-offcanvasmenu li a::before {
display: block;
line-height: 1;
text-align: center;
color: #87140d;
font-family: blogicon;
}
@media (min-width: 768px) {
.offcanvasmenu .sub-offcanvasmenu li a::before {
display: none;
}
}
/* ハンバーガーメニューをタップで body 要素にクラス offcanvas が追加される */
body.offcanvas {
overflow: hidden;
}
.offcanvas .offcanvasmenu {
right: 0;
}
.offcanvas .offcanvastoggle::before {
-webkit-transform: rotate(45deg);
transform: rotate(45deg);
-webkit-box-shadow: none;
box-shadow: none;
}
.offcanvas .offcanvastoggle::after {
-webkit-box-shadow: none;
box-shadow: none;
-webkit-transform: rotate(-45deg);
transform: rotate(-45deg);
}
/* 中身を移動しているので抜け殻非表示 */
.hatena-module-category {
display: none;
}
  • offcanvas menu は、これもいろいろ方法はありますが、今回は、position:absolute; を指定して、デバイス幅分右にずらして非表示にし、ハンバーガーメニューをタップで右からスライドさせています。
  • デスクトップでは、検索、またはカテゴリーをマウスオーバーまたはタップしますと、検索窓、またはカテゴリーメニューを表示します。

かなり煩雑になってしまいました。

Joomla! 3.8.13 セキュリティリリースが公開されています
はてなブログで Google Web Fonts を使ってみる
Twitter
Facebook
ブックマーク
LINEで送る

最初のサイドバー

最新記事

2023/05/25

WordPress:リビジョン削除、回数制限

2023/05/10

WordPress:裏技的サイトリニューアル

2023/04/28

XserverへのSSH接続がエラーになってしまった

2023/04/16

正規表現の最短一致でミスる

2023/04/4

WordPress:公開中サイトをサブディレクトリでリニューアルし公開する

最新記事を一覧で見る

よく読まれている記事

よく読まれている記事を一覧で見る

カテゴリー

  • はてなブログ215
  • WebTips109
  • javascript98
  • Joomla!88
  • Wordpress70
  • Windows68
  • CSS63
  • Joomla!更新53
  • Linux49
  • はてなテーマ45
  • Google34
  • Plamo33
  • はてなプラグイン25
  • php23
  • Node.js18
  • Ubuntu16
  • SASS16
  • laravel415
  • Chrome11
  • cms-style10
  • iPhone9
  • Git入門6
  • ConoHa WING6
  • genesis6
  • Python5
  • Android5
  • PC全般4
  • Facebook4
  • スマートフォン4
  • Xserver3
  • Firefox3
  • 静的サイトジェネレーター3
  • SSD3
  • Docker3
  • Blankslate3
  • Twitter2
  • Mactype2
  • GitHub2
  • youtube1
  • はてなブクマ1
  • rails入門1
  • 映画1

Footer

My Web Sites

  • @半径とことこ60分
  • そんなには褒めないよ。映画評
  • IMUZA.com
  • GitHub

Related Sites

  • WordPress公式
  • WordPress関数リファレンス
  • PHPマニュアル

Contact Us

  • お問い合わせフォーム
  • Twitter
  • Facebook
  • Feedly

Copyright © 2023 · IMUZA.com