media-pseudo-classes-in-has.html (3928B)
1 <!DOCTYPE html> 2 <title>:has() invalidation with :playing, :paused, :seeking and :muted pseudo-classes</title> 3 <link rel="author" title="Tim Nguyen" href="https://github.com/nt1m"> 4 <link rel="help" href="https://drafts.csswg.org/selectors/#relational"> 5 <link rel="help" href="https://drafts.csswg.org/selectors/#video-state"> 6 <style> 7 #subject { 8 background-color: black; 9 accent-color: black; 10 color: black; 11 border: 2px solid black; 12 } 13 #subject:has(:muted) { 14 background-color: red; 15 } 16 #subject:has(:playing) { 17 border-color: green; 18 } 19 #subject:has(:paused) { 20 color: orange; 21 } 22 #subject:has(:seeking) { 23 accent-color: blue; 24 } 25 </style> 26 <body> 27 <div id="subject"> 28 Test media pseudo-classes invalidation with :has() 29 <input type="checkbox"> 30 <video width="300" height="300" loop></video> 31 </div> 32 <script src="/resources/testharness.js"></script> 33 <script src="/resources/testharnessreport.js"></script> 34 <script src="/common/media.js"></script> 35 <script> 36 const GREEN = "rgb(0, 128, 0)"; 37 const ORANGE = "rgb(255, 165, 0)"; 38 const BLUE = "rgb(0, 0, 255)"; 39 const RED = "rgb(255, 0, 0)"; 40 const BLACK = "rgb(0, 0, 0)"; 41 42 function assert_matches_muted(muted) { 43 assert_equals(getComputedStyle(subject).backgroundColor, muted ? RED : BLACK); 44 } 45 46 function assert_matches_playing(playing) { 47 assert_equals(getComputedStyle(subject).borderColor, playing ? GREEN : BLACK); 48 assert_equals(getComputedStyle(subject).color, !playing ? ORANGE : BLACK); 49 } 50 51 function assert_matches_seeking(seeking) { 52 assert_equals(getComputedStyle(subject).accentColor, seeking ? BLUE : BLACK); 53 } 54 55 promise_test(async (t) => { 56 assert_implements(CSS.supports("selector(:playing)"), ":playing is not supported"); 57 t.add_cleanup(() => { 58 video.muted = false; 59 video.pause(); 60 video.removeAttribute("src"); 61 }); 62 const video = document.querySelector("video"); 63 assert_matches_muted(false); 64 assert_matches_playing(false); 65 assert_matches_seeking(false); 66 await new Promise((r) => { 67 video.addEventListener("canplay", r, { once: true }); 68 video.src = getVideoURI("/media/counting"); 69 }); 70 video.muted = true; // allows us to play the video 71 assert_matches_muted(true); 72 await new Promise((r) => { 73 video.addEventListener("playing", r, { once: true }); 74 video.play(); 75 }); 76 assert_matches_playing(true); 77 }, "Test :playing pseudo-class"); 78 79 promise_test(async (t) => { 80 assert_implements(CSS.supports("selector(:seeking)"), ":seeking is not supported"); 81 t.add_cleanup(() => { 82 video.removeAttribute("src"); 83 }); 84 const video = document.querySelector("video"); 85 assert_matches_muted(false); 86 assert_matches_playing(false); 87 assert_matches_seeking(false); 88 await new Promise((r) => { 89 video.addEventListener("canplay", r, { once: true }); 90 video.src = getVideoURI("/media/counting"); 91 }); 92 93 assert_matches_seeking(false); 94 await new Promise((r) => { 95 video.addEventListener("seeking", r, { once: true }); 96 video.currentTime = 10; 97 }); 98 assert_matches_seeking(true); 99 }, "Test :seeking pseudo-class"); 100 101 promise_test(async (t) => { 102 assert_implements(CSS.supports("selector(:muted)"), ":muted is not supported"); 103 t.add_cleanup(() => { 104 video.removeAttribute("src"); 105 }); 106 const video = document.querySelector("video"); 107 await new Promise((r) => { 108 video.addEventListener("canplay", r, { once: true }); 109 video.src = getVideoURI("/media/counting"); 110 }); 111 assert_matches_muted(false); 112 video.muted = true; 113 assert_matches_muted(true); 114 video.muted = false; 115 assert_matches_muted(false); 116 }, "Test :muted pseudo-class"); 117 </script> 118 </body>