ハンバーガー・ボタンのメニュー(v9.17.2)

ロゴの右にちょこんとあるハンバーガー・ボタン(やその左の空間)を押すと、ページ・ヘッダーのウェブサイト・ナビゲーションを切り替えるようにした。details要素を使っている。HTMLにかなり手を入れた上で、ちょっとCSSを書いたくらいで、スクリプトは書いていない。キーボードでのアクセス性は悪くなさそうだし、おおむね問題なく操作できそうだ。v9.17.0からこうなったが、いろいろ直したので、すでにパッチ番号が2つ上がっている。

このようなほぼ完結した文章があるだけのウェブサイトなので、ウェブサイト・ナビゲーションは「additional」だと考えられる。つまりdetails要素を使って、隠しておいても構わないだろう。このような理屈は成立しそうだが、ウェブページの最初にあるdetails要素には前後の脈絡がなく、何に対する追加情報が出てくるのか伝わらない。summary要素をロゴに使っているので、なおさらだ。

また、追加のナビゲーションを隠しておきたいので、最初はnav要素をdetails要素の子にした。しかし、隠れているとランドマークとして機能しない(実装にも依存する)。nav要素をdetails要素の親にすると解決するが、これでいいのかよくわからない。現在はheader要素の中にnav要素のみ、nav要素の中にdetails要素のみ、という状況で、やたらとネストされている。


この先は実装の話だ。Edge 87やChrome 87、Firefox 84では、summary要素をFlexboxにして、疑似要素でハンバーガー・ボタンを追加するだけだったが、Safari 14ではまったくうまくいかない。Safari 14にはsummary要素をFlexboxにできないというバグがあり、これによって色々な不具合が起こるようだ。CSSだけではどうしようもないので、HTMLに手を入れる。

<details>
  <summary class="logo">
    <span>
      <a href="/">Logo</a>
    </span>
  </summary>

  <ul>
    <li>
      <a href="/">Menuitem</a>
    </li>
  </ul>
</details>

具体的にはsummary要素と中身の間に何かしらの要素をネストし、それをFlexboxにすればいい。summary要素のcontent modelはphrasing contentとheading contentなので、span要素がいいだろう。

.logo {
  list-style-type: none;
}

.logo::-webkit-details-marker {
  display: none;
}

.logo > span {
  display: flex;
}

.logo > span::after {
  content: "≡";
  flex-grow: 1;
  text-align: right;
}

[open] .logo > span::after {
  content: "×";
}

CSSではFlex関係のプロパティーと疑似要素をspan要素に対して当てていく。

Safari 14のsummary要素でのFlexboxのバグは、単に無視されるのではなく、何かいろいろおかしなことが起きる。Flexboxでレイアウトできないのに、a要素がflex-item風に解釈され、幅いっぱいになった。また、別のスタイルとの組み合わせで疑似要素がうまく追加できなくなったりもした(再現できていない)ので、一時期はspan要素でハンバーガー・ボタンと閉じるボタンを追加したり、いろいろ間違えた。


もうちょっと詰めるべきところがありそうだ。CSSが面倒くさくなりそうな予感があり、こういう構造(ロゴをsummary要素に含める形)にしたが、結局は面倒な実装になってしまった。やはりロゴに続けてdetails要素にした方が無難だろうか。横長の広い領域が操作可能になっていて、どこでもメニューが出てくる状態は、操作しやすくて気に入っていおり、なかなか悩ましい。

summary要素にa要素を置いても、問題なく両者が操作可能であることなど、柔軟な使い方ができることがわかり、収穫はあったので、もっと様々な利用例を考えて試してみたい。今までbutton要素でやっていた、ボタンを押してすぐ下にコンテンツが追加されるような仕組みは、半分くらいは置き換えられそうだ。ページングで分けるフォームなども、details要素のネストでやっても面白そうだ。