MENU

【続】空のaタグでボタンを作るCSSについて

空のaタグが必要なケースを見つけました。

そもそもの経緯

以前空のaタグをposition:absoluteで全面覆ってボックス型のボタンを作る方法について「その必要はないのでは?」という記事を書きました。引き続き調べたら「もしかすると空のaタグを使う場合もあるのでは?」と思い始めたので書いてみた。

前の記事はこちら。

aタグの中に別のaタグ(リンク)を入れたい場合

例えばカード型UIのレイアウトがあったとした時に、カード全体は記事へのリンク。カードの中にあるボタンは別のページへのリンクを設置したい時。

サンプルデザイン

この場合、前回の記事の考え方のコーディング方法だとこうなるはず。

<div class="hotel_item">
  <a href="/detail/" class="hotel_detail">
    <figure class="hotel_img"><img src="img_hotel.jpg" alt=""></figure>
    <h2 class="hotel_name">hogehoge hotel</h2>
    <div class="hotel_txt">説明テキスト説明テキスト説明テキスト説明テキスト説明テキスト</div>
    <div class="hotel_book"><a href="/book/" class="hotel_btn-book">予約する</a></div>
  </a>
</div>

がしかし、ブラウザで表示するとレイアウト崩れがおきる。
ソースコードを見ると実際に記述したコードと異なる。
親のaタグが子のaタグを囲む直前で閉じるように解釈され、その後にもう一度、空の親のaタグが出てくる。

<div class="hotel_item">
  <a href="/detail/" class="hotel_detail">
    <figure class="hotel_img"><img src="img_hotel.jpg" alt=""></figure>
    <h2 class="hotel_name">hogehoge hotel</h2>
    <div class="hotel_txt">説明テキスト説明テキスト説明テキスト説明テキスト説明テキスト</div>
  </a>
  <div class="hotel_book">
    <a href="/detail/" class="hotel_detail"></a>
    <a href="/book/" class="hotel_btn-book">予約する</a>
  </div>
</div>

これはブラウザ側でHTMLパース*(HTMLの構造の解釈)がされてこうなるらしい。
tableタグでもtbodyを省略して書いても挿入されるのはHTMLパースによる解釈によるもの。

HTMLパースとは?
HTMLパースとは、HTML文法規則にのっとった文字列を、その文法に基づいて字句解析し、意味や構造を解釈することをいい、HTMLパースを行うプログラムのことをHTMLパーサといいます。
–  SEO検索エンジン最適化さんより –

そもそもこんなレイアウトはUI的にどうなの?

「そもそも、こんなUI使いづらくない?」って一瞬思ったが、アプリではリンクの中にリンクのケースがよくある。

例えばtwitterだと、本人のツイートの中にリンクのフレームがあったり、更には、リプライやリツイート、ファボのアイコンなどツイートのタップ領域の中の下に並んでいる。

モバイルファーストになってきている今だと、こういったUIも見慣れたものとして扱われてくるんだなぁ。と思い考えを改めることにしました。

aタグの中に別のaタグ(リンク)を入れる解決方法3つ

1.空のaタグを使って実装する方法

カード全体のリンクのaタグ(.hotel_detail)を空にして、position:absoluteでカード全対応覆う方法。前回の記事で非推奨だったやつ。空タグが気になるならテキスト入れて文字を見えなくする手法でも良いと思う。

<div class="hotel_item">
  <figure class="hotel_img"><img src="http://bit.ly/2Kzvg9E" alt=""></figure>
  <h2 class="hotel_name">hogehoge hotel</h2>
  <div class="hotel_txt">説明テキスト説明テキスト説明テキスト説明テキスト説明テキスト</div>
  <div class="hotel_book">
    <a href="https://www.google.com/" target="_blank" class="hotel_btn-book">予約する</a>
  </div>
  <a href="https://nanimonaikedo.jp" target="_blank" class="hotel_detail"></a>
</div>

2.aタグの中にaタグを入れて実装する方法

aタグの中にaタグを使いたい場合、子のaタグをobjectタグで囲めば、HTMLパースされても、そのままの構造で解釈(表示)される。ただし、objectタグ自体は正しい使い方ではない。

<div class="hotel_item">
  <a href="https://nanimonaikedo.jp" target="_blank" class="hotel_detail">
    <figure class="hotel_img"><img src="http://bit.ly/2Kzvg9E" alt=""></figure>
    <h2 class="hotel_name">hogehoge hotel</h2>
    <div class="hotel_txt">説明テキスト説明テキスト説明テキスト説明テキスト説明テキスト</div>
    <object class="hotel_book"><a href="https://www.google.com/" target="_blank" class="hotel_btn-book">予約する</a></object>
  </a>
</div>

3.jQueryと使って実装する方法

aタグを入れ子にした時の子のaタグを別のタグで置き換えてjsで無理やりリンクさせる。

<div class="hotel_item">
  <a href="https://nanimonaikedo.jp" target="_blank" class="hotel_detail">
    <figure class="hotel_img"><img src="http://bit.ly/2Kzvg9E" alt=""></figure>
    <h2 class="hotel_name">hogehoge hotel</h2>
    <div class="hotel_txt">説明テキスト説明テキスト説明テキスト説明テキスト説明テキスト</div>
    <div class="hotel_book"><span data-url="https://www.google.com/" class="hotel_btn-book js-url">予約する</span></div>
  </a>
</div>
$('.js-url').on('click', function(e){
  let href=$(this).attr('data-url');
  window.open(href, "_blank");
  return false; //クリックイベントによる、子要素から親要素への伝播をキャンセル
});

4.javascriptを使って実装する方法

3のjavascript版。

<div class="hotel_item">
  <a href="https://nanimonaikedo.jp" target="_blank" class="hotel_detail">
    <figure class="hotel_img"><img src="http://bit.ly/2Kzvg9E" alt=""></figure>
    <h2 class="hotel_name">hogehoge hotel</h2>
    <div class="hotel_txt">説明テキスト説明テキスト説明テキスト説明テキスト説明テキスト</div>
    <div class="hotel_book"><span name="https://www.google.com/" class="hotel_btn-book js-url">予約する</span></div>
  </a>
</div>
function innerLink (e) {
  var linkUrl = this.getAttribute("name"); //name属性の値を取得
  window.open(linkUrl, '_blank'); //取得した値のurlを別ウィンドウで開く
  e.stopPropagation(); // イベント伝搬の停止
  e.preventDefault(); // イベントキャンセル
}
Array.prototype.forEach.call(document.getElementsByClassName('js-url'), function (e) {
  e.addEventListener('click', innerLink, false);
});

まとめ。

どれを使うかなかなか悩む。。個人的にはjsとは絡めたくないなー。という印象はあるけど、それぞれ実装してみて汎用性や管理のしやすさの面を検証していこうと思う。今回の解決方法は正しい手段ではないので、気持ち悪さは残るけど、こういう場合もあるのか。くらいに思っておくことにする。