このページの本文へ

jQueryで無駄なくコードを書くために知っておきたい、セレクターの微妙な違い

2016年08月22日 10時49分更新

文●Baljeet Rathi

  • この記事をはてなブックマークに追加
本文印刷
jQueryっていろんなセレクターがあって便利ですよね。でもいつも同じセレクターばかり使っていて、実は無駄なコードを書いていません? 主要なセレクターを一挙解説。ふだんjQueryを使っている人も、おさらいにどうぞ。

本記事はMatt SmithTim Severienが査読を担当しています。最高のコンテンツに仕上げるために尽力してくれたSitePointの査読担当者のみなさんに感謝します。

jQueryのセレクターは、Webページ上の要素の内容を操作したいのか、要素にイベントを追加したいのか、あるいはほかのなにかをしたいのか、の選択に関与します。セレクターはライブラリーの重要な部分を形成します。

記事では、セレクターのすべてをカバーし、使用の際に心に留めておくべき大切なことを紹介します。

jQueryのセレクター

セレクターの主な目的は、一定の基準を満たすWebページ上の要素の選択です。基準は、ID、クラス名、属性の内のいずれか、あるいはすべての組み合わせです。jQueryのセレクターの大半は既存のCSSセレクターに基づいていますが、ライブラリーには独自のカスタムセレクターもあります。

基本的なセレクター

ID $("#id")、クラス $(".class")、あるいはタグ名 $("li")を使い、Webページの要素を選択できます。また、$(".class tag")のようなセレクターの組み合わせや、$("selectorA, selectorB, selectorC")のような複数のセレクターの結果の組み合わせも選択できます。

次に紹介する一覧のように、jQueryには基本的なセレクターがほかにもあります。

  • :headerセレクター — <section>で、<h1><h2><h3>のような見出しをすべて選択するとします。この場合、$("section h1, section h2, section h3")セレクター、あるいは、さらに短い$("section :header")セレクターを使えます。どちらも同じ働きをしますが、後者は比較的読み込みが簡単です。デモでは、ヘッダーセレクターは見出しの背景を黄色に設定しています
  • :targetセレクター — idが文書のURIのフラグメント識別子またはハッシュと一致する要素を返します。たとえばURLが「https://sitepoint.com/#hash」の場合、セレクター$("h2:target")は要素<h2 id="hash">を選択します
  • :animatedセレクター — このセレクターは、実行されたとき、進行中のアニメーションを持つすべての要素を返します。つまり、セレクターが実行された後に開始したアニメーションを持つ要素は返されません。また、エフェクト・モジュールなしでカスタムビルドしたjQueryを使用している場合は、このセレクターがエラーを出すことに留意してください。デモでは、アニメーション中のボックスのみがセレクターによってオレンジ色に変わります。

インデックスベースのセレクター

基本的なセレクターのほかにも、インデックスに基づいて要素を選択できます。jQueryは、ゼロから始まるインデックスをベースとしたセレクターを提供しています。つまり、3番目の要素を選択するには、インデックス2を使用します。

次に紹介するのは、インデックス・ベースのセレクターです。

  • :eq(n)セレクター — インデックスnにある要素を返します。バージョン1.8以降は、正と負の両方のインデックス値を受け入れます。負の値が供給されると、最後の要素から反対にカウントします
  • :lt(n)セレクター — n未満のインデックスを持つすべての要素を返します。また、バージョン1.8以降は正と負の値の両方を受け入れます。:eq(n)セレクターと同じように、負の値が供給されると最後の要素から反対にカウントします
  • :gt(n)セレクター — このセレクターは:lt(n)とまったく同じです。唯一の違いは、n以上のインデックスを持つすべての要素を返すことです
  • :firstセレクター — Webページ上で最初に一致したDOM要素を返します。:eq(0)および:lt(1)と等価です。:firstセレクターと:first-childセレクターの唯一の違いは、:first-childが、複数の親要素のそれぞれの最初の子について複数選択できることです
  • :lastセレクター — このセレクターは:firstセレクターと似ていますが、最後の子要素を返します
  • :evenセレクター — 偶数インデックスを持つすべての要素を返します。jQueryでのインデックスはゼロが基準なので、セレクターは最初の子要素、3番目の子要素のように選択します。直観に反するようですが、そのように動作します
  • :oddセレクター — :evenのように動作しますが、奇数インデックスを返します

以下のデモでは:lt:gt:eqの3つのボタンをクリックでき、これらのボタンはインデックスをランダムに生成して、結果として生じるセレクターをリストに適用します。

デモのように:first:lastを使って、Webページ上のそれぞれの最初と最後の要素のみを選択します。

子セレクター

jQueryはインデックスまたは種類に基づいて、子要素を選択できます。これらはCSSの子セレクターですので、jQueryの子セレクターとは異なり、ゼロを基準としたインデックスを使用しません(1から数えます)。

子セレクターを紹介します。

  • :first-child — 指定した要素の親要素の最初の子要素をすべて選択します(間に他の要素があった場合は選択されません)
  • :first-of-type —同じ親要素にある指定した要素のうち最初に出現した要素を選択します(間に他の要素があっても無視します)
  • :last-child — 親要素の最後の子要素を選択します。:first-childと同じく、親要素が多い場合に複数の要素を選択できます
  • :last-of-type — 親要素の中で、その種類の最後にあたるすべての子要素を選択します。親が複数の場合は複数の要素を選択できます
  • :nth-child() — このセレクターは少し複雑です。1以上の数、文字列even(偶数)odd(奇数)、あるいは4n+1のような式などのパラメーターとして、各種の値を受け入れます
  • :nth-last-child() — このセレクターは前のものと似ており、同じパラメーターを受け付けます。唯一の違いは、最後の子要素からカウントを開始することです
  • :nth-of-type() — 同じ名前を持つ兄弟に対する親のn番目の子であるすべての要素を返します
  • :nth-last-of-type() — このセレクターは:nth-of-type()セレクターと同じような作用をしますが、カウントは終わりから開始します
  • :only-child — 名前の通り、このセレクターは、その親の唯一の子であるすべての要素を返します。親要素に複数の子要素がある場合は、なにも選択されません
  • :only-of-type — 同じ種類の兄弟を持っていないすべての要素を返します

このデモでは、セレクターがどのように機能するのか説明します。前回のデモと同じく、ボタンをクリックするだけです。

デモは各divfirstlastの子要素に別々のボーダーが追加されていることに注意してください。

属性セレクター

属性の値に基づいた要素の選択も可能です。セレクターを操作するときは、複数のスペースで区切られた値を単一の文字列と見なすという、とても重要なことに留意してください。たとえば$("a[rel='nofollow']")$("a[rel='nofollow other']")とは一致しません。

次に紹介するのは、属性ベースのセレクターです。

  • $(“[attribute|=’value’]”) — 「接頭辞セレクターを含む属性」は、与えられた文字列と同じ値、あるいはその文字列から開始する属性を持つ、すべての要素を返します
  • $(“[attribute*=’value’]”) — 「セレクターを含む属性」は、部分文字列を含む属性を持つ値のすべての要素を返します。値の位置は重要ではありません。与えられた値と一致さえすれば、セレクターは要素を選択します
  • $(“[attribute~=’value’]”) — スペースで区切られた、指定した単語が含まれている属性値がある、すべての要素を返します
  • \$(“[attribute$=’value’]”) — 指定の文字列で終わる属性を持つすべての要素を返します

デモでは、各セレクターが異なる属性値でどのように動作するのか説明します。

  • $(“[attribute=’value’]”) — 指定の文字列に正確に等しい値を持つ属性のすべての要素を返します
  • (“[attribute^=’value’]”) — 与えられたものとまったく同じ文字列で値が始まる属性を持つすべての要素を返します
  • ( “[attribute!=’value’]” ) — 指定された属性でないか、属性の値がセレクターに指定されている値と等しくないものの、どちらかのすべての要素を返します

デモでは、アクションの最後の3つのセレクターを説明します。

要素が指定された属性を持っているのか確認したいだけで値を気にしない場合は、$("[attribute]")セレクターを使用できます。

コンテンツセレクター

要素内のコンテンツに基づいたセレクターです。このカテゴリーには4つのセレクターがあります。

  • :contains(text) — 指定のテキストを持つすべての要素を返します。テキストは、要素内に直接、あるいは、その子孫内のいずれかに表示されます。このセレクターで要素を選択するときは、大文字と小文字が区別されることに注意してください
  • :has(selector) — 指定のセレクターに一致する要素を少なくとも1つ持ったすべての要素を返します。たとえば$("section:has(h2)")は要素を持つすべてのセクションを選択します。h2は、直接の子要素でなくても構いません。子孫の間の任意の場所に存在できます

デモでは、:contains(text):has(selector)が異なる状況でどのように動作するのか説明します。

このデモを見ると、:contains(text)セレクターがテキストの大文字と小文字をどう区別するのかが明確です。テキストの内容と大文字小文字の区別が完全に一致すれば、テキストの前後に何があっても関係ありません。

  • :empty — テキストノードを含む子を持たないすべての要素を返します
  • :parent — 少なくとも1つの子ノードを持つすべての要素を返します。子ノードは、要素ノードまたはテキストノードのいずれかです。この意味では:emptyセレクターの逆です

階層セレクター

階層セレクターは、カテゴリー名を説明する要素を選択する基準として、DOMの階層を使います。以下に階層セレクターを紹介します。

  • $(“ancestor descendant”) — 指定された親のすべての子孫要素を返します。子孫とは、子要素、孫要素などです
  • $(“parent > child”) — このセレクターはこれまでのものと比べると特異で、親要素の直接の子要素だけを返します
  • $(“prev + next”)nextセレクターと一致し、prevと同じ親を持ち、prevから始まるすべての兄弟要素を返します
  • $(“prev ~ siblings”) — このセレクターは、prev要素の後に来て、prevと同じ親を持ち、siblingsセレクターに一致するすべての兄弟要素を返します。

デモでは、アクション内のすべての階層のセレクターを説明します。

デモから分かる通り、次の隣接兄弟と次の兄弟セレクターは、それらの前の兄弟には影響しません。第2パラグラフが<h2>要素に隣接しているにもかかわらず青なのは、そのためです。

フォームセレクター

jQueryは、フォーム内の入力要素に、短いバージョンのセレクターを提供します。これらはフォームセレクターとして分類されます。

たとえば、ボタン要素またはボタンタイプの要素を選択する場合、長い$("button, input[type='button']")セレクターの代わりに短い$(":button")セレクターを使用できます。同じように、ラジオタイプのある要素をすべて選択するには$("[type=radio]")セレクターの代わりに$(":radio")セレクターを使います。

デモでは、フォーム内の要素のカウントにセレクターを使う方法を説明します。

また、$(":enabled")セレクターと$(":disabled")セレクターを別々に使い、有効または無効とされる要素の選択もできます。これらのセレクターは、<button><input><textarea>などのdisabled属性をサポートする要素でのみ使用します。

チェックまたは選択されている要素を選ぶ$(":checked")セレクターもあります。これは、select要素のチェックボックス、ラジオボタン、オプションに適用されます。単にselect要素のオプションを検索したい場合は、代わりに$(":selected")を使います。

デモのさまざまな要素の周囲にある黄色の枠は、特定のセレクターにより選択されたことを意味します。

可視性セレクター

さらに知っておくべき重要なセレクターが2つあります。それは:visible:hiddenです。名前が示す通り、表示または非表示の要素を返します。

jQueryにおいて、要素は次の4例で隠し要素と見なされます。

  • displayプロパティがnoneに設定されている
  • widthheightがゼロに設定されている
  • 祖先が隠されている
  • type="hidden"を持つフォーム要素である

次のセクションでは、jQuery3.0で変更された高さと幅のルールについて説明します。

要素の不透明度が0に設定されていたり、スペースを取るvisibilityがhiddenに設定されているときは、可視性がある(目に見えるもの)と見なされます。つまり、$("elem").css( "visibility", "hidden" ).is( ":hidden" )ならfalseを返します。

透明なdiv:visibleセレクターからオレンジ色を取得している次のデモで明らかな通り、不透明度が0の要素も目に見えるものと見なされます。

jQuery3.0での変更

jQuery3.0のリリースでは、セレクター関連でいくつかの変更がありました。:visible:hiddenのようなカスタムセレクターは、場合によっては17倍速くなりました。

今後、要素は高さや幅がゼロかどうかではなく、DOMのgetClientRectsメソッドから返されたレイアウトボックスがあれば、可視性があると見なされます。

セレクターの文字列がハッシュ記号だけの場合は、ライブラリーは引き続きエラーを出します。以前のバージョンでは、$("#")は空のコレクションを返し、find("#")はエラーを出しましたが、現在のバージョンではいずれも無効と見なされます。

要素のキャッシュを保存する

jQueryは、複雑なセレクターを使う要素の選択を簡単にします。たとえば、クラスexternalLinkのあるリンクをすべて選択するには、$("a .externalLink")を使います。ただし、jQueryは呼び出しにDOMの再スキャンが必要なので、このような要素の選択は実行量の多いタスクとなります。

同じ選択を何度も使う必要があるときは、変数で返された要素(複数可)のキャッシュをおすすめします。これは複数のスキャンを回避し、パフォーマンスが向上します。

例として以下のコードを、

$("a .externalLink").click( function () {
  $("a .externalLink").removeClass("marked");
  $("a .externalLink").addClass("visited");
});

次のように記述できます:

var $linkExternal = $("a .externalLink");
$linkExternal.click( function () {
  $linkExternal.removeClass("marked");
  $linkExternal.addClass("visited");
});

上のコードは、ドキュメントを3回スキャンする代わりに、1度だけスキャンする方法です。性能向上は最小限だとしても、セレクターを多用するときは改良することに意義があります。

なお、:visibleセレクターはキャッシュ保存の利用によっても改善されました。

要約

本記事では、プロジェクトで使用する可能性のあるjQueryのセレクターのほとんどをカバーしました。また、セレクターを使用しているときに心に留めておくべき微妙な違いも指摘しました。

(原文:A Comprehensive Look at jQuery Selectors

[翻訳:柴田理恵]
[編集:Livit

Web Professionalトップへ

WebProfessional 新着記事