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

# ワンライナー

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


# 分解と解説

```js
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>` とかは本当に表示されないのか

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

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

## MDN を見てみる

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

- コンテンツカテゴリー - HTML: ハイパーテキストマークアップ言語 | MDN
  https://developer.mozilla.org/ja/docs/Web/HTML/Content_categories
  - &gt; 主要コンテンツカテゴリー &gt; [メタデータコンテンツ](https://developer.mozilla.org/ja/docs/Web/HTML/Content_categories#%E3%83%A1%E3%82%BF%E3%83%87%E3%83%BC%E3%82%BF%E3%82%B3%E3%83%B3%E3%83%86%E3%83%B3%E3%83%84)

> このカテゴリーに属する要素は、`<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/
  - &gt; 15.3 Non-replaced elements &gt; [15.3.1 Hidden elements](https://html.spec.whatwg.org/multipage/rendering.html#hidden-elements)

```css
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)[^firefox]

[^firefox]: 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

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

### Chrome (Blink)[^chrome]

[^chrome]: 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

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

### Safari (WebKit)[^safari]

[^safari]: 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

```css: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 種については**とにかく良さそうだ**。（雑）


&ZeroWidthSpace;

おわり