scope-invalidation.html (21480B)
1 <!DOCTYPE html> 2 <title>@scope - invalidation</title> 3 <link rel="help" href="https://drafts.csswg.org/css-cascade-6/#scope-atrule"> 4 <script src="/resources/testharness.js"></script> 5 <script src="/resources/testharnessreport.js"></script> 6 <script> 7 8 function test_scope_invalidation(script_element, callback_fn, description) { 9 test((t) => { 10 // The provided <script> element must be an immedate subsequent sibling of 11 // a <template> element. 12 let template_element = script_element.previousElementSibling; 13 assert_equals(template_element.tagName, 'TEMPLATE'); 14 15 t.add_cleanup(() => { 16 while (main.firstChild) 17 main.firstChild.remove() 18 }); 19 20 main.append(template_element.content.cloneNode(true)); 21 22 callback_fn(); 23 }, description); 24 } 25 26 function assert_green(element) { 27 assert_equals(getComputedStyle(element).backgroundColor, 'rgb(0, 128, 0)'); 28 } 29 function assert_red(element) { 30 assert_equals(getComputedStyle(element).backgroundColor, 'rgb(255, 0, 0)'); 31 } 32 function assert_not_green(element) { 33 assert_equals(getComputedStyle(element).backgroundColor, 'rgb(0, 0, 0)'); 34 } 35 </script> 36 <style> 37 main * { 38 background-color: black; 39 } 40 </style> 41 <main id=main> 42 </main> 43 44 <!-- Tests follow --> 45 46 <template> 47 <style> 48 @scope (.a) { 49 span { background-color: green; } 50 } 51 </style> 52 <div> 53 <span></span> 54 </div> 55 </template> 56 <script> 57 test_scope_invalidation(document.currentScript, () => { 58 let div = main.querySelector('div'); 59 let span = main.querySelector('div > span'); 60 assert_not_green(span); 61 div.classList.add('a'); 62 assert_green(span); 63 div.classList.remove('a'); 64 assert_not_green(span); 65 }, 'Element becoming scope root'); 66 </script> 67 68 <template> 69 <style> 70 @scope (.a, .b) { 71 span { background-color: green; } 72 } 73 </style> 74 <div> 75 <span></span> 76 </div> 77 </template> 78 <script> 79 test_scope_invalidation(document.currentScript, () => { 80 let div = main.querySelector('div'); 81 let span = main.querySelector('div > span'); 82 83 // .a 84 assert_not_green(span); 85 div.classList.add('a'); 86 assert_green(span); 87 div.classList.remove('a'); 88 assert_not_green(span); 89 90 // .b 91 assert_not_green(span); 92 div.classList.add('b'); 93 assert_green(span); 94 div.classList.remove('b'); 95 assert_not_green(span); 96 }, 'Element becoming scope root (selector list)'); 97 </script> 98 99 <template> 100 <style> 101 @scope (.a) { 102 :scope { background-color: green; } 103 } 104 </style> 105 <div class=b></div> 106 </template> 107 <script> 108 test_scope_invalidation(document.currentScript, () => { 109 let b = main.querySelector('.b'); 110 assert_not_green(b); 111 b.classList.add('a'); 112 assert_green(b); 113 b.classList.remove('a'); 114 assert_not_green(b); 115 }, 'Element becoming scope root, with inner :scope rule'); 116 </script> 117 118 <template> 119 <style> 120 @scope (.a) to (.b) { 121 span { background-color: green; } 122 } 123 </style> 124 <div class=a> 125 <div> 126 <span></span> 127 </div> 128 </div> 129 </template> 130 <script> 131 test_scope_invalidation(document.currentScript, () => { 132 let inner_div = main.querySelector('.a > div'); 133 let span = main.querySelector('.a > div > span'); 134 assert_green(span); 135 inner_div.classList.add('b'); 136 assert_not_green(span); 137 inner_div.classList.remove('b'); 138 assert_green(span); 139 }, 'Parent element becoming scope limit'); 140 </script> 141 142 <template> 143 <style> 144 @scope (.a) to (.b, .c) { 145 span { background-color: green; } 146 } 147 </style> 148 <div class=a> 149 <div> 150 <span></span> 151 </div> 152 </div> 153 </template> 154 <script> 155 test_scope_invalidation(document.currentScript, () => { 156 let inner_div = main.querySelector('.a > div'); 157 let span = main.querySelector('.a > div > span'); 158 159 // .b 160 assert_green(span); 161 inner_div.classList.add('b'); 162 assert_not_green(span); 163 inner_div.classList.remove('b'); 164 assert_green(span); 165 166 // .c 167 assert_green(span); 168 inner_div.classList.add('c'); 169 assert_not_green(span); 170 inner_div.classList.remove('c'); 171 assert_green(span); 172 }, 'Parent element becoming scope limit (selector list)'); 173 </script> 174 175 <template> 176 <style> 177 @scope (.a) to (.b) { 178 span { background-color: green; } 179 } 180 </style> 181 <div class=a> 182 <div> 183 <span></span> 184 </div> 185 </div> 186 </template> 187 <script> 188 test_scope_invalidation(document.currentScript, () => { 189 let span = main.querySelector('.a > div > span'); 190 assert_green(span); 191 span.classList.add('b'); 192 assert_not_green(span); 193 span.classList.remove('b'); 194 assert_green(span); 195 }, 'Subject element becoming scope limit'); 196 </script> 197 198 <template> 199 <style> 200 @scope (.a) to (.b .c) { 201 span { background-color: green; } 202 } 203 </style> 204 <div class=a> 205 <div> 206 <div class=c> 207 <span></span> 208 </div> 209 </div> 210 </div> 211 </template> 212 <script> 213 test_scope_invalidation(document.currentScript, () => { 214 let intermediate_div = main.querySelector('.a > div'); 215 let span = main.querySelector('span'); 216 assert_green(span); 217 intermediate_div.classList.add('b'); 218 assert_not_green(span); 219 intermediate_div.classList.remove('b'); 220 assert_green(span); 221 }, 'Parent element affecting scope limit'); 222 </script> 223 224 <template> 225 <style> 226 @scope (.a) to (.b ~ .c) { 227 span { background-color: green; } 228 } 229 </style> 230 <div class=a> 231 <div></div> 232 <div></div> 233 <div></div> 234 <div></div> 235 <div class=c> 236 <span></span> 237 </div> 238 </div> 239 </template> 240 <script> 241 test_scope_invalidation(document.currentScript, () => { 242 let sibling_div = main.querySelector('.a > div'); 243 let span = main.querySelector('span'); 244 assert_green(span); 245 sibling_div.classList.add('b'); 246 assert_not_green(span); 247 sibling_div.classList.remove('b'); 248 assert_green(span); 249 }, 'Sibling element affecting scope limit'); 250 </script> 251 252 <template> 253 <style> 254 @scope (.a) { 255 @scope (.b) { 256 span { background-color: green; } 257 } 258 } 259 </style> 260 <div> 261 <div> 262 <span></span> 263 </div> 264 </div> 265 </template> 266 <script> 267 test_scope_invalidation(document.currentScript, () => { 268 let outer_div = main.querySelector(':scope > div'); 269 let inner_div = main.querySelector(':scope > div > div'); 270 let span = main.querySelector('div > div > span'); 271 272 assert_not_green(span); 273 274 outer_div.classList.add('a'); 275 assert_not_green(span); 276 277 inner_div.classList.add('b'); 278 assert_green(span); 279 280 // Toggle .b while .a remains. 281 inner_div.classList.remove('b'); 282 assert_not_green(span); 283 inner_div.classList.add('b'); 284 assert_green(span); 285 286 // Toggle .a while .b remains. 287 outer_div.classList.remove('a'); 288 assert_not_green(span); 289 outer_div.classList.add('a'); 290 assert_green(span); 291 }, 'Toggling inner/outer scope roots'); 292 </script> 293 294 295 <template> 296 <style> 297 @scope (.a) { 298 :scope { background-color:green; } 299 } 300 </style> 301 <div></div> 302 </template> 303 <script> 304 test_scope_invalidation(document.currentScript, () => { 305 let div = main.querySelector('main > div'); 306 assert_not_green(div); 307 div.classList.add('a'); 308 assert_green(div); 309 div.classList.remove('a'); 310 assert_not_green(div); 311 }, 'Element becoming root, with :scope in subject'); 312 </script> 313 314 315 <template> 316 <style> 317 @scope (.a:has(.c)) { 318 .b { background-color:green; } 319 } 320 </style> 321 <div class=a> 322 <div class=b> 323 <div></div> 324 </div> 325 </div> 326 </template> 327 <script> 328 test_scope_invalidation(document.currentScript, () => { 329 let b = main.querySelector('.b'); 330 let innermost = main.querySelector('.b > div'); 331 assert_not_green(b); 332 innermost.classList.add('c'); 333 assert_green(b); 334 innermost.classList.remove('c'); 335 assert_not_green(b); 336 }, 'Scope root with :has()'); 337 </script> 338 339 340 <template> 341 <style> 342 @scope (.a:has(.c)) { 343 :scope { background-color:green; } 344 } 345 </style> 346 <div class=a> 347 <div class=b> 348 <div></div> 349 </div> 350 </div> 351 </template> 352 <script> 353 test_scope_invalidation(document.currentScript, () => { 354 let a = main.querySelector('.a'); 355 let innermost = main.querySelector('.b > div'); 356 assert_not_green(a); 357 innermost.classList.add('c'); 358 assert_green(a); 359 innermost.classList.remove('c'); 360 assert_not_green(a); 361 }, 'Scope root with :has(), :scope subject'); 362 </script> 363 364 365 <template> 366 <style> 367 @scope (.a:has(.c)) { 368 :scope { background-color:green; } 369 :scope .b { background-color:green; } 370 } 371 </style> 372 <div class=a> 373 <div class=b> 374 <div></div> 375 </div> 376 </div> 377 </template> 378 <script> 379 test_scope_invalidation(document.currentScript, () => { 380 let a = main.querySelector('.a'); 381 let b = main.querySelector('.b'); 382 let innermost = main.querySelector('.b > div'); 383 assert_not_green(a); 384 assert_not_green(b); 385 innermost.classList.add('c'); 386 assert_green(a); 387 assert_green(b); 388 innermost.classList.remove('c'); 389 assert_not_green(a); 390 assert_not_green(b); 391 }, 'Scope root with :has(), :scope both subject and non-subject'); 392 </script> 393 394 395 <template> 396 <style> 397 @scope (.a) to (.b:has(.c)) { 398 .b { background-color:green; } 399 } 400 </style> 401 <div class=a> 402 <div class=b> 403 <div></div> 404 </div> 405 </div> 406 </template> 407 <script> 408 test_scope_invalidation(document.currentScript, () => { 409 let b = main.querySelector('.b'); 410 let innermost = main.querySelector('.b > div'); 411 assert_green(b); 412 innermost.classList.add('c'); 413 assert_not_green(b); 414 innermost.classList.remove('c'); 415 assert_green(b); 416 }, 'Scope limit with :has()'); 417 </script> 418 419 <template> 420 <style> 421 @scope (.a) { 422 .b ~ :scope { background-color:green; } 423 } 424 </style> 425 <div></div> 426 <div></div> 427 </template> 428 <script> 429 test_scope_invalidation(document.currentScript, () => { 430 let div1 = main.querySelector('main > div:nth-of-type(1)'); 431 let div2 = main.querySelector('main > div:nth-of-type(2)'); 432 433 assert_not_green(div2); 434 div1.classList.add('b'); 435 assert_not_green(div2); 436 div2.classList.add('a'); 437 assert_green(div2); 438 div1.classList.remove('b'); 439 assert_not_green(div2); 440 }, 'Element becoming root, with :scope selected by ~ combinator'); 441 </script> 442 443 <template> 444 <style> 445 @scope (.a ~ .b) { 446 .c { background-color:green; } 447 } 448 </style> 449 <div> 450 <div></div> 451 <div></div> 452 <div></div> 453 <div class=b> 454 <div class=c></div> 455 </div> 456 </div> 457 </template> 458 <script> 459 test_scope_invalidation(document.currentScript, () => { 460 let root = main.querySelector('div > div:first-child'); 461 let c = main.querySelector('.c'); 462 assert_not_green(c); 463 root.classList.add('a'); 464 assert_green(c); 465 root.classList.remove('a'); 466 assert_not_green(c); 467 }, 'Element becoming root via ~ combinator'); 468 </script> 469 470 <template> 471 <style> 472 @scope (.a + .b) { 473 .c { background-color:green; } 474 } 475 </style> 476 <div> 477 <div></div> 478 <div class=b> 479 <div class=c></div> 480 </div> 481 </div> 482 </template> 483 <script> 484 test_scope_invalidation(document.currentScript, () => { 485 let root = main.querySelector('div > div:first-child'); 486 let c = main.querySelector('.c'); 487 assert_not_green(c); 488 root.classList.add('a'); 489 assert_green(c); 490 root.classList.remove('a'); 491 assert_not_green(c); 492 }, 'Element becoming root via + combinator'); 493 </script> 494 495 <template> 496 <style> 497 @scope (.root) { 498 :not(:scope) { background-color:green; } 499 } 500 </style> 501 <div class=root> 502 <div class=a></div> 503 <div class=b></div> 504 <div class=c></div> 505 </div> 506 <div class=a></div> 507 </template> 508 <script> 509 test_scope_invalidation(document.currentScript, () => { 510 let root = main.querySelector('.root'); 511 let a1 = main.querySelector('.root > .a'); 512 let b = main.querySelector('.root > .b'); 513 let c = main.querySelector('.root > .c'); 514 let a2 = main.querySelector('main > .a'); 515 516 assert_not_green(root); 517 assert_green(a1); 518 assert_green(b); 519 assert_green(c); 520 assert_not_green(a2); 521 522 root.classList.remove('root'); 523 assert_not_green(root); 524 assert_not_green(a1); 525 assert_not_green(b); 526 assert_not_green(c); 527 assert_not_green(a2); 528 529 root.classList.add('root'); 530 assert_not_green(root); 531 assert_green(a1); 532 assert_green(b); 533 assert_green(c); 534 assert_not_green(a2); 535 }, ':not(scope) in subject'); 536 </script> 537 538 <template> 539 <style> 540 @scope (.root) { 541 :not(:scope) > .a { background-color:green; } 542 } 543 </style> 544 <div class=root> 545 <div class=a></div> 546 <div> 547 <div class=a></div> 548 </div> 549 </div> 550 </template> 551 <script> 552 test_scope_invalidation(document.currentScript, () => { 553 let root = main.querySelector('.root'); 554 let outer_a = main.querySelector('.root > .a'); 555 let inner_a = main.querySelector('.root > div > .a'); 556 557 assert_not_green(outer_a); 558 assert_green(inner_a); 559 560 root.classList.remove('root'); 561 assert_not_green(outer_a); 562 assert_not_green(inner_a); 563 564 root.classList.add('root'); 565 assert_not_green(outer_a); 566 assert_green(inner_a); 567 }, ':not(scope) in ancestor'); 568 </script> 569 570 <template> 571 <style> 572 @scope (.root) to (:not(:scope)) { 573 :is(div, :scope) { background-color: green; } 574 } 575 </style> 576 <div class=root> 577 <div class=a></div> 578 </div> 579 </template> 580 <script> 581 test_scope_invalidation(document.currentScript, () => { 582 let root = main.querySelector('.root'); 583 let a = main.querySelector('.root > .a'); 584 585 assert_green(root); 586 assert_not_green(a); 587 588 root.classList.remove('root'); 589 assert_not_green(root); 590 assert_not_green(a); 591 592 root.classList.add('root'); 593 assert_green(root); 594 assert_not_green(a); 595 }, ':not(scope) in limit subject'); 596 </script> 597 598 <template> 599 <style> 600 @scope (.root) to (:not(:scope) > .a) { 601 :is(div, :scope) { background-color: green; } 602 } 603 </style> 604 <div class=root> 605 <div class=a> 606 <div class=a></div> 607 </div> 608 </div> 609 </template> 610 <script> 611 test_scope_invalidation(document.currentScript, () => { 612 let root = main.querySelector('.root'); 613 let outer_a = main.querySelector('.root > .a'); 614 let inner_a = main.querySelector('.root > .a > .a'); 615 616 assert_green(root); 617 assert_green(outer_a); 618 assert_not_green(inner_a); 619 620 root.classList.remove('root'); 621 assert_not_green(root); 622 assert_not_green(outer_a); 623 assert_not_green(inner_a); 624 625 root.classList.add('root'); 626 assert_green(root); 627 assert_green(outer_a); 628 assert_not_green(inner_a); 629 }, ':not(scope) in limit ancestor'); 630 </script> 631 632 <template> 633 <style> 634 @scope (:nth-child(2n of .a)) { 635 :scope { background-color: green; } 636 } 637 </style> 638 <div id=wrapper> 639 <div class=a></div> 640 <div></div> 641 <div class=a></div> 642 <div></div> 643 <div class=a></div> 644 <div></div> 645 <div class=a></div> 646 <div></div> 647 </div> 648 </template> 649 <script> 650 test_scope_invalidation(document.currentScript, () => { 651 let e = main.querySelectorAll('#wrapper > div'); 652 assert_equals(e.length, 8); 653 654 // <div class=a></div> 655 // <div></div> 656 // <div class=a></div> 657 // <div></div> 658 // <div class=a></div> 659 // <div></div> 660 // <div class=a></div> 661 // <div></div> 662 assert_not_green(e[0]); 663 assert_not_green(e[1]); 664 assert_green(e[2]); 665 assert_not_green(e[3]); 666 assert_not_green(e[4]); 667 assert_not_green(e[5]); 668 assert_green(e[6]); 669 assert_not_green(e[7]); 670 671 e[1].classList.add('a'); 672 // <div class=a></div> 673 // <div class=a></div> 674 // <div class=a></div> 675 // <div></div> 676 // <div class=a></div> 677 // <div></div> 678 // <div class=a></div> 679 // <div></div> 680 assert_not_green(e[0]); 681 assert_green(e[1]); 682 assert_not_green(e[2]); 683 assert_not_green(e[3]); 684 assert_green(e[4]); 685 assert_not_green(e[5]); 686 assert_not_green(e[6]); 687 assert_not_green(e[7]); 688 689 e[1].classList.remove('a'); 690 // <div class=a></div> 691 // <div></div> 692 // <div class=a></div> 693 // <div></div> 694 // <div class=a></div> 695 // <div></div> 696 // <div class=a></div> 697 // <div></div> 698 assert_not_green(e[0]); 699 assert_not_green(e[1]); 700 assert_green(e[2]); 701 assert_not_green(e[3]); 702 assert_not_green(e[4]); 703 assert_not_green(e[5]); 704 assert_green(e[6]); 705 assert_not_green(e[7]); 706 }, ':nth-child() in scope root'); 707 </script> 708 709 <template> 710 <style> 711 @scope (#wrapper) to (:nth-child(4n of .a)) { 712 div { background-color: green; } 713 } 714 </style> 715 <div id=wrapper> 716 <div class=a></div> 717 <div></div> 718 <div class=a></div> 719 <div></div> 720 <div class=a></div> 721 <div></div> 722 <div class=a></div> 723 <div></div> 724 </div> 725 </template> 726 <script> 727 test_scope_invalidation(document.currentScript, () => { 728 let e = main.querySelectorAll('#wrapper > div'); 729 assert_equals(e.length, 8); 730 731 // <div class=a></div> 732 // <div></div> 733 // <div class=a></div> 734 // <div></div> 735 // <div class=a></div> 736 // <div></div> 737 // <div class=a></div> <= limit 738 // <div></div> 739 assert_green(e[0]); 740 assert_green(e[1]); 741 assert_green(e[2]); 742 assert_green(e[3]); 743 assert_green(e[4]); 744 assert_green(e[5]); 745 assert_not_green(e[6]); 746 assert_green(e[7]); 747 748 e[1].classList.add('a'); 749 // <div class=a></div> 750 // <div class=a></div> 751 // <div class=a></div> 752 // <div></div> 753 // <div class=a></div> <= limit 754 // <div></div> 755 // <div class=a></div> 756 // <div></div> 757 assert_green(e[0]); 758 assert_green(e[1]); 759 assert_green(e[2]); 760 assert_green(e[3]); 761 assert_not_green(e[4]); 762 assert_green(e[5]); 763 assert_green(e[6]); 764 assert_green(e[7]); 765 766 e[1].classList.remove('a'); 767 // <div class=a></div> 768 // <div></div> 769 // <div class=a></div> 770 // <div></div> 771 // <div class=a></div> 772 // <div></div> 773 // <div class=a></div> <= limit 774 // <div></div> 775 assert_green(e[0]); 776 assert_green(e[1]); 777 assert_green(e[2]); 778 assert_green(e[3]); 779 assert_green(e[4]); 780 assert_green(e[5]); 781 assert_not_green(e[6]); 782 assert_green(e[7]); 783 }, ':nth-child() in scope limit'); 784 785 </script> 786 787 <template> 788 <style> 789 @scope (.a) { 790 .nomatch { background-color: green; } 791 } 792 </style> 793 <div id=wrapper> 794 <div class=a> 795 <div class=b></div> 796 </div> 797 </div> 798 </template> 799 <script> 800 test_scope_invalidation(document.currentScript, () => { 801 let b = main.querySelector('.b'); 802 assert_not_green(b); 803 let scope_rule = main.querySelector('style').sheet.cssRules[0]; 804 assert_true(scope_rule instanceof CSSScopeRule); 805 scope_rule.cssRules[0].selectorText = '.b'; 806 assert_green(b); 807 }, 'Modifying selectorText invalidates affected elements'); 808 </script> 809 810 <template> 811 <style> 812 @scope (.a) { 813 .nomatch { background-color: green; } 814 } 815 </style> 816 <div id=wrapper> 817 <div class=a> 818 <div class=b></div> 819 </div> 820 </div> 821 </template> 822 <script> 823 test_scope_invalidation(document.currentScript, () => { 824 let b = main.querySelector('.b'); 825 assert_not_green(b); 826 let scope_rule = main.querySelector('style').sheet.cssRules[0]; 827 assert_true(scope_rule instanceof CSSScopeRule); 828 scope_rule.cssRules[0].selectorText = '> .b'; 829 assert_green(b); 830 }, 'Modifying selectorText invalidates affected elements (>)'); 831 </script> 832 833 <template> 834 <style> 835 .a { 836 > .b, > .c { 837 background-color: green; /* Specificity: (0, 2, 0) */ 838 } 839 } 840 @scope (.a.a) { 841 .nomatch1 { 842 background-color: red; /* Specificity: (0, 1, 0) */ 843 } 844 .nomatch2 { 845 background-color: red; /* Specificity: (0, 1, 0) */ 846 } 847 } 848 </style> 849 <div id=wrapper> 850 <div class=a> 851 <div class=b></div> 852 <div class=c></div> 853 </div> 854 </div> 855 </template> 856 <script> 857 test_scope_invalidation(document.currentScript, () => { 858 let b = main.querySelector('.b'); 859 let c = main.querySelector('.c'); 860 assert_green(b); 861 assert_green(c); 862 let scope_rule = main.querySelector('style').sheet.cssRules[1]; 863 assert_true(scope_rule instanceof CSSScopeRule); 864 scope_rule.cssRules[0].selectorText = '> .b'; /* Still (0, 1, 0) */ 865 scope_rule.cssRules[1].selectorText = '& > .c'; /* Still (0, 1, 0) */ 866 assert_green(b); 867 assert_green(c); 868 }, 'Relative selectors set with selectorText are relative to :scope and &'); 869 </script> 870 871 <template> 872 <style> 873 @scope (.a .b) { 874 @scope(.c .d, .e .f) { 875 .g { 876 background-color: green; 877 } 878 } 879 } 880 </style> 881 <div class=a> 882 <div class=b> 883 <div class=e> 884 <div class=f> 885 <div class=g> 886 </div> 887 </div> 888 </div> 889 </div> 890 </div> 891 </template> 892 <script> 893 test_scope_invalidation(document.currentScript, () => { 894 let a = main.querySelector('.a'); 895 let g = main.querySelector('.g'); 896 assert_green(g); 897 a.classList.remove('a'); 898 assert_not_green(g); 899 a.classList.add('a'); 900 assert_green(g); 901 }, 'Ancestor element affecting nested scope root (Through latter selector in list)') 902 </script> 903 904 <template> 905 <style> 906 @scope (.a) to (.b .c) { 907 :scope .d .f{ 908 background-color: green; 909 } 910 } 911 </style> 912 913 <div class=a> 914 <div class=b> 915 <div class=d> 916 <div class=c> 917 <div class=f> 918 </div> 919 </div> 920 </div> 921 </div> 922 </div> 923 </template> 924 <script> 925 test_scope_invalidation(document.currentScript, () => { 926 let b = main.querySelector('.b'); 927 let f = main.querySelector('.f'); 928 assert_not_green(f); 929 b.classList.remove('b'); 930 assert_green(f); 931 b.classList.add('b'); 932 assert_not_green(f); 933 }, 'Parent element of subject affecting scope limit') 934 </script> 935 936 <template> 937 <div class=a> 938 <div><div><div><div> 939 <style> 940 @scope(.a) { 941 @scope { 942 @scope(> .b) { 943 :scope { background: green; } 944 } 945 } 946 } 947 </style> 948 <div class=b></div> 949 </div></div></div></div> 950 </div> 951 </template> 952 <script> 953 test_scope_invalidation(document.currentScript, () => { 954 let a = main.querySelector('.a'); 955 let b = main.querySelector('.b'); 956 assert_green(b); 957 a.classList.remove('a'); 958 assert_not_green(b); 959 a.classList.add('a'); 960 assert_green(b); 961 }, 'Sandwiched deep implicit scope root, :scope in subject') 962 </script>