tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

shadow-cascade-order-001.html (16221B)


      1 <!DOCTYPE html>
      2 <html>
      3 <head>
      4 <title>Shadow DOM: CSS Style Rule cascading</title>
      5 <meta name="assert" content="Cascading order test for style rules from various shadow trees.">
      6 <link rel="author" title="Takayoshi Kochi" href="mailto:kochi@google.com">
      7 <link rel="help" href="https://drafts.csswg.org/css-scoping-1/#shadow-cascading">
      8 <script src="/resources/testharness.js"></script>
      9 <script src="/resources/testharnessreport.js"></script>
     10 </head>
     11 <body>
     12 <div id="log"></div>
     13 <script>
     14 
     15 // Taken from the example in
     16 // https://github.com/w3c/webcomponents/blob/gh-pages/proposals/Shadow-DOM-Cascade-Order.md
     17 // https://github.com/w3c/webcomponents/issues/316
     18 // https://github.com/w3c/webcomponents/blob/gh-pages/proposals/Shadow-DOM-Cascade-Order-in-v1.md
     19 // with element renamed and style rule location changed.
     20 //
     21 // <style>my-item { color: red; }</style>
     22 // <my-list>
     23 //   <:shadow>
     24 //     <style>::slotted(my-item) { color: blue; }</style>
     25 //     <slot></slot>
     26 //   </:shadow>
     27 //   <my-item style="color: green;">
     28 //     <:shadow>
     29 //       <style>:host { color: yellow; }</style>
     30 //       <slot></slot>
     31 //     </:shadow>
     32 //     ITEM
     33 //   </my-item>
     34 // </my-list>
     35 //
     36 // There are 4 possible style rules that applies to <my-item> above:
     37 // 1. document-wide style
     38 // 2. ::slotted style in the shadow in <my-list>
     39 // 3. :host style in the shadow in <my-item>
     40 // 4. inline style within <my-item> itself.
     41 //
     42 // It could be possible to nest many more shadow trees in <my-list>,
     43 // but to prevent the number of combination explosion, such case is covered
     44 // in another test file.
     45 //
     46 // So testing cases where 2 style rules are competing,
     47 // 4C2 = 6 combinations exist, multiplied by 4, which is the possible
     48 // combination of applying "!important" for the 2 style rules.
     49 
     50 function createMyList(mode, slottedStyle, hostStyle, inlineStyle) {
     51    var myList = document.createElement('my-list');
     52    var root = myList.attachShadow({'mode': mode});
     53    root.innerHTML = '<style>' + slottedStyle + '</style><slot></slot>';
     54    var myItem = document.createElement('my-item');
     55    if (inlineStyle !== '')
     56        myItem.setAttribute('style', inlineStyle);
     57    myList.appendChild(myItem);
     58    var root2 = myItem.attachShadow({'mode': mode});
     59    root2.innerHTML = '<style>' + hostStyle + '</style><slot></slot>';
     60    myItem.appendChild(document.createTextNode('ITEM'));
     61    return myList;
     62 }
     63 
     64 function testCascadingOrder(mode) {
     65    // In all test cases, the rule specified as "color: green" should win.
     66    var testCases = [
     67        // [A] Cases between document, ::slotteed, :host, and inline
     68        {
     69            title: 'A1. document vs ::slotted, document rule should win',
     70            documentStyle: 'my-item { color: green; }',
     71            slottedStyle: '::slotted(my-item) { color: red; }',
     72            hostStyle: '',
     73            inlineStyle: ''
     74        },
     75        {
     76            title: 'A2. document vs :host, document rule should win',
     77            documentStyle: 'my-item { color: green; }',
     78            slottedStyle: '',
     79            hostStyle: ':host { color: red; }',
     80            inlineStyle: ''
     81        },
     82        {
     83            title: 'A3. document vs inline, inline rule should win',
     84            documentStyle: 'my-item { color: red; }',
     85            slottedStyle: '',
     86            hostStyle: '',
     87            inlineStyle: 'color: green;'
     88        },
     89        {
     90            title: 'A4. ::slotted vs :host, earlier in tree-of-trees rule should win',
     91            documentStyle: '',
     92            slottedStyle: '::slotted(my-item) { color: green; }',
     93            hostStyle: ':host { color: red; }',
     94            inlineStyle: ''
     95        },
     96        {
     97            title: 'A5. ::slotted vs inline, inline rule should win',
     98            documentStyle: '',
     99            slottedStyle: '::slotted(my-item) { color: red; }',
    100            hostStyle: '',
    101            inlineStyle: 'color: green;'
    102        },
    103        {
    104            title: 'A6. :host vs inline, inline rule should win',
    105            documentStyle: '',
    106            slottedStyle: '',
    107            hostStyle: ':host { color: red; }',
    108            inlineStyle: 'color: green;'
    109        },
    110 
    111        // [B] Stronger rule is still stronger with !important
    112        {
    113            title: 'B1. document with !important vs ::slotted, document rule should win',
    114            documentStyle: 'my-item { color: green !important; }',
    115            slottedStyle: '::slotted(my-item) { color: red; }',
    116            hostStyle: '',
    117            inlineStyle: ''
    118        },
    119        {
    120            title: 'B2. document with !important vs :host, document rule should win',
    121            documentStyle: 'my-item { color: green !important; }',
    122            slottedStyle: '',
    123            hostStyle: ':host { color: red; }',
    124            inlineStyle: ''
    125        },
    126        {
    127            title: 'B3. document vs inline with !important, inline rule should win',
    128            documentStyle: 'my-item { color: red; }',
    129            slottedStyle: '',
    130            hostStyle: '',
    131            inlineStyle: 'color: green !important;'
    132        },
    133        {
    134            title: 'B4. ::slotted  with !important vs :host, earlier in tree-of-trees rule should win',
    135            documentStyle: '',
    136            slottedStyle: '::slotted(my-item) { color: green !important; }',
    137            hostStyle: ':host { color: red; }',
    138            inlineStyle: ''
    139        },
    140        {
    141            title: 'B5. ::slotted vs inline with !important, inline rule should win',
    142            documentStyle: '',
    143            slottedStyle: '::slotted(my-item) { color: green !important; }',
    144            hostStyle: '',
    145            inlineStyle: 'color: red;'
    146        },
    147        {
    148            title: 'B6. :host vs inline with !important, inline rule should win',
    149            documentStyle: '',
    150            slottedStyle: '',
    151            hostStyle: ':host { color: red; }',
    152            inlineStyle: 'color: green !important;'
    153        },
    154 
    155        // [C] Weaker rule gets stronger with !important
    156        {
    157            title: 'C1. document vs ::slotted with !important, ::slotted rule should win',
    158            documentStyle: 'my-item { color: red; }',
    159            slottedStyle: '::slotted(my-item) { color: green !important; }',
    160            hostStyle: '',
    161            inlineStyle: ''
    162        },
    163        {
    164            title: 'C2. document vs :host with !important, :host rule should win',
    165            documentStyle: 'my-item { color: red; }',
    166            slottedStyle: '',
    167            hostStyle: ':host { color: green !important; }',
    168            inlineStyle: ''
    169        },
    170        {
    171            title: 'C3. document with !important vs inline, document rule should win',
    172            documentStyle: 'my-item { color: green !important; }',
    173            slottedStyle: '',
    174            hostStyle: '',
    175            inlineStyle: 'color: red;'
    176        },
    177        {
    178            title: 'C4. ::slotted vs :host with !important, later in tree-of-trees rule should win',
    179            documentStyle: '',
    180            slottedStyle: '::slotted(my-item) { color: green !important; }',
    181            hostStyle: ':host { color: red; }',
    182            inlineStyle: ''
    183        },
    184        {
    185            title: 'C5. ::slotted with !important vs inline, ::slotted rule should win',
    186            documentStyle: '',
    187            slottedStyle: '::slotted(my-item) { color: green !important; }',
    188            hostStyle: '',
    189            inlineStyle: 'color: red;'
    190        },
    191        {
    192            title: 'C6. :host with !important vs inline, :host rule should win',
    193            documentStyle: '',
    194            slottedStyle: '',
    195            hostStyle: ':host { color: green !important; }',
    196            inlineStyle: 'color: red;'
    197        },
    198 
    199        // [D] Cases between document, ::slotteed, :host, and inline, both with !important
    200        {
    201            title: 'D1. document vs ::slotted both with !important, ::slotted rule should win',
    202            documentStyle: 'my-item { color: red !important; }',
    203            slottedStyle: '::slotted(my-item) { color: green !important; }',
    204            hostStyle: '',
    205            inlineStyle: ''
    206        },
    207        {
    208            title: 'D2. document vs :host both with !important, :host rule should win',
    209            documentStyle: 'my-item { color: red !important; }',
    210            slottedStyle: '',
    211            hostStyle: ':host { color: green !important; }',
    212            inlineStyle: ''
    213        },
    214        {
    215            title: 'D3. document vs inline both with !important, inline rule should win',
    216            documentStyle: 'my-item { color: red !important; }',
    217            slottedStyle: '',
    218            hostStyle: '',
    219            inlineStyle: 'color: green !important;'
    220        },
    221        {
    222            title: 'D4. ::slotted vs :host both with !important, later in tree-of-trees rule should win',
    223            documentStyle: '',
    224            slottedStyle: '::slotted(my-item) { color: red !important; }',
    225            hostStyle: ':host { color: green !important; }',
    226            inlineStyle: ''
    227        },
    228        {
    229            title: 'D5. ::slotted vs inline both with !important, ::slotted rule should win',
    230            documentStyle: '',
    231            slottedStyle: '::slotted(my-item) { color: green !important; }',
    232            hostStyle: '',
    233            inlineStyle: 'color: red !important;'
    234        },
    235        {
    236            title: 'D6. :host vs inline both with !important, :host rule should win',
    237            documentStyle: '',
    238            slottedStyle: '',
    239            hostStyle: ':host { color: green !important; }',
    240            inlineStyle: 'color: red !important;'
    241        },
    242        // [E] Putting all together
    243        {
    244            title: 'E1. all style applied, inline rule should win',
    245            documentStyle: 'my-item { color: red; }',
    246            slottedStyle: '::slotted(my-item) { color: blue; }',
    247            hostStyle: ':host { color: yellow; }',
    248            inlineStyle: 'color: green;'
    249        },
    250        {
    251            title: 'E2. all styles with !important applied, rule in the last tree-of-trees should win',
    252            documentStyle: 'my-item { color: red !important; }',
    253            slottedStyle: '::slotted(my-item) { color: blue !important; }',
    254            hostStyle: ':host { color: green !important; }',
    255            inlineStyle: 'color: yellow !important;'
    256        },
    257    ];
    258 
    259    for (var i = 0; i < testCases.length; ++i) {
    260        var testCase = testCases[i];
    261        var documentStyle = document.createElement('style');
    262        documentStyle.appendChild(document.createTextNode(testCase['documentStyle']));
    263        document.head.appendChild(documentStyle);
    264 
    265        var myList = createMyList(mode,
    266            testCase['slottedStyle'], testCase['hostStyle'], testCase['inlineStyle']);
    267        document.body.appendChild(myList);
    268 
    269        test(function () {
    270            var myItem = myList.querySelector('my-item');
    271            assert_equals(window.getComputedStyle(myItem).color, 'rgb(0, 128, 0)',
    272                          testCase['title']);
    273        }, testCase['title'] + ' for ' + mode + ' mode.');
    274 
    275        myList.parentNode.removeChild(myList);
    276        document.head.removeChild(documentStyle)
    277    }
    278 }
    279 
    280 // Open or Closed should not make any difference in style application.
    281 testCascadingOrder('open');
    282 testCascadingOrder('closed');
    283 
    284 
    285 // Taken from the example in
    286 // https://github.com/w3c/webcomponents/blob/gh-pages/proposals/Shadow-DOM-Cascade-Order.md
    287 // https://github.com/w3c/webcomponents/issues/316
    288 // https://github.com/w3c/webcomponents/blob/gh-pages/proposals/Shadow-DOM-Cascade-Order-in-v1.md
    289 // with element renamed and style rule location changed.
    290 //
    291 // <style>my-item { color: red; }</style>
    292 // <my-list>
    293 //   <:shadow>
    294 //     <style>::slotted(my-item) { color: blue; }</style>
    295 //     <div>
    296 //       <:shadow>
    297 //         <slot/>
    298 //       </:shadow>
    299 //       <slot/>
    300 //     </div>
    301 //   </:shadow>
    302 //   <my-item style="color: green;">
    303 //     <:shadow>
    304 //       <style>:host { color: yellow; }</style>
    305 //       <slot/>
    306 //     </:shadow>
    307 //     ITEM
    308 //   </my-item>
    309 // </my-list>
    310 //
    311 // The difference from the example tree above is that <my-list> has 2 levels of
    312 // shadow trees, each with ::slotted(my-list) style rules.
    313 
    314 function createMyListWith2LevelShadow(mode, slottedStyle1, slottedStyle2, hostStyle) {
    315    var myList = document.createElement('my-list');
    316    var root = myList.attachShadow({'mode': mode});
    317    root.innerHTML = '<style>' + slottedStyle1 + '</style><div><slot></slot></div>';
    318    var div = root.querySelector('div');
    319    var root2 = div.attachShadow({'mode': mode});
    320    root2.innerHTML = '<style>' + slottedStyle2 + '</style><slot></slot>';
    321    var myItem = document.createElement('my-item');
    322    myList.appendChild(myItem);
    323    var root3 = myItem.attachShadow({'mode': mode});
    324    root3.innerHTML = '<style>' + hostStyle + '</style><slot></slot>';
    325    myItem.appendChild(document.createTextNode('ITEM'));
    326    return myList;
    327 }
    328 
    329 function testCascadingOrderWith2LevelShadow(mode) {
    330    // In all test cases, the rule specified as "color: green" should win.
    331    var testCases = [
    332        {
    333            title: 'F1. document vs others, document (the first rule in tree-of-trees order) rule should win',
    334            documentStyle: 'my-item { color: green; }',
    335            slottedStyle1: '::slotted(my-item) { color: red; }',
    336            slottedStyle2: '::slotted(my-item) { color: red; }',
    337            hostStyle: ':host { color: red; }',
    338        },
    339        {
    340            title: 'F2. document with !important vs others, document rule should win',
    341            documentStyle: 'my-item { color: green !important; }',
    342            slottedStyle1: '::slotted(my-item) { color: red; }',
    343            slottedStyle2: '::slotted(my-item) { color: red; }',
    344            hostStyle: ':host { color: red; }',
    345        },
    346        {
    347            title: 'F3. document vs ::slotted with !important, important rule should win',
    348            documentStyle: 'my-item { color: red; }',
    349            slottedStyle1: '::slotted(my-item) { color: green !important; }',
    350            slottedStyle2: '::slotted(my-item) { color: red; }',
    351            hostStyle: ':host { color: red; }',
    352        },
    353        {
    354            title: 'F4. document vs ::slotted with !important, important rule should win',
    355            documentStyle: 'my-item { color: red; }',
    356            slottedStyle1: '::slotted(my-item) { color: red; }',
    357            slottedStyle2: '::slotted(my-item) { color: green !important; }',
    358            hostStyle: ':host { color: red; }',
    359        },
    360        {
    361            title: 'F5. document vs :host with !important, important rule should win',
    362            documentStyle: 'my-item { color: red; }',
    363            slottedStyle1: '::slotted(my-item) { color: red; }',
    364            slottedStyle2: '::slotted(my-item) { color: red; }',
    365            hostStyle: ':host { color: green !important; }',
    366        },
    367        {
    368            title: 'F6. all rules with !important, the last rule in tree-of-trees should win',
    369            documentStyle: 'my-item { color: red !important; }',
    370            slottedStyle1: '::slotted(my-item) { color: red !important; }',
    371            slottedStyle2: '::slotted(my-item) { color: red !important; }',
    372            hostStyle: ':host { color: green !important ; }',
    373        }
    374    ];
    375 
    376    for (var i = 0; i < testCases.length; ++i) {
    377        var testCase = testCases[i];
    378        var documentStyle = document.createElement('style');
    379        documentStyle.appendChild(document.createTextNode(testCase['documentStyle']));
    380        document.head.appendChild(documentStyle);
    381 
    382        var myList = createMyListWith2LevelShadow(mode,
    383            testCase['slottedStyle1'], testCase['slottedStyle2'], testCase['hostStyle']);
    384        document.body.appendChild(myList);
    385 
    386        test(function () {
    387            var myItem = myList.querySelector('my-item');
    388            assert_equals(window.getComputedStyle(myItem).color, 'rgb(0, 128, 0)',
    389                          testCase['title']);
    390        }, testCase['title'] + ' for ' + mode + ' mode.');
    391 
    392        myList.parentNode.removeChild(myList);
    393        document.head.removeChild(documentStyle)
    394    }
    395 }
    396 
    397 // Open or Closed should not make any difference in style application.
    398 testCascadingOrderWith2LevelShadow('open');
    399 testCascadingOrderWith2LevelShadow('closed');
    400 
    401 </script>
    402 </body>
    403 </html>