isolate video player against opaque-bg regressions (recurring INC class)
Two-layer defense for the recurring "black screen during playback" bug class (5+ occurrences in 24h per doc 26/28/30): L1 (prevention): scope every black-bg rule with :not(:has(.htmlVideoPlayer)):not(:has(#videoOsdPage)) so the rules self-disable while a player is in the DOM. Covers body, #reactRoot, .skinBody, .backgroundContainer, .mainAnimatedPage, .mainAnimatedPages, .pageContainer. L2 (override): when JS-toggled body.arrflix-video-active is set, high-specificity (0,3,2 + tag) transparent rule wins against any ancestor opaque-bg rule (including future regressions someone adds without scoping). Covers all known wrappers, the videoPlayerContainer + videoPlayerContainer-onTop, #videoOsdPage, .libraryPage, .htmlVideoPlayer. L3 (z-index lift): force .htmlVideoPlayer + child <video> to z-index:9999 + isolation:isolate during playback so it floats above any opaque ancestor that still leaks through. Verified in playwright: with arrflix-video-active + .htmlVideoPlayer mounted, all 7 ancestors return rgba(0,0,0,0). Without — all 7 return rgb(0,0,0). Self-disabling works. Lesson reinforced (doc 30 roadmap open): add darkPct assertion to bin/headless-test-v2.py + xmllint CI gate. Five recurrences without those gates says we keep relearning this. TODO next.
This commit is contained in:
parent
e9d209da73
commit
452ce68d7a
3 changed files with 21 additions and 9 deletions
|
|
@ -53,9 +53,13 @@ CSS = (
|
||||||
".arrflix-nav{text-transform:uppercase;letter-spacing:.08em;font-weight:600;padding:0 .9em;color:#fff!important;text-decoration:none;display:inline-flex;align-items:center;height:100%;font-size:.85em;transition:color .18s ease,text-shadow .18s ease,font-weight .18s ease}\n"
|
".arrflix-nav{text-transform:uppercase;letter-spacing:.08em;font-weight:600;padding:0 .9em;color:#fff!important;text-decoration:none;display:inline-flex;align-items:center;height:100%;font-size:.85em;transition:color .18s ease,text-shadow .18s ease,font-weight .18s ease}\n"
|
||||||
".arrflix-nav:hover{color:#E50914!important}\n"
|
".arrflix-nav:hover{color:#E50914!important}\n"
|
||||||
".arrflix-nav.active{color:#E50914!important;font-weight:700;text-shadow:0 0 12px rgba(229,9,20,0.55),0 0 24px rgba(229,9,20,0.25)}\n"
|
".arrflix-nav.active{color:#E50914!important;font-weight:700;text-shadow:0 0 12px rgba(229,9,20,0.55),0 0 24px rgba(229,9,20,0.25)}\n"
|
||||||
"/* Pure-black background: kill the #101010 stripe that bleeds at page bottom (jellyfin-web/themes/dark/theme.css:44-50 .backgroundContainer + html) */\n"
|
"/* Pure-black background — L1: scope rules to non-video pages so they self-disable when player mounts. Skips when .htmlVideoPlayer or #videoOsdPage is in the DOM. Doc 30 lesson — recurring black-screen-over-video bug class. */\n"
|
||||||
"html,body.arrflix-themed,body.arrflix-themed .backgroundContainer,body.arrflix-themed .skinBody,body.arrflix-themed .mainAnimatedPage,body.arrflix-themed .mainAnimatedPages,body.arrflix-themed .pageContainer,body.arrflix-themed #reactRoot{background-color:#000!important}\n"
|
"html,body.arrflix-themed:not(:has(.htmlVideoPlayer)):not(:has(#videoOsdPage)),body.arrflix-themed:not(:has(.htmlVideoPlayer)):not(:has(#videoOsdPage)) .backgroundContainer,body.arrflix-themed:not(:has(.htmlVideoPlayer)):not(:has(#videoOsdPage)) .skinBody,body.arrflix-themed:not(:has(.htmlVideoPlayer)):not(:has(#videoOsdPage)) .mainAnimatedPage,body.arrflix-themed:not(:has(.htmlVideoPlayer)):not(:has(#videoOsdPage)) .mainAnimatedPages,body.arrflix-themed:not(:has(.htmlVideoPlayer)):not(:has(#videoOsdPage)) .pageContainer,body.arrflix-themed:not(:has(.htmlVideoPlayer)):not(:has(#videoOsdPage)) #reactRoot{background-color:#000!important}\n"
|
||||||
"body.arrflix-themed .backgroundContainer.withBackdrop{background-color:rgba(0,0,0,.86)!important}\n"
|
"body.arrflix-themed:not(:has(.htmlVideoPlayer)):not(:has(#videoOsdPage)) .backgroundContainer.withBackdrop{background-color:rgba(0,0,0,.86)!important}\n"
|
||||||
|
"/* Video isolation L2: high-specificity transparent override gated by JS-toggled body.arrflix-video-active. Beats any ancestor opaque-bg rule (specificity 0,3,2 plus tag) by chaining 2 body classes + the wrapper class. */\n"
|
||||||
|
"body.arrflix-themed.arrflix-video-active,body.arrflix-themed.arrflix-video-active .backgroundContainer,body.arrflix-themed.arrflix-video-active .skinBody,body.arrflix-themed.arrflix-video-active .mainAnimatedPage,body.arrflix-themed.arrflix-video-active .mainAnimatedPages,body.arrflix-themed.arrflix-video-active .pageContainer,body.arrflix-themed.arrflix-video-active #reactRoot,body.arrflix-themed.arrflix-video-active .videoPlayerContainer,body.arrflix-themed.arrflix-video-active .videoPlayerContainer-onTop,body.arrflix-themed.arrflix-video-active #videoOsdPage,body.arrflix-themed.arrflix-video-active #videoOsdPage .pageContainer,body.arrflix-themed.arrflix-video-active #videoOsdPage .mainAnimatedPage,body.arrflix-themed.arrflix-video-active #videoOsdPage .layout-desktop,body.arrflix-themed.arrflix-video-active .libraryPage,body.arrflix-themed.arrflix-video-active .htmlVideoPlayer{background-color:transparent!important;background:transparent!important;background-image:none!important}\n"
|
||||||
|
"/* Video element on top of all stacking contexts during playback. */\n"
|
||||||
|
"body.arrflix-themed.arrflix-video-active video.htmlvideoplayer,body.arrflix-themed.arrflix-video-active .htmlVideoPlayer video,body.arrflix-themed.arrflix-video-active .htmlVideoPlayer{z-index:9999!important;isolation:isolate}\n"
|
||||||
"/* Search input: replace stock cyan focus ring (jellyfin-web/themes/dark/theme.css:262-272) with a borderless slab + red underline on focus, true to the Cineplex/Netflix accent */\n"
|
"/* Search input: replace stock cyan focus ring (jellyfin-web/themes/dark/theme.css:262-272) with a borderless slab + red underline on focus, true to the Cineplex/Netflix accent */\n"
|
||||||
"body.arrflix-themed .searchFields .emby-input,body.arrflix-themed input.searchfields-txtSearch,body.arrflix-themed #searchTextInput{background:#141414!important;border:0!important;border-bottom:2px solid transparent!important;border-radius:2px!important;color:#fff!important;transition:border-color .18s ease,box-shadow .18s ease,background-color .18s ease;padding:.55em .8em!important}\n"
|
"body.arrflix-themed .searchFields .emby-input,body.arrflix-themed input.searchfields-txtSearch,body.arrflix-themed #searchTextInput{background:#141414!important;border:0!important;border-bottom:2px solid transparent!important;border-radius:2px!important;color:#fff!important;transition:border-color .18s ease,box-shadow .18s ease,background-color .18s ease;padding:.55em .8em!important}\n"
|
||||||
"body.arrflix-themed .searchFields .emby-input::placeholder,body.arrflix-themed input.searchfields-txtSearch::placeholder,body.arrflix-themed #searchTextInput::placeholder{color:rgba(255,255,255,.4);letter-spacing:.02em}\n"
|
"body.arrflix-themed .searchFields .emby-input::placeholder,body.arrflix-themed input.searchfields-txtSearch::placeholder,body.arrflix-themed #searchTextInput::placeholder{color:rgba(255,255,255,.4);letter-spacing:.02em}\n"
|
||||||
|
|
|
||||||
|
|
@ -259,9 +259,13 @@ body.arrflix-video-active:not(:has(#loginPage:not(.hide))) .skinHeader,body.arrf
|
||||||
.arrflix-nav{text-transform:uppercase;letter-spacing:.08em;font-weight:600;padding:0 .9em;color:#fff!important;text-decoration:none;display:inline-flex;align-items:center;height:100%;font-size:.85em;transition:color .18s ease,text-shadow .18s ease,font-weight .18s ease}
|
.arrflix-nav{text-transform:uppercase;letter-spacing:.08em;font-weight:600;padding:0 .9em;color:#fff!important;text-decoration:none;display:inline-flex;align-items:center;height:100%;font-size:.85em;transition:color .18s ease,text-shadow .18s ease,font-weight .18s ease}
|
||||||
.arrflix-nav:hover{color:#E50914!important}
|
.arrflix-nav:hover{color:#E50914!important}
|
||||||
.arrflix-nav.active{color:#E50914!important;font-weight:700;text-shadow:0 0 12px rgba(229,9,20,0.55),0 0 24px rgba(229,9,20,0.25)}
|
.arrflix-nav.active{color:#E50914!important;font-weight:700;text-shadow:0 0 12px rgba(229,9,20,0.55),0 0 24px rgba(229,9,20,0.25)}
|
||||||
/* Pure-black background: kill the #101010 stripe that bleeds at page bottom (jellyfin-web/themes/dark/theme.css:44-50 .backgroundContainer + html) */
|
/* Pure-black background — L1: scope rules to non-video pages so they self-disable when player mounts. Skips when .htmlVideoPlayer or #videoOsdPage is in the DOM. Doc 30 lesson — recurring black-screen-over-video bug class. */
|
||||||
html,body.arrflix-themed,body.arrflix-themed .backgroundContainer,body.arrflix-themed .skinBody,body.arrflix-themed .mainAnimatedPage,body.arrflix-themed .mainAnimatedPages,body.arrflix-themed .pageContainer,body.arrflix-themed #reactRoot{background-color:#000!important}
|
html,body.arrflix-themed:not(:has(.htmlVideoPlayer)):not(:has(#videoOsdPage)),body.arrflix-themed:not(:has(.htmlVideoPlayer)):not(:has(#videoOsdPage)) .backgroundContainer,body.arrflix-themed:not(:has(.htmlVideoPlayer)):not(:has(#videoOsdPage)) .skinBody,body.arrflix-themed:not(:has(.htmlVideoPlayer)):not(:has(#videoOsdPage)) .mainAnimatedPage,body.arrflix-themed:not(:has(.htmlVideoPlayer)):not(:has(#videoOsdPage)) .mainAnimatedPages,body.arrflix-themed:not(:has(.htmlVideoPlayer)):not(:has(#videoOsdPage)) .pageContainer,body.arrflix-themed:not(:has(.htmlVideoPlayer)):not(:has(#videoOsdPage)) #reactRoot{background-color:#000!important}
|
||||||
body.arrflix-themed .backgroundContainer.withBackdrop{background-color:rgba(0,0,0,.86)!important}
|
body.arrflix-themed:not(:has(.htmlVideoPlayer)):not(:has(#videoOsdPage)) .backgroundContainer.withBackdrop{background-color:rgba(0,0,0,.86)!important}
|
||||||
|
/* Video isolation L2: high-specificity transparent override gated by JS-toggled body.arrflix-video-active. Beats any ancestor opaque-bg rule (specificity 0,3,2 plus tag) by chaining 2 body classes + the wrapper class. */
|
||||||
|
body.arrflix-themed.arrflix-video-active,body.arrflix-themed.arrflix-video-active .backgroundContainer,body.arrflix-themed.arrflix-video-active .skinBody,body.arrflix-themed.arrflix-video-active .mainAnimatedPage,body.arrflix-themed.arrflix-video-active .mainAnimatedPages,body.arrflix-themed.arrflix-video-active .pageContainer,body.arrflix-themed.arrflix-video-active #reactRoot,body.arrflix-themed.arrflix-video-active .videoPlayerContainer,body.arrflix-themed.arrflix-video-active .videoPlayerContainer-onTop,body.arrflix-themed.arrflix-video-active #videoOsdPage,body.arrflix-themed.arrflix-video-active #videoOsdPage .pageContainer,body.arrflix-themed.arrflix-video-active #videoOsdPage .mainAnimatedPage,body.arrflix-themed.arrflix-video-active #videoOsdPage .layout-desktop,body.arrflix-themed.arrflix-video-active .libraryPage,body.arrflix-themed.arrflix-video-active .htmlVideoPlayer{background-color:transparent!important;background:transparent!important;background-image:none!important}
|
||||||
|
/* Video element on top of all stacking contexts during playback. */
|
||||||
|
body.arrflix-themed.arrflix-video-active video.htmlvideoplayer,body.arrflix-themed.arrflix-video-active .htmlVideoPlayer video,body.arrflix-themed.arrflix-video-active .htmlVideoPlayer{z-index:9999!important;isolation:isolate}
|
||||||
/* Search input: replace stock cyan focus ring (jellyfin-web/themes/dark/theme.css:262-272) with a borderless slab + red underline on focus, true to the Cineplex/Netflix accent */
|
/* Search input: replace stock cyan focus ring (jellyfin-web/themes/dark/theme.css:262-272) with a borderless slab + red underline on focus, true to the Cineplex/Netflix accent */
|
||||||
body.arrflix-themed .searchFields .emby-input,body.arrflix-themed input.searchfields-txtSearch,body.arrflix-themed #searchTextInput{background:#141414!important;border:0!important;border-bottom:2px solid transparent!important;border-radius:2px!important;color:#fff!important;transition:border-color .18s ease,box-shadow .18s ease,background-color .18s ease;padding:.55em .8em!important}
|
body.arrflix-themed .searchFields .emby-input,body.arrflix-themed input.searchfields-txtSearch,body.arrflix-themed #searchTextInput{background:#141414!important;border:0!important;border-bottom:2px solid transparent!important;border-radius:2px!important;color:#fff!important;transition:border-color .18s ease,box-shadow .18s ease,background-color .18s ease;padding:.55em .8em!important}
|
||||||
body.arrflix-themed .searchFields .emby-input::placeholder,body.arrflix-themed input.searchfields-txtSearch::placeholder,body.arrflix-themed #searchTextInput::placeholder{color:rgba(255,255,255,.4);letter-spacing:.02em}
|
body.arrflix-themed .searchFields .emby-input::placeholder,body.arrflix-themed input.searchfields-txtSearch::placeholder,body.arrflix-themed #searchTextInput::placeholder{color:rgba(255,255,255,.4);letter-spacing:.02em}
|
||||||
|
|
|
||||||
|
|
@ -259,9 +259,13 @@ body.arrflix-video-active:not(:has(#loginPage:not(.hide))) .skinHeader,body.arrf
|
||||||
.arrflix-nav{text-transform:uppercase;letter-spacing:.08em;font-weight:600;padding:0 .9em;color:#fff!important;text-decoration:none;display:inline-flex;align-items:center;height:100%;font-size:.85em;transition:color .18s ease,text-shadow .18s ease,font-weight .18s ease}
|
.arrflix-nav{text-transform:uppercase;letter-spacing:.08em;font-weight:600;padding:0 .9em;color:#fff!important;text-decoration:none;display:inline-flex;align-items:center;height:100%;font-size:.85em;transition:color .18s ease,text-shadow .18s ease,font-weight .18s ease}
|
||||||
.arrflix-nav:hover{color:#E50914!important}
|
.arrflix-nav:hover{color:#E50914!important}
|
||||||
.arrflix-nav.active{color:#E50914!important;font-weight:700;text-shadow:0 0 12px rgba(229,9,20,0.55),0 0 24px rgba(229,9,20,0.25)}
|
.arrflix-nav.active{color:#E50914!important;font-weight:700;text-shadow:0 0 12px rgba(229,9,20,0.55),0 0 24px rgba(229,9,20,0.25)}
|
||||||
/* Pure-black background: kill the #101010 stripe that bleeds at page bottom (jellyfin-web/themes/dark/theme.css:44-50 .backgroundContainer + html) */
|
/* Pure-black background — L1: scope rules to non-video pages so they self-disable when player mounts. Skips when .htmlVideoPlayer or #videoOsdPage is in the DOM. Doc 30 lesson — recurring black-screen-over-video bug class. */
|
||||||
html,body.arrflix-themed,body.arrflix-themed .backgroundContainer,body.arrflix-themed .skinBody,body.arrflix-themed .mainAnimatedPage,body.arrflix-themed .mainAnimatedPages,body.arrflix-themed .pageContainer,body.arrflix-themed #reactRoot{background-color:#000!important}
|
html,body.arrflix-themed:not(:has(.htmlVideoPlayer)):not(:has(#videoOsdPage)),body.arrflix-themed:not(:has(.htmlVideoPlayer)):not(:has(#videoOsdPage)) .backgroundContainer,body.arrflix-themed:not(:has(.htmlVideoPlayer)):not(:has(#videoOsdPage)) .skinBody,body.arrflix-themed:not(:has(.htmlVideoPlayer)):not(:has(#videoOsdPage)) .mainAnimatedPage,body.arrflix-themed:not(:has(.htmlVideoPlayer)):not(:has(#videoOsdPage)) .mainAnimatedPages,body.arrflix-themed:not(:has(.htmlVideoPlayer)):not(:has(#videoOsdPage)) .pageContainer,body.arrflix-themed:not(:has(.htmlVideoPlayer)):not(:has(#videoOsdPage)) #reactRoot{background-color:#000!important}
|
||||||
body.arrflix-themed .backgroundContainer.withBackdrop{background-color:rgba(0,0,0,.86)!important}
|
body.arrflix-themed:not(:has(.htmlVideoPlayer)):not(:has(#videoOsdPage)) .backgroundContainer.withBackdrop{background-color:rgba(0,0,0,.86)!important}
|
||||||
|
/* Video isolation L2: high-specificity transparent override gated by JS-toggled body.arrflix-video-active. Beats any ancestor opaque-bg rule (specificity 0,3,2 plus tag) by chaining 2 body classes + the wrapper class. */
|
||||||
|
body.arrflix-themed.arrflix-video-active,body.arrflix-themed.arrflix-video-active .backgroundContainer,body.arrflix-themed.arrflix-video-active .skinBody,body.arrflix-themed.arrflix-video-active .mainAnimatedPage,body.arrflix-themed.arrflix-video-active .mainAnimatedPages,body.arrflix-themed.arrflix-video-active .pageContainer,body.arrflix-themed.arrflix-video-active #reactRoot,body.arrflix-themed.arrflix-video-active .videoPlayerContainer,body.arrflix-themed.arrflix-video-active .videoPlayerContainer-onTop,body.arrflix-themed.arrflix-video-active #videoOsdPage,body.arrflix-themed.arrflix-video-active #videoOsdPage .pageContainer,body.arrflix-themed.arrflix-video-active #videoOsdPage .mainAnimatedPage,body.arrflix-themed.arrflix-video-active #videoOsdPage .layout-desktop,body.arrflix-themed.arrflix-video-active .libraryPage,body.arrflix-themed.arrflix-video-active .htmlVideoPlayer{background-color:transparent!important;background:transparent!important;background-image:none!important}
|
||||||
|
/* Video element on top of all stacking contexts during playback. */
|
||||||
|
body.arrflix-themed.arrflix-video-active video.htmlvideoplayer,body.arrflix-themed.arrflix-video-active .htmlVideoPlayer video,body.arrflix-themed.arrflix-video-active .htmlVideoPlayer{z-index:9999!important;isolation:isolate}
|
||||||
/* Search input: replace stock cyan focus ring (jellyfin-web/themes/dark/theme.css:262-272) with a borderless slab + red underline on focus, true to the Cineplex/Netflix accent */
|
/* Search input: replace stock cyan focus ring (jellyfin-web/themes/dark/theme.css:262-272) with a borderless slab + red underline on focus, true to the Cineplex/Netflix accent */
|
||||||
body.arrflix-themed .searchFields .emby-input,body.arrflix-themed input.searchfields-txtSearch,body.arrflix-themed #searchTextInput{background:#141414!important;border:0!important;border-bottom:2px solid transparent!important;border-radius:2px!important;color:#fff!important;transition:border-color .18s ease,box-shadow .18s ease,background-color .18s ease;padding:.55em .8em!important}
|
body.arrflix-themed .searchFields .emby-input,body.arrflix-themed input.searchfields-txtSearch,body.arrflix-themed #searchTextInput{background:#141414!important;border:0!important;border-bottom:2px solid transparent!important;border-radius:2px!important;color:#fff!important;transition:border-color .18s ease,box-shadow .18s ease,background-color .18s ease;padding:.55em .8em!important}
|
||||||
body.arrflix-themed .searchFields .emby-input::placeholder,body.arrflix-themed input.searchfields-txtSearch::placeholder,body.arrflix-themed #searchTextInput::placeholder{color:rgba(255,255,255,.4);letter-spacing:.02em}
|
body.arrflix-themed .searchFields .emby-input::placeholder,body.arrflix-themed input.searchfields-txtSearch::placeholder,body.arrflix-themed #searchTextInput::placeholder{color:rgba(255,255,255,.4);letter-spacing:.02em}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue