Title Image

ブログ制作記 #8

投稿日

忙しかったこともあり、だいぶ期間が空きましたが続きをやっていきます。

ブログタイトルを考える

いくら何でも「技術ブログ」は単純すぎます。

テック島開拓記」(てっくとうかいたくき or てっくしまかいたくき or てっくじまかいたくき)

と命名しました。技術の島を開拓していくという意味がこめられています(?)。

(友人の案を参考に考えました。ありがとう。)

タイトルの変更はプロジェクト直下のhugo.tomltitleを書き換えればよいです。

hugo.toml
baseURL = 'https://tech.n-island.dev/'
languageCode = 'ja-jp'
title = 'テック島開拓記'
theme = 'my-theme'
pagenate = 10

また、上部タイトルをクリックしてホームに戻れるように改良します。

layouts/partials/header.htmlを以下のように書き換えることで、サイト上部のタイトル部分を画像にできるようにしました。

layouts/partials/header.html
{{ with resources.Get (.Site.Param "titleImagePath") }}
  <a href={{ site.Home.Permalink }}>
    <img class="title-image" src="{{ .RelPermalink }}" alt="Title Image">
  </a>
{{ else }}
  <h1 class="site-title">
    <a href={{ site.Home.Permalink }}>{{ site.Title }}</a>
  </h1>
{{ end }}
{{ partial "menu.html" (dict "menuID" "main" "page" .) }}

このように変更したうえでassets/images/title.pngなどの画像を置き、hugo.tomlに以下のように書き込むとタイトル部分が画像になります。

hugo.toml
[params]
titleImagePath = 'images/title.png'

ハンバーガーメニューを作る

PC表示ならメニューを横並びにしても問題は起きないのですが、スマホ表示だとメニュー欄が窮屈でこれ以上増やせない状態です。

スマホ表示の現状

これを解消するため、主にCSSを書き換えることでスマホで表示した際はハンバーガーメニューになるようにします。

デザインは一旦置いておき、要件は以下のとおりです。

ハンバーガーメニューを実装する方法はいくつもありますが、今回はチェックボックスを使う方法で実装します。

layouts/partials/menu.htmlを開き、navタグ部分を以下のように書き換えます。

layouts/partials/menu.html
<nav>
    <input type="checkbox" id="menu-toggle">
    <label for="menu-toggle" class="menu-icon">
        <span class="menu-open">&#9776;</span> <!-- ☰ ハンバーガー -->
        <span class="menu-close">&times;</span> <!-- ✖ 閉じる -->
    </label>
    <label for="menu-toggle" class="overlay"></label>
    <ul class="menu">
        {{- partial "inline/menu/walk.html" (dict "page" $page "menuEntries" .) }}
    </ul>
</nav>

inputタグでチェックボックスを置いていて、チェックの有無でハンバーガーメニューの開閉を管理します。

また、labelタグのfor属性を用いてハンバーガーメニューのボタンと、ハンバーガーメニュー以外の場所へのタップをチェックボックスに紐づけています。

続いて、CSSを以下のように設定します。スマホ表示の際のみハンバーガーメニューが表示されるようにしており、見た目も若干調節しています。

assets/css/main.css
/* ハンバーガーメニュー */
.menu-icon {
  display: none;
  font-size: 32px;
  cursor: pointer;
  position: absolute;
  top: 20px;
  right: 30px;
  z-index: 1001;
}

.menu-icon .menu-close {
  display: none;
  /* 初期状態は非表示 */
}

/* メニューのトグル用チェックボックス */
#menu-toggle {
  display: none;
}

/* 半透明のオーバーレイ(デフォルトは非表示) */
.overlay {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: rgba(0, 0, 0, 0.5);
  /* 半透明 */
  visibility: hidden;
  opacity: 0;
  transition: opacity 0.3s ease-in-out, visibility 0.3s;
  z-index: 999;
}

/* スマホ向けレイアウト */
@media (max-width: 768px) {
  .menu-icon {
    display: block;
    position: fixed;
  }

  /* メニューの初期状態: 画面外に隠す */
  nav ul {
    display: flex;
    flex-direction: column;
    position: fixed;
    top: 0;
    right: -300px;
    /* 初期位置は画面外 */
    width: 300px;
    height: 100%;
    background: white;
    border-left: 1px solid #ccc;
    padding: 0;
    padding-top: 100px;
    transition: right 0.3s ease-in-out;
    box-shadow: -2px 0 5px rgba(0, 0, 0, 0.2);
    z-index: 1000;
  }

  nav ul li {
    margin: 15px 0;
    width: 100%;
  }

  nav ul li a {
    display: block;
    font-size: 20px;
    width: 100%;
  }

  /* メニューが開いたとき */
  #menu-toggle:checked+.menu-icon+.overlay {
    visibility: visible;
    opacity: 1;
  }

  #menu-toggle:checked+.menu-icon+.overlay+ul {
    right: 0;
  }


  /* ☰ → ✖ に切り替え */
  #menu-toggle:checked+.menu-icon .menu-open {
    display: none;
  }

  #menu-toggle:checked+.menu-icon .menu-close {
    display: block;
  }
}

/* メニューオープン中に body に追加されるクラス */
.no-scroll {
  overflow: hidden;
  height: 100vh; /* iOS対策 */
}

ハンバーガーメニューを開いたときに背景をスクロールできないようにするため、以下のJSを書いてチェックボックスがオンの時にno-scrollをbodyに付与してスクロールしないようにします。

assets/js/main.js
// ハンバーガーメニューを開いているときにスクロールを無効にする
document.addEventListener('DOMContentLoaded', function () {
  const menuToggle = document.getElementById('menu-toggle');

  menuToggle.addEventListener('change', function () {
    if (menuToggle.checked) {
      document.body.classList.add('no-scroll');
    } else {
      document.body.classList.remove('no-scroll');
    }
  });
});

ハンバーガーメニューのマークにアニメーションを付ける

前章でハンバーガーメニューを付けましたが、アニメーションが欲しくなったので付けてみます。

まずはlayouts/partials/menu.htmlに書かれているnavタグの部分を以下のように変更します。

layouts/partials/menu.html
<nav>
<input type="checkbox" id="menu-toggle">
<label for="menu-toggle" class="menu-icon">
    <div class="hamburger"></div>
</label>
<label for="menu-toggle" class="overlay"></label>
<ul class="menu">
    {{- partial "inline/menu/walk.html" (dict "page" $page "menuEntries" .) }}
</ul>
</nav>

そのうえで、assets/css/main.cssを以下のように書き換えます。

assets/css/main.css
/* ハンバーガーメニュー */
.menu-icon {
  display: none;
  font-size: 32px;
  cursor: pointer;
  position: absolute;
  top: 25px;
  right: 30px;
  z-index: 1001;
}

.menu-icon .menu-close {
  display: none;
  /* 初期状態は非表示 */
}

/* メニューのトグル用チェックボックス */
#menu-toggle {
  display: none;
}

/* 半透明のオーバーレイ(デフォルトは非表示) */
.overlay {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: rgba(0, 0, 0, 0.5);
  /* 半透明 */
  visibility: hidden;
  opacity: 0;
  transition: opacity 0.3s ease-in-out, visibility 0.3s;
  z-index: 999;
}

/* スマホ向けレイアウト */
@media (max-width: 768px) {
  .menu-icon {
    display: block;
    position: fixed;
    cursor: pointer;
    margin: auto;
    height: 50px;
    -webkit-tap-highlight-color: transparent;
    outline: none;
  }

  /* メニューの初期状態: 画面外に隠す */
  nav ul {
    display: flex;
    flex-direction: column;
    position: fixed;
    top: 0;
    right: -300px;
    /* 初期位置は画面外 */
    width: 300px;
    height: 100%;
    background: white;
    border-left: 1px solid #ccc;
    padding: 0;
    padding-top: 100px;
    transition: right 0.3s ease-in-out;
    box-shadow: -2px 0 5px rgba(0, 0, 0, 0.2);
    z-index: 1000;
  }

  .menu-icon .hamburger {
    background: black;
    width: 30px;
    height: 3px;
    position: relative;
    transition: background 10ms 200ms ease;
    transform: translateY(20px);
  }
  .menu-icon .hamburger:before, .menu-icon .hamburger:after {
    transition: top 200ms 250ms ease, transform 200ms 50ms ease;
    position: absolute;
    background: black;
    width: 30px;
    height: 3px;
    content: "";
  }
  .menu-icon .hamburger:before {
    top: -10px;
  }
  .menu-icon .hamburger:after {
    top: 10px;
  }
  
  #menu-toggle:checked ~ .menu-icon .hamburger {
    background: transparent;
  }
  #menu-toggle:checked ~ .menu-icon .hamburger:after, #menu-toggle:checked ~ .menu-icon .hamburger:before {
    transition: top 200ms 50ms ease, transform 200ms 350ms ease;
    top: 0;
  }
  #menu-toggle:checked ~ .menu-icon .hamburger:before {
    transform: rotate(45deg);
  }
  #menu-toggle:checked ~ .menu-icon .hamburger:after {
    transform: rotate(-45deg);
  }

  nav ul li {
    margin: 15px 0;
    width: 100%;
  }

  nav ul li a {
    display: block;
    font-size: 20px;
    width: 100%;
  }

  /* メニューが開いたとき */
  #menu-toggle:checked+.menu-icon+.overlay {
    visibility: visible;
    opacity: 1;
  }

  #menu-toggle:checked+.menu-icon+.overlay+ul {
    right: 0;
  }
}

/* メニューオープン中に body に追加されるクラス */
.no-scroll {
  overflow: hidden;
  height: 100vh; /* iOS対策 */
}

以下のサイトを参考にさせていただきました。

選択時に水色になるのをなくす

CSSのデフォルト設定で、画像やリンクを触ったときに水色になってしまいます。これをなくすために、assets/css/main.cssに以下を書き込みました。

assets/css/main.css
a, button, input, textarea, label, img {
  -webkit-tap-highlight-color: transparent;
  outline: none;
}

おわりに

レスポンシブ対応もできてばっちりです。そろそろデザインを凝っていきたいです。