0
0

`display: none` な要素を全て取得するワンライナー

Last updated at Posted at 2023-11-04

ワンライナー

const undisplayedElements = [... document.querySelectorAll('*')].filter(eF => window.getComputedStyle(eF).display === 'none' && ! ['head', 'base', 'link', 'meta', 'script', 'style', 'title'].includes(eF.tagName.toLowerCase()));

分解と解説

const undisplayedElements =
  [...  // HTMLCollection や NodeList を真の配列に変換、Array.from() でも可
    document.querySelectorAll('*')  // .getElementsByTagName('*') でも可、.all はやめとけ
  ]
  .filter(eF =>  // 真の配列に変換しておかないと .filter() できない
    window.getComputedStyle(eF).display === 'none'  // その要素の最終的な display プロパティ
    &&
    !  // そもそも表示されるはずが無い要素を除外
      ['head', 'base', 'link', 'meta', 'script', 'style', 'title']
      .includes(  // 特定の値が含まれるかどうかを返す
        eF.tagName.toLowerCase()  // .tagName は大文字
      )
  )
;
  • .querySelectorAll().getElementsByTagName() で得られるのは配列とは似て非なる反復可能オブジェクトであり、.filter() メソッドなんて持っていないので、まずはスプレッド構文か Array.from() で真の配列に変換してやる必要がある。
  • 全要素を取得するにあたって document.all とかいう便利そうなやつがあるが、HTML 5 以降廃止されたらしいので使うべきではない。
  • [要素達].filter(要素 => ! [候補達].includes(要素)) とすることで、いずれの候補にも一致しない要素だけを抽出できる。
    • 記事修正前は .includes() ではなく .every() を用いて、除外処理のコードを ['head', 'base', 'link', 'meta', 'script', 'style', 'title'].every(eE => eF.tagName.toLowerCase() !== eE)) としていた。
      コメントで改善の提案をいただき修正した。
  • HTML の 要素.tagName は必ず大文字なので注意。

ちなみに:<head> とかは本当に表示されないのか

    !  // そもそも表示されるはずが無い要素を除外
      ['head', 'base', 'link', 'meta', 'script', 'style', 'title']

本当に? という疑いは当然生じてくる。

MDN を見てみる

MDN では、メタデータコンテンツに属する HTML 要素として、上記 7 種のうち <head> 以外が挙げられている。

このカテゴリーに属する要素は、<base>, <command>, <link>, <meta>, <noscript>, <script>, <style>, <title> です。

<command> は廃止済みの要素だし、<noscript> は明らかに環境に応じた表示用なのでちょっと除くとして、まぁメタデータに属するやつなら表示されないと見て良さそうだ。(雑)

HTML Living Standard を見てみる

HTML Living Standard では、デフォルトで非表示になることを想定している要素として、上記の 7 種を全て含むセレクターが示されている。

area, base, basefont, datalist, head, link, meta, noembed,
noframes, param, rp, script, style, template, title {
  display: none;
}

廃止済みのうちの <noembed><noframes>、比較的新顔の <template>、ルビ代替表示用の <rp> 辺りは古い環境では表示され得ると思うが、まぁ今回の 7 種については表示されないと見て良さそうだ。(雑)

各ブラウザーのユーザーエージェントスタイルシートを見てみる

Firefox、Chrome、Safari はどいつもこいつもレンダリングエンジンがオープンソースなので(ありがとう)、ブラウザーがデフォルトで採用するスタイルがどんなもんなのかをソースコードから直接確認できる。

Firefox (Gecko)1

html.css(抜粋)
base, basefont, datalist, head, link, meta, noembed,
noframes, param, rp, script, style, template, title {
   display: none;
}

Chrome (Blink)2

html.css(抜粋)
base, basefont, datalist, head, link, meta, noembed,
noframes, param, rp, script, style, template, title {
  display: none;
}

Safari (WebKit)3

html.css(抜粋)
/* children of the <head> element all have display:none as below */
area, base, basefont, datalist, head, link, meta, noembed, noframes,
param, rp, script, style, template, title {
    display: none;
}

これらの "html.css" はあくまでメインの CSS ファイルであって、実際にはそれぞれと同じ階層にある他の CSS ファイル(例えば Firefox なら "accessiblecaret.css" 等)も同時に効いてくると思うが、まぁとりあえずメインにおいては今回の 7 種の要素が全て display: none とされているので良さそうだ。(雑)

というわけで

深掘りしてみるとどうやら自明な非表示要素は 7 種どころではない気もしてくるが、まぁ今回の 7 種についてはとにかく良さそうだ。(雑)

おわり

  1. mozilla-release: layout/style/res/html.css@6a78abe63b7e7aa191341b42ef4f2168bdf0fc89
    https://hg.mozilla.org/releases/mozilla-release/file/FIREFOX_119_0_RELEASE/layout/style/res/html.css

  2. chromium/third_party/blink/renderer/core/html/resources/html.css at 119.0.6045.106 · chromium/chromium
    https://github.com/chromium/chromium/blob/119.0.6045.106/third_party/blink/renderer/core/html/resources/html.css

  3. WebKit/Source/WebCore/css/html.css at WebKit-7616.2.9.11.9 · WebKit/WebKit
    https://github.com/WebKit/WebKit/blob/WebKit-7616.2.9.11.9/Source/WebCore/css/html.css

0
0
2

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
0
0