nested-declarations-cssom.html (7588B)
1 <!DOCTYPE html> 2 <title>CSS Nesting: CSSNestedDeclarations CSSOM</title> 3 <link rel="help" href="https://drafts.csswg.org/css-nesting-1/#nested-declarations-rule"> 4 <script src="/resources/testharness.js"></script> 5 <script src="/resources/testharnessreport.js"></script> 6 <script> 7 test(() => { 8 let s = new CSSStyleSheet(); 9 s.replaceSync(` 10 .a { 11 & { --x:1; } 12 --x:2; 13 } 14 `); 15 assert_equals(s.cssRules.length, 1); 16 let outer = s.cssRules[0]; 17 assert_equals(outer.cssRules.length, 2); 18 assert_equals(outer.cssRules[0].cssText, `& { --x: 1; }`); 19 assert_equals(outer.cssRules[1].cssText, `--x: 2;`); 20 }, 'Trailing declarations'); 21 22 test(() => { 23 let s = new CSSStyleSheet(); 24 s.replaceSync(` 25 .a { 26 --a:1; 27 --b:1; 28 & { --c:1; } 29 --d:1; 30 --e:1; 31 & { --f:1; } 32 --g:1; 33 --h:1; 34 --i:1; 35 & { --j:1; } 36 --k:1; 37 --l:1; 38 } 39 `); 40 assert_equals(s.cssRules.length, 1); 41 let outer = s.cssRules[0]; 42 assert_equals(outer.cssRules.length, 6); 43 assert_equals(outer.cssRules[0].cssText, `& { --c: 1; }`); 44 assert_equals(outer.cssRules[1].cssText, `--d: 1; --e: 1;`); 45 assert_equals(outer.cssRules[2].cssText, `& { --f: 1; }`); 46 assert_equals(outer.cssRules[3].cssText, `--g: 1; --h: 1; --i: 1;`); 47 assert_equals(outer.cssRules[4].cssText, `& { --j: 1; }`); 48 assert_equals(outer.cssRules[5].cssText, `--k: 1; --l: 1;`); 49 }, 'Mixed declarations'); 50 51 test(() => { 52 let s = new CSSStyleSheet(); 53 s.replaceSync(` 54 .a { 55 & { --x:1; } 56 --y:2; 57 --z:3; 58 } 59 `); 60 assert_equals(s.cssRules.length, 1); 61 let outer = s.cssRules[0]; 62 assert_equals(outer.cssRules.length, 2); 63 let nested_declarations = outer.cssRules[1]; 64 assert_true(nested_declarations instanceof CSSNestedDeclarations); 65 assert_equals(nested_declarations.style.length, 2); 66 assert_equals(nested_declarations.style.getPropertyValue('--x'), ''); 67 assert_equals(nested_declarations.style.getPropertyValue('--y'), '2'); 68 assert_equals(nested_declarations.style.getPropertyValue('--z'), '3'); 69 }, 'CSSNestedDeclarations.style'); 70 71 test(() => { 72 let s = new CSSStyleSheet(); 73 s.replaceSync(` 74 .a { 75 @media (width > 100px) { 76 --x:1; 77 --y:1; 78 .b { } 79 --z:1; 80 } 81 --w:1; 82 } 83 `); 84 assert_equals(s.cssRules.length, 1); 85 let outer = s.cssRules[0]; 86 assert_equals(outer.cssRules.length, 2); 87 88 // @media 89 let media = outer.cssRules[0]; 90 assert_equals(media.cssRules.length, 3); 91 assert_true(media.cssRules[0] instanceof CSSNestedDeclarations); 92 assert_equals(media.cssRules[0].cssText, `--x: 1; --y: 1;`); 93 assert_equals(media.cssRules[1].cssText, `& .b { }`); 94 assert_true(media.cssRules[2] instanceof CSSNestedDeclarations); 95 assert_equals(media.cssRules[2].cssText, `--z: 1;`); 96 97 assert_true(outer.cssRules[1] instanceof CSSNestedDeclarations); 98 assert_equals(outer.cssRules[1].cssText, `--w: 1;`); 99 }, 'Nested group rule'); 100 101 test(() => { 102 let s = new CSSStyleSheet(); 103 s.replaceSync(` 104 .a { 105 @scope (.foo) { 106 --x:1; 107 --y:1; 108 .b { } 109 --z:1; 110 } 111 --w:1; 112 } 113 `); 114 assert_equals(s.cssRules.length, 1); 115 let outer = s.cssRules[0]; 116 if (window.CSSScopeRule) { 117 assert_equals(outer.cssRules.length, 2); 118 119 // @scope 120 let scope = outer.cssRules[0]; 121 assert_true(scope instanceof CSSScopeRule); 122 assert_equals(scope.cssRules.length, 3); 123 assert_true(scope.cssRules[0] instanceof CSSNestedDeclarations); 124 assert_equals(scope.cssRules[0].cssText, `--x: 1; --y: 1;`); 125 assert_equals(scope.cssRules[1].cssText, `.b { }`); // Implicit :scope here. 126 assert_true(scope.cssRules[2] instanceof CSSNestedDeclarations); 127 assert_equals(scope.cssRules[2].cssText, `--z: 1;`); 128 129 assert_true(outer.cssRules[1] instanceof CSSNestedDeclarations); 130 assert_equals(outer.cssRules[1].cssText, `--w: 1;`); 131 } else { 132 assert_equals(outer.cssRules.length, 0); 133 } 134 }, 'Nested @scope rule'); 135 136 test(() => { 137 let s = new CSSStyleSheet(); 138 s.replaceSync(` 139 a { 140 & { --x:1; } 141 width: 100px; 142 height: 200px; 143 color:hover {} 144 --y: 2; 145 } 146 `); 147 assert_equals(s.cssRules.length, 1); 148 let outer = s.cssRules[0]; 149 assert_equals(outer.cssRules.length, 4); 150 assert_equals(outer.cssRules[0].cssText, `& { --x: 1; }`); 151 assert_equals(outer.cssRules[1].cssText, `width: 100px; height: 200px;`); 152 assert_equals(outer.cssRules[2].cssText, `& color:hover { }`); 153 assert_equals(outer.cssRules[3].cssText, `--y: 2;`); 154 }, 'Inner rule starting with an ident'); 155 156 test(() => { 157 let s = new CSSStyleSheet(); 158 s.replaceSync('.a {}'); 159 assert_equals(s.cssRules.length, 1); 160 let a_rule = s.cssRules[0]; 161 assert_equals(a_rule.cssRules.length, 0); 162 a_rule.insertRule(` 163 width: 100px; 164 height: 200px; 165 `); 166 assert_equals(a_rule.cssRules.length, 1); 167 assert_true(a_rule.cssRules[0] instanceof CSSNestedDeclarations); 168 assert_equals(a_rule.cssRules[0].cssText, `width: 100px; height: 200px;`); 169 }, 'Inserting a CSSNestedDeclaration rule into style rule'); 170 171 test(() => { 172 let s = new CSSStyleSheet(); 173 s.replaceSync('.a { @media (width > 100px) {} }'); 174 assert_equals(s.cssRules.length, 1); 175 assert_equals(s.cssRules[0].cssRules.length, 1); 176 let media_rule = s.cssRules[0].cssRules[0]; 177 assert_true(media_rule instanceof CSSMediaRule); 178 assert_equals(media_rule.cssRules.length, 0); 179 media_rule.insertRule(` 180 width: 100px; 181 height: 200px; 182 `); 183 assert_equals(media_rule.cssRules.length, 1); 184 assert_true(media_rule.cssRules[0] instanceof CSSNestedDeclarations); 185 assert_equals(media_rule.cssRules[0].cssText, `width: 100px; height: 200px;`); 186 }, 'Inserting a CSSNestedDeclaration rule into nested group rule'); 187 188 test(() => { 189 let s = new CSSStyleSheet(); 190 s.replaceSync('@media (width > 100px) {}'); 191 assert_equals(s.cssRules.length, 1); 192 let media_rule = s.cssRules[0]; 193 assert_true(media_rule instanceof CSSMediaRule); 194 assert_equals(media_rule.cssRules.length, 0); 195 assert_throws_dom('SyntaxError', () => { 196 media_rule.insertRule(` 197 width: 100px; 198 height: 200px; 199 `); 200 }); 201 }, 'Attempting to insert a CSSNestedDeclaration rule into top-level @media rule'); 202 203 test(() => { 204 let sheet = new CSSStyleSheet(); 205 assert_throws_dom('SyntaxError', () => { 206 sheet.insertRule(` 207 width: 100px; 208 height: 200px; 209 `); 210 }); 211 }, 'Attempting to insert a CSSNestedDeclaration rule into a stylesheet'); 212 213 test(() => { 214 let s = new CSSStyleSheet(); 215 s.replaceSync('.a {}'); 216 assert_equals(s.cssRules.length, 1); 217 let a_rule = s.cssRules[0]; 218 assert_equals(a_rule.cssRules.length, 0); 219 assert_throws_dom('SyntaxError', () => { 220 a_rule.insertRule(''); 221 }); 222 }, 'Attempting to insert a CSSNestedDeclaration rule, empty block'); 223 224 test(() => { 225 let s = new CSSStyleSheet(); 226 s.replaceSync('.a {}'); 227 assert_equals(s.cssRules.length, 1); 228 let a_rule = s.cssRules[0]; 229 assert_equals(a_rule.cssRules.length, 0); 230 assert_throws_dom('SyntaxError', () => { 231 a_rule.insertRule(` 232 xwidth: 100px; 233 xheight: 200px; 234 `); 235 }); 236 }, 'Attempting to insert a CSSNestedDeclaration rule, all invalid declarations'); 237 </script>