ワンライナー
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 ↩