4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

BulmaのハンバーガーメニューをElmでトグルする

Last updated at Posted at 2020-06-06

はじめに

最近Elmを触り始めました。せっかくWebサイトを作るのならリッチなほうがいいですよね。ということでCSSフレームワークとしてElmと親和性の高そうなBulmaをつかうことにしました。その際にハンバーガーメニューでちょっと迷いました。その際のメモです。

Bulma、Elmとは?

ElmはJavaScript にコンパイルできる関数型プログラミング言語です。 詳しい説明は公式ドキュメントをよみましょう。日本語訳もあります。

BulmaはCSSフレームワークの1つです。フロントエンドのデザインのフレームワークというとBootstrapが有名です。しかし、BootstrapはJavaScriptを内包しているため、自分でJavaScriptやElmでDOMを操作するような際は干渉してしまい不適です。一方、BulmaはCSSのみで構成されているためElmと干渉するようなことがありません。詳しいことは公式ドキュメントを(略)

実装

まずhtmlの概要を書いていきます。重要になるのがナビゲーションバーです。
公式ドキュメントのナビゲーションバーの説明( https://bulma.io/documentation/components/navbar/#navbar-burger )によれば

The navbar-burger is a hamburger menu that only appears on touch devices. It has to appear as the last child of navbar-brand. It has to contain three empty span tags in order to visualize the hamburger lines or the cross (when active).

とあります。つまり「ハンバーガーメニューはタッチデバイスのときのみに現れ、"navbar-brand"の最後の子要素であるひつようがあり、3つのspanタグが必要」ということですね。

また、ハンバーガーメニューに表示する内容は"navbar-menu"で指定できます。例のごとく公式ドキュメントを読んでみると

The navbar-menu is the counterpart of the navbar brand. As such, it must appear as a direct child of navbar, as a sibling of navbar-brand.

とあり、navbar-menuは navbar-brandの子要素である必要があるとわかります。これらを踏まえてhtmlにすると下記となります。

<!DOCTYPE html>
<html>

    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Bulma Sample</title>
        <link rel="stylesheet" href="https://unpkg.com/bulma@0.8.2/css/bulma.min.css" />
    </head>

    <body>

        <nav class="navbar is-white">
            <div class="container">
                <div class="navbar-brand">
                    <a class="navbar-item brand-text" href="../index.html">
                        burger Sample
                    </a>
                    <div class="navbar-burger burger" data-target="navMenu">
                        <span></span>
                        <span></span>
                        <span></span>
                    </div>
                </div>
                <div id="navMenu" class="navbar-menu">
                    <div class="navbar-start">
                        <a class="navbar-item" href="#">
                            AAA
                        </a>
                        <a class="navbar-item" href="#">
                            BBB
                        </a>
                        <a class="navbar-item" href="#">
                            CCC
                        </a>
                    </div>
                </div>
            </div>
        </nav>

    </body>
</html>

これでウィンドウサイズを変更するとナビゲーションメニューやハンバーガーメニューが現れたり、消えたりします。しかし、ハンバーガーメニューをクリックしても内容が現れたりしません。これはBulmaはCSSのみで構成されているため、具体的に動かしたりの処理実装されていないためです。したがって自分で実装します。

ElmではhtmlをElmの関数として表現します。そのためにまずはHtmlをHtmlを表現するElmの型であるHtml Msgに変換する必要があります。このHtmlからElmへの変換はhttp://mbylstra.github.io/html-to-elm/ というサイトが便利です。

また、ハンバーガーメニューの制御には2つの段階があります。まずハンバーガーメニューを「三」から「×」マークにする、もうひとつが開閉を制御するです。前者は"navbar-burger"のclassに"is-active"を、後者は"navbar-menu"に"is-active"を指定すれば実現できます。これをハンバーガーメニューをクリックしたときにトグルするようにすればいいですね。これはElmのmodelとしてはトグルの状態を管理する型、MsgはToggleとし、Toggleが発行されたらupdateでmodelの状態を反転させれば良いでしょう。以上を実装すると下記となります。

module Main exposing (Model, Msg(..), init, main, update, view)

import Browser
import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Events exposing (onClick)


main =
    Browser.sandbox { init = init, update = update, view = view }



-- MODEL


type alias Model =
    Bool


init : Model
init =
    False



-- UPDATE


type Msg
    = Toggle


update : Msg -> Model -> Model
update msg model =
    case msg of
        Toggle ->
            not model



-- VIEW


view : Model -> Html Msg
view model =
    div []
        [ nav [ class "navbar is-white" ]
            [ div [ class "container" ]
                [ div [ class "navbar-brand" ]
                    [ a [ class "navbar-item brand-text", href "../index.html" ]
                        [ text "burger Sample" ]
                    , div
                        [ class "navbar-burger burger"
                        , class
                            (if model then
                                "is-active"

                             else
                                "burger"
                            )
                        , attribute "data-target" "navMenu"
                        , onClick Toggle
                        ]
                        [ span []
                            []
                        , span []
                            []
                        , span []
                            []
                        ]
                    ]
                , div
                    [ class "navbar-menu"
                    , class
                        (if model then
                            "is-active"

                         else
                            ""
                        )
                    , id "navMenu"
                    ]
                    [ div [ class "navbar-start" ]
                        [ a [ class "navbar-item", href "#" ]
                            [ text "AAA" ]
                        , a [ class "navbar-item", href "#" ]
                            [ text "BBB" ]
                        , a [ class "navbar-item", href "#" ]
                            [ text "CCC" ]
                        ]
                    ]
                ]
            ]
        ]

これでハンバーガーメニューを押したときに開閉ができるようになりましたね。

まとめ

今回はBulmaのハンバーガーメニューをElmから操作する方法について紹介しました。Bulmaのハンバーガーメニューの制御は"navbar-burger"および"navbar-menu"に"is-active"をつけるかつけないかでできます。Elm側ではトグル状態を表現したモデルを用意してその状態に応じて"is-active"の追加するしないを制御すればよいです。

4
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?