ワンライナー
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> 以外が挙げられている。
- コンテンツカテゴリー - HTML: ハイパーテキストマークアップ言語 | MDN
https://developer.mozilla.org/ja/docs/Web/HTML/Content_categories- > 主要コンテンツカテゴリー > メタデータコンテンツ
このカテゴリーに属する要素は、
<base>,<command>,<link>,<meta>,<noscript>,<script>,<style>,<title>です。
<command> は廃止済みの要素だし、<noscript> は明らかに環境に応じた表示用なのでちょっと除くとして、まぁメタデータに属するやつなら表示されないと見て良さそうだ。(雑)
HTML Living Standard を見てみる
HTML Living Standard では、デフォルトで非表示になることを想定している要素として、上記の 7 種を全て含むセレクターが示されている。
- HTML Standard
https://html.spec.whatwg.org/multipage/- > 15.3 Non-replaced elements > 15.3.1 Hidden elements
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
base, basefont, datalist, head, link, meta, noembed,
noframes, param, rp, script, style, template, title {
display: none;
}
Chrome (Blink)2
base, basefont, datalist, head, link, meta, noembed,
noframes, param, rp, script, style, template, title {
display: none;
}
Safari (WebKit)3
/* 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 種についてはとにかく良さそうだ。(雑)
おわり
-
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 ↩ -
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 ↩ -
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 ↩