[2] [CODE(DOMi)@en[[[Document]]]] [[オブジェクト]]の [DFN[[CODE(DOMa)@en[[[hidden]]]]]] [[属性]]は、
[[文書]]が表示されているかを返します。

[16] [CODE(DOMi)@en[[[Document]]]] [[オブジェクト]]の [CODE(DOMa)@en[[[visibilityState]]]]
[[属性]]の値 [DFN[[CODE(DOM)@en[[[hidden]]]]]]、
[DFN[[CODE(DOM)@en[[[visible]]]]]] は[[文書]]が隠れていること、いないことをそれぞれ表します。

[17] これら2つの「hidden」の意味は若干異なっています。

* 仕様書

[REFS[
- [28] [CITE@en[Page Visibility (Second Edition)]] ([TIME[2015-11-13 18:23:52 +09:00]] 版) <https://w3c.github.io/page-visibility/#idl-def-.hidden>
- [31] [CITE@en[Page Visibility (Second Edition)]] ([TIME[2015-11-13 18:23:52 +09:00]] 版) <https://w3c.github.io/page-visibility/#h-hidden-attribute>
- [36] [CITE@en[Page Visibility (Second Edition)]] ([TIME[2015-11-13 18:23:52 +09:00]] 版) <https://w3c.github.io/page-visibility/#h-visibilitystate-attribute>
- [27] [CITE@en[Vibration API]] ([TIME[2014-11-20 01:59:39 +09:00]] 版) <http://dev.w3.org/2009/dap/vibration/#dfn-processing-vibration-patterns>
]REFS]

* [CODE(DOMa)@en[visibilityState]] 属性の値 [CODE(DOM)@en[hidden]]

[19] [[最上位閲覧文脈]]に含まれている [CODE(DOMi)@en[[[Document]]]] がまったく見えないなら
[CODE(DOMa)@en[[[visibilityState]]]] [[属性]]は [CODE(DOM)@en[[[hidden]]]]
を返さなければ[['''なりません''']]。ただし >>7 の場合は [CODE(DOM)@en[[[visible]]]]
を返して[['''構いません''']]。 [SRC[>>18]]

[HISTORY[
[20] >>19 の規定からすると [CODE(DOMa)@en[[[hidden]]]] [[属性]]が[[真]]なら [CODE(DOMa)@en[[[visibilityState]]]]
[[属性]]は必ず [CODE(DOM)@en[[[hidden]]]] になりそうなものですが、 >>11 の場合に [CODE(DOM)@en[[[unloaded]]]]
という別の値が用意されています。また [CODE(DOM)@en[[[prerender]]]] という値も用意されています。
更に [[vendor prefix]] のついた値も認められており、厳密に解釈すると >>19 の規定に反してしまう可能性があります。
仕様書の例示には >>9、>>10、>>13 のみ挙げられています。

;; [32] その後の改訂でこの辺の規定は整理されています。
]HISTORY]

[29] [[文書]]の[F[[[可視性状態]]]]の値[DFN[[RUBYB[隠れ]@en[hidden]]]]は、
[[文書]]がまったく[[画面]]内にないことを表します [SRC[>>28]]。

* [CODE(DOMa)@en[visibilityState]] 属性の値 [CODE(DOM)@en[visible]]

[23] [[最上位閲覧文脈]]に含まれている [CODE(DOMi)@en[[[Document]]]] 
がどこかの[[画面]]に一部分でも表示されているなら [CODE(DOMa)@en[[[visibilityState]]]]
[[属性]]は [CODE(DOM)@en[[[visible]]]] を返さなければ[['''なりません''']]。また >>7
の場合も [CODE(DOM)@en[[[visible]]]] で[['''構いません''']]。 [SRC[>>18]]

;; [24] これは [CODE(DOMa)@en[[[hidden]]]] が[[偽]]になる場合と同じである [SRC[>>18]] とわざわざ明記されています
(>>19 については言及なし)。

[30] [[文書]]の[F[[[可視性状態]]]]の値[DFN[[RUBYB[可視]@en[visible]]]]は、
[[文書]]の少なくても一部が可視状態であることを表します [SRC[>>28]]。

* 可視性の決定

[45] [[文書]]の[F[可視性状態]]は、[[文書]]が[[閲覧文脈]]中にあり、
それが[[最上位閲覧文脈]]である時のみ定義されているようです。

[35] [[文書]]の[F[[[可視性状態]]]]が[[可視]]であるか[[隠れ][document.hidden]]であるかは、
次のように判断されます [SRC[>>36]]。

[FIG(list)[
- [44] [[文書]]の[F[閲覧文脈]]の[F[窓][窓 (Web)]]の[F[画面]]の[F[[[ロック画面]]表示中]]が[[真]]なら、
-- [50] [[隠れ][document.hidden]]です。
- [43] [[利用者エージェント]]が[[文書]]を [[unload]] 中なら、[[隠れ]]です。
- [41] [[文書]]の[F[閲覧文脈]]の[F[窓][窓 (Web)]]の[F[最小化]]が[[真]]なら、
-- [46] [[隠れ][document.hidden]]です。
- [38] それ以外なら、
-- [42] [[利用者エージェント]]が完全に隠されていても、それが[[アクセシビリティーツール]]であり、[[文書]]の表示であるなら、[[可視]]です。
-- [39] [[文書]]の[F[閲覧文脈]]の[F[前景]]が[[真]]なら、
--- [47] [[可視]]です。
-- [40] それ以外 ([[背景]]) なら、
--- [48] [[隠れ][document.hidden]]です。
]FIG]

;; [49] つまり、最前面の[[タブ]]以外では、[[隠れ]]となります。

;; [37] [[事前レンダリング]]については、そちらの項を参照。

[70] [[アクセシビリティーツール]]にしか言及がありませんが、
[[IME]] なども同様と思われます。

* [CODE(DOMi)@en[Document]] インターフェイス [CODE(DOMa)@en[hidden]] 属性 (DOM)

[4] [CODE(DOMi)@en[[[Document]]]] [[インターフェイス]]の
[DFN[[CODE(DOMa)@en[[[hidden]]]]]] [[IDL属性]]は、
[[最上位閲覧文脈]]の[[文書]]が一部でも可視なら[[偽]]、
そうでないなら[[真]]を返します。

;; [6] 当該 [CODE(DOMi)@en[[[Document]]]] が直接含まれている[[閲覧文脈]]ではなく、[[最上位閲覧文脈]]によって決まります。

;; [5] [CODE(DOMi)@en[[[Document]]]] の [CODE(DOMa)@en[[[defaultView]]]] が [[null]] なら、[[真]]を返さなければ[['''なりません''']]
[SRC[>>1]]。

[FIG(important)[
[34] 本[[属性]]は歴史的なものであり、 [CODE[[[visibilityState]]]]
[[属性]]を使う[RUBYB[べき]@en[should]]です [SRC[>>31]]。
]FIG]

[3] [[取得時]]、[[文書が隠れているか決定する手順]]を実行しなければ[['''なりません''']] [SRC[>>31]]。
この[[属性]]は[[読み取り専用]]で、 [CODE(IDL)@en[[[boolean]]]] を返します [SRC[>>31]]。

[33] [DFN[[RUBYB[文書が隠れているか決定する手順]@en[steps to determine if the document is hidden]]]]は、
[[可視性状態を決定する手順]]が [CODE[[[visible]]]] を返すかどうかを返します [SRC[>>31]]。

[7] 通常[[全画面]]で表示するような[[アクセシビリティ・ツール]]もあったりしますから、
[[Webブラウザー]]が[[最小化]]されておらず他の[[アプリケーション]]に完全に隠れてしまっているような場合であれば[[偽]]を返しても[['''構いません''']]
[SRC[>>1]]。

[EG[
[8] 例えば次の場合に[[真]]を返します。

- [9] [[最小化]]されている場合 [SRC[>>1]]
- [10] 裏の[[タブ]]になっている場合 [SRC[>>1]]
- [11] [[unload]] しようとしている場合 [SRC[>>1]]
- [12] [[session history entry]] を探索しようとしている場合 [SRC[>>1]]
- [13] [[OS]] の[[ロック画面]]が表示されている場合 [SRC[>>1]]
- [21] [CODE(DOMa)@en[[[visibilityState]]]] が [CODE(DOM)@en[[[prerender]]]] の場合
]EG]

[25] 値の変化のタイミングについては [CODE(DOMe)@en[[[visibilitychange]]]] の項をご覧ください。

* 副作用

[52] 隠れ状態は、可視状態とは違う動作となることがあります。

[FIG(list)[
[HISTORY[
- [26] [CODE(JS)@en[navigator.vibrate]] が無視されるかどうかは、
[CODE(JS)@en[document.hidden]] [[属性]]の値に依存する [SRC[>>27]]
と以前はされていましたが、現在は[F[可視性状態]]に依存する形に改められています。
]HISTORY]

- [53] [[Chrome]] では、隠れ状態の[[文書]]は、[[捨て][文書を捨てる]]られることがあります。
- [54] 隠れ状態の[[文書]]の[[スクリプト]]その他の[[タスク]]の実行は、
他の[[文書]]よりも優先度が下げられるかもしれません。
- [63] [[DeviceOrientation Event]] の[[発火]]の有無や頻度にも影響するかもしれません。
- [66] [[アイドル期間]]に入るかどうかの判断に影響するかもしれません。
ひいては [CODE[requestIdleCallback]] の処理遅延に影響することがあります。
]FIG]

[59] [[Chrome]] は[[非表示][document.hidden]]状態の[[タブ]]の[[活性文書]]も[[捨てる][文書を捨てる]]ことがあるようです。
[TIME[2016-09-16T04:46:45.900Z]]

[51] 捨てる正確な条件はわかりませんが、一部 [[fetch]] が実行中でも平気で捨てるようで、
困ったものです。

[60] [CODE[POST]] で作成されたページも勝手に捨てられて、
再表示できずにかわりに再読込を促す[[ネットワークエラー]]が表示されるのも、
困ったものです。

[55] [[Webブラウザー]]は次のような点に注意が必要です。
[FIG(list)[
- [61] [[ネットワーク]]処理の実行中なら、[[文書を捨てる]]べきではありません。
- [62] [CODE[POST]] で作成された[[文書を捨てる]]べきではありません。
- [56] [[利用者]]は、時間のかかる処理を待つ間他の[[タブ]]を開いているかもしれません。
隠れている処理が停止されたり、過剰に優先度を下げられたりすると、
[[利用者]]の期待に反します。
- [57] [[利用者]]は、[[音声]]や[[動画]]を[[再生]]させながら、
これを [[BGM]] として他の[[タブ]]を開いた状態にするかもしれません。
- [64] [[利用者]]は、[[音声]]や[[動画]]を[[一時停止]]状態にして待機させた状態で、
他の[[タブ]]で作業して、後でまた続きから[[再生]]したいかもしれません。
- [58] [[Webアプリケーション]]は[[ログインセッション]]や[[利用者]]の操作状態などを[[クライアント]]側で
([[ストレージ]]などに明示的に保存せず) 保持したり、[[サーバー]]と低頻度で通信したりしているかもしれません。
一定時間[[利用者]]の操作がないからと言って、これを破棄するのは[[利用者]]の期待に反する動作かもしれません。
]FIG]

[68] 
非表示であっても、他の[[窓]]の[[文書]]から参照されていたり、
[[ワーカー]]や [CODE[postMessage]] を通じて通信していたりすることがあります。
[CODE[BroadcastChannel]] で通知を受け付けているかもしれません。
[[Webブラウザー]]はどの[[文書]]を捨てても問題が出ないか、慎重に判断する必要があります。

[71] 
[[Chrome]] は最前面の[[タブ]]に表示していても[[窓]]が隠れている状態なら、
破棄してしまうことがあります。困ったもんです。。。
[TIME[2021-02-04T02:56:21.500Z]]

[73] 
[[Chrome]]
は[[開発者コンソール]]を開いていても捨ててしまいます。
困ったものです。
[TIME[2021-12-01T06:14:27.500Z]]

[74] 
[[Chrome]] は捨ててしまうまでいかないまでも、
[[動画]]の再生を停止してしまうことがあります。
([[音声]]の再生は継続されます。)
[[Windows]] で画面撮影用のソフトウェアを使って
[[Chrome]]
の画面を録画記録しながらビデオ会議をしつつ、
表に他の画面を開いているような場合に、
(録画されてることを [[Chrome]] は検知し得ないので、
平気で動画再生を止めてしまい、)
音声のやり取りは続いているのに動画が真っ暗になってたりして、
ほんと困ります。。。

[75] 
[[Chrome]] は最前面の窓の最前面のタブですら捨てちゃうことあった! やばすぎ!
[TIME[2022-05-18T11:36:20.200Z]]

[76] 
その割にメモリー満杯近くなのになぜか破棄されない背景タブとかあって謎だよね。
[TIME[2022-06-23T02:22:23.500Z]]

* 濫用

[79] 
可視性はしばしば悪意ある、あるいは設計が悪い [[Webアプリケーション]]によって乱用されています。

[80] 
[[Webブラウザー]]は、[[利用者]]の簡単な操作によって特定の [[Webサイト]]が可視性を失わせない
(常に最前面表示であるかのように状態を伝える)
ことで、 [[Webサイト]]の乱用に対処できるようにするべきです。

-*-*-


[77] 
[CITE@ja[Xユーザーのymrlさん: 「ブラウザバックで広告出るやつも嫌いなんだけど、それ以上にブラウザのタブがアクティブでなくなったとき全面広告に切り替わるやつが嫌い。たぶんvisibilitychangeイベントとdocument.visibilityStateでやってるやつ。いろんなページを見比べて調べ物してる時に集中力が分断されるので。」 / X]], [TIME[午前7:02 · 2024年8月16日][2024-08-15T22:02:34.000Z]], [TIME[2024-08-17T01:59:53.000Z]] <https://x.com/ymrl/status/1824205065055506848>


[78] 
表示中タブではなくなったときに再生を停止する動画サイトは嫌がらせしてるとしか思えない。


* 関連

[14] [[要素]]の [CODE(DOMa)@en[[[hidden]]]] [[属性]]とは関係ありません。

* 歴史

[15] [[Page Visibility]] 仕様により追加されました。 [[WebKit]] では [DFN[[CODE(DOMa)@en[[[webkitHidden]]]]]]
として実装されています [TIME[2013-05-20T14:04:38.00Z]]。 [[WinIE]] では [DFN[[CODE(DOMa)@en[[[msHidden]]]]]]、
[[Firefox]] では [DFN[[CODE(DOMa)@en[[[mozHidden]]]]]] も実装されていました。

[REFS[
- [1] [CITE@en[Page Visibility]] ([TIME[2013-05-20 13:53:52 +09:00]] 版) <https://dvcs.w3.org/hg/webperf/raw-file/tip/specs/PageVisibility/Overview.html#dom-document-hidden>
- [18] [CITE@en[Page Visibility]] ([TIME[2013-05-20 14:16:53 +09:00]] 版) <https://dvcs.w3.org/hg/webperf/raw-file/tip/specs/PageVisibility/Overview.html#pv-page-hidden>
- [22] [CITE@en[Page Visibility]] ([TIME[2013-05-20 14:24:55 +09:00]] 版) <https://dvcs.w3.org/hg/webperf/raw-file/tip/specs/PageVisibility/Overview.html#pv-page-visible>
]REFS]


[FIG(quote)[
[FIGCAPTION[
[65] [CITE[Release Notes for Safari Technology Preview 17 | WebKit]]
( ([TIME[2016-11-10 10:08:39 +09:00]]))
<https://webkit.org/blog/7071/release-notes-for-safari-technology-preview-17/>
]FIGCAPTION]

> Fixed WebAudio to resume when moving from background to foreground tab (r208092)

]FIG]


[67] [CITE@en[Background Tabs in Chrome 57  |  Web  |  Google Developers]]
([TIME[2017-03-14 09:42:32 +09:00]])
<https://developers.google.com/web/updates/2017/03/background_tabs>

[69] [CITE@en[Vibration API Recommendation errata · w3c/vibration@b844ba9]]
([TIME[2016-04-27 12:32:30 +09:00]] 版)
<https://github.com/w3c/vibration/commit/b844ba923d9a4c9b04398dd793011b5ace48f242>


[72] [CITE@ja[大山ゆっけ(蘇る鈴木佑輔)さんはTwitterを使っています 「Chromeが画面裏にあるウィンドウのアプリ動作を止めるという糞みたいな糞機能を実装したせいでブラウザゲーム複数同時進行勢から大量の悲鳴が上がっているという。」 / Twitter]]
([TIME[2021-11-02T01:54:36.000Z]], [TIME[2021-11-02T01:59:45.957Z]])
<https://twitter.com/trinity_site/status/1455121637796241418>