2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

VivaldiでYouTubeのネイティブPiPが表示されない原因と解決方法(Enhancer for YouTube)

2
Posted at

この記事の概要

  • Enhancer for YouTubeがCSSを追加する
  • そのCSSの影響でVivaldiのPiPボタンが z-index の競合(stacking context)で背後に隠れてしまう
  • UserScript で PiP ボタンの親 divz-index を変更することで解決できる

1. はじめに

こんにちは、ピーラップ(Prrapp)です。

私は普段ブラウザとして Vivaldi を使っています。

YouTubeを見る際は拡張機能「Enhancer for YouTube」を利用しているのですが、次の問題に気づきました。

YouTubeだけ Vivaldi ネイティブの PiP(Picture-in-Picture)が使えない。

原因を調べたところ、拡張機能によって追加される CSS の影響で
PiP ボタンがプレイヤーの背後に隠れてしまいクリックできない状態になっていました。

そこで今回は、この問題を UserScript で解決する方法 を紹介します。

2. この記事の概要

2-1. 対象読者

  • Vivaldi を使用している
  • Enhancer for YouTube を使っている
  • PiP が表示されない問題に困っている

2-2. 症状例

動画プレイヤーにマウスカーソルを重ねてもPiPボタンが表示されません。(Snipping Toolではマウスカーソルがキャプチャされないため表示されていません)
image.png
(引用元:フレデリック「オドループ」Music Video | Frederic "oddloop")

今回作成したUserScriptを使用して正常にした場合、このようになります。

image.png
(引用元:フレデリック「オドループ」Music Video | Frederic "oddloop")

(シークバーが緑色になっているのはEnhancer for YouTubeの機能です)

2-3. 技術ポイント

今回の問題では次の技術要素が関係しています。

  • CSS z-index
  • Shadow DOM
  • ブラウザ拡張によるUI干渉
  • UserScriptによるDOM操作

3. 環境

項目 バージョン
ブラウザ Vivaldi 7.8.3925.76 (64-bit)
カスタムバージョン 144.0.7559.238
OS Windows 11 25H2 (Build 26200.7922)
Enhancer for YouTube 3.0.16
UserScriptマネージャー Tampermonkey 5.4.1

4. 原因

4-1. 症状

Vivaldi Forumで指摘されていますが、VivaldiではPiPボタンに z-index: 10 が設定されています。
しかし、Enhancer for YouTube はプレイヤー要素に z-index: 301 を追加します。

その結果、プレイヤーがPiPボタンの上に表示されてしまい、クリックできなくなります。
それが分かったので、自分で調べて実装を考えてみます。
イメージとして断面図で表すと、次のような状態になります。

見る方向
↓
[プレイヤー (z-index: 301)]
[PiPボタン (z-index: 10)]

プレイヤー要素の z-index が高いため、
PiPボタンがプレイヤーの背後に隠れてしまいます。

4-2. ネイティブPiPボタンの構造

VivaldiのPiPボタン自体はこんな感じの構造になっていました。

/
└─ div(クラスなし)
   └─ #shadow-root (open)
      ├─ link(Vivaldi内部拡張へのリンク)
      └─ div(クラス名:vivaldi-picture-in-picture-container)
         └─ input

4-3. 検証

まず、PiPボタン側の z-index2147483647z-indexの最大値)に変更してみました。
しかし、これだけでは表示されませんでした。
原因は、z-index の競合が 親要素のレイヤー構造 に依存していたためです。
そこで、Shadow DOMの外側にある親要素(div)の z-index
2147483647に変更すると正常に表示されることを確認できました。

5. 解決策

PiPボタンは Shadow DOM 内にありますが、
.vivaldi-picture-in-picture-container から親要素を取得することで
外側の div にアクセスできます。(外側のdivはクラス名とidがないので直接取得するのは難しいです)

そこで以下の方針で解決します。

  1. .vivaldi-picture-in-picture-container を取得
  2. Shadow DOM の外側の親 div を取得
  3. その z-index2147483647 に変更

この処理をUserScriptで実装します。

6. 実装

長いので折りたたみにしています
// ==UserScript==
// @name         VivaldiのPiPのEnhancer for YouTube使用時の不具合を解決する
// @namespace    https://qiita.com/Prrapp
// @version      1.11.0
// @author       Prrapp
// @description  VivaldiのPiPのEnhancer for YouTube使用時の不具合を解決します。
// @match        https://www.youtube.com/*
// @grant        none
// @license      MIT
// ==/UserScript==

(function () {
    'use strict';

    let cachedHost = null;
    const shadowHosts = new Set();

    function scanShadowHosts() {
        const elements = document.querySelectorAll('*');
        for (const el of elements) {
            if (el.shadowRoot) shadowHosts.add(el);
        }
    }

    function findPipHost() {
        for (const host of shadowHosts) {
            const root = host.shadowRoot;
            if (!root) continue;

            const pip = root.querySelector('.vivaldi-picture-in-picture-container');
            if (!pip) continue;

            const nodeRoot = pip.getRootNode();
            if (!nodeRoot || !nodeRoot.host) continue;

            return nodeRoot.host;
        }

        return null;
    }

    function applyZIndex() {
        const host = findPipHost();
        if (!host) return;

        const current = getComputedStyle(host).zIndex;
        if (cachedHost === host && current === '2147483647') return;

        host.style.setProperty('z-index', '2147483647', 'important');
        cachedHost = host;
    }

    scanShadowHosts();

    const observer = new MutationObserver(() => {
        scanShadowHosts();
        applyZIndex();
    });

    observer.observe(document.documentElement, {
        childList: true,
        subtree: true
    });

    setInterval(() => {
        if (!cachedHost || !cachedHost.isConnected) {
            scanShadowHosts();
        }
        applyZIndex();
    }, 800);

    const reset = () => {
        cachedHost = null;
        shadowHosts.clear();
        scanShadowHosts();
    };

    document.addEventListener('yt-navigate-finish', reset);
    document.addEventListener('yt-page-data-updated', reset);
})();

7. 使い方

7-1. Greasyforkを利用した方法(推奨)

  1. Tampermonkeyをインストールする
  2. GreasyforkからこのUserScriptをインストールする

7-2. 手動インストール(非推奨)

  1. Tampermonkeyをインストールする
  2. 5-2の実装したものをコピーする
  3. 右上のTampermonkeyの拡張機能アイコンから「新規スクリプトを追加」
  4. 開いたページのコードを削除してペースト
  5. Ctrl(Cmd) + S(保存)

8. まとめ

Enhancer for YouTube を使用すると
Vivaldi のネイティブ PiP が表示されない問題が発生する場合があります。

原因は、拡張機能によって追加された CSS により
PiPボタンがプレイヤーの背後に隠れてしまうことでした。

この記事では以下の方法で解決しました。

  • UserScript を作成
  • PiPボタンの親 divz-index を変更
  • Tampermonkey で実行

このように、ブラウザ拡張機能による UI の競合は
UserScript で DOM を調整することで回避できる場合があります。

拡張機能を自作するよりも
手軽に試せる解決方法になるケースもあります。

同じ問題で困っている方の参考になれば幸いです。

Ex. Before/After

Ex-1. Before

image.png

Ex-2. After

image.png
(Ex-1,Ex-2ともに引用元はフレデリック「オドループ」Music Video | Frederic "oddloop"です)

2
0
0

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?