HTML
CSS
JavaScript
HTML5
jQuery

IDが重複してもページ内ジャンプできるようにする方法

More than 3 years have passed since last update.

HTML上に複数の同じようなコンテンツを置かざるを得ないケースに遭遇することってたまにあると思います。

たとえば


  • PCとスマホのコンテンツを同一ページ別DOMで用意するとき

  • 多言語のコンテンツを同一ページに複数DOMで用意するとき

  • テンプレートを作って中身を変えずにクローンしまくるとき

本来サーバーサイドで出し分けるべきものの場合が多いですが、

訳あってフロントサイドしか触れないなど、やむを得ないケースはあるかと思われます。

そして、何かの手違いだったりやむを得ない事情で、IDも一緒にコピーしてしまうことがあるかと思われます。

要素のIDは重複してはならないのがルールですが、

実はCSSやJavaScriptではある程度許容されているような動作をします(おそらく仕様にない挙動ですので濫用はしないように)。


複数IDのフィルタリング


sample.html

<!DOCTYPE html>

<html lang="ja">
<head>
<meta charset="UTF-8">
<title>has duplicated</title>
<style>
.env-1 {
display: none;
}
</style>
</head>
<body>
<a href="#p1"></a>
<a href="#p2"></a>
<div class="env-1">
<p id="p1">この親のdivはPCだとか。</p>
<p id="p2">この親のdivはenだとか。</p>
</div>
<div class="env-2">
<p id="p1">この親のdivはSPだとか。</p>
<p id="p2">この親のdivはjaだとか</p>
</div>

<script src="https://code.jquery.com/jquery-1.11.3.min.js"></script>
</body>
</html>


このHTMLの2番目の<p id="p1">を取得する方法をいくつか。(※要jQuery)

↓こういうのは無理です。

$('.env-2#p')

↓これなら大丈夫みたいです。

$('.env-2').find('#p2');

↓これなら大丈夫(重複しているIDの2番目)

$('[id="p2"]').eq(1)

↓これでも大丈夫(重複しているIDの最後)

$('[id="p2"]').eq(-1)

↓これが実用的(DOMの可視/不可視をまるごと切り替えてるとき)

$('[id="p2"]:visible')


ページ内ジャンプの実装

最後の:visibleセレクタを用い、見えている方のIDの元へ飛んでいってくれるページ内ジャンプを書いてみました。


internal_link_with_duplicate_id.js

$('a[href^=#]').on('click', function() {

var targetId = $(this).attr('href').slice(1);
var selector = targetId ? '[id="' + targetId + '"]:visible' : 'html';
var $target = $(selector);

var dist = $target.offset().top;

$('html, body').animate({scrollTop: dist});
});


デモ:

ID重複ページ内リンク - jsdo.it


補足

このように、属性セレクタ等を用いて重複したIDを取得できることがわかりましたが、

重ね重ねIDの重複はHTMLとしてはinvalidのため、出来る限り別IDにするか、クラスやデータ属性を使って回避しましょう。

(僕は基本的に実務でのIDの使用は極力避けてます。)

ちなみに、IDの重複チェッカーを作ったので、Validatorに通す前に軽くチェックするフローを挟むなど活用して頂ければ幸いです。

JavaScript - DOM上のIDの重複を検出する - Qiita