parsing.html (3184B)
1 <!doctype html> 2 <title>CSS Selectors parsing</title> 3 <link rel="author" title="Adam Argyle" href="mailto:argyle@google.com"> 4 <link rel="author" title="Tab Atkins-Bittner" href="https://tabatkins.com/contact/"> 5 <link rel="help" href="https://drafts.csswg.org/css-nesting-1/"> 6 <script src="/resources/testharness.js"></script> 7 <script src="/resources/testharnessreport.js"></script> 8 9 <style id="test-sheet"></style> 10 <script> 11 let [ss] = document.styleSheets 12 13 function resetStylesheet() { 14 while (ss.rules.length) 15 ss.removeRule(0) 16 } 17 18 function testNestedSelector(sel, {expected=sel, parent=".foo"}={}) { 19 resetStylesheet(); 20 const ruleText = `${parent} { ${sel} { color: green; }}` 21 test(()=>{ 22 ss.insertRule(ruleText); 23 assert_equals(ss.rules.length, 1, "Outer rule should exist."); 24 const rule = ss.rules[0]; 25 assert_equals(rule.cssRules.length, 1, "Inner rule should exist."); 26 const innerRule = rule.cssRules[0]; 27 assert_equals(innerRule.selectorText, expected, `Inner rule's selector should be "${expected}".`); 28 }, ruleText); 29 } 30 31 function testInvalidNestingSelector(sel, {parent=".foo"}={}) { 32 resetStylesheet(); 33 const ruleText = `${parent} { ${sel} { color: green; }}` 34 test(()=>{ 35 ss.insertRule(ruleText); 36 assert_equals(ss.rules.length, 1, "Outer rule should exist."); 37 const rule = ss.rules[0]; 38 assert_equals(rule.cssRules.length, 0, "Inner rule should not exist."); 39 }, "INVALID: " + ruleText); 40 } 41 42 // basic usage 43 testNestedSelector("&"); 44 testNestedSelector("&.bar"); 45 testNestedSelector("& .bar"); 46 testNestedSelector("& > .bar"); 47 48 // relative selector 49 testNestedSelector("> .bar", {expected:"& > .bar"}); 50 testNestedSelector("> & .bar", {expected:"& > & .bar"}); 51 testNestedSelector("+ .bar &", {expected:"& + .bar &"}); 52 testNestedSelector("+ .bar, .foo, > .baz", {expected:"& + .bar, & .foo, & > .baz"}); 53 54 // implicit relative (and not) 55 testNestedSelector(".foo", {expected:"& .foo"}); 56 testNestedSelector(".test > & .bar"); 57 testNestedSelector(".foo, .foo &", {expected:"& .foo, .foo &"}); 58 testNestedSelector(".foo, .bar", {expected:"& .foo, & .bar"}); 59 testNestedSelector(":is(.bar, .baz)", {expected:"& :is(.bar, .baz)"}); 60 testNestedSelector("&:is(.bar, .baz)"); 61 testNestedSelector(":is(.bar, &.baz)"); 62 testNestedSelector("&:is(.bar, &.baz)"); 63 64 // Mixing nesting selector with other simple selectors 65 testNestedSelector("div&"); 66 testInvalidNestingSelector("&div"); // type selector must be first 67 testNestedSelector(".class&"); 68 testNestedSelector("&.class"); 69 testNestedSelector("[attr]&"); 70 testNestedSelector("&[attr]"); 71 testNestedSelector("#id&"); 72 testNestedSelector("&#id"); 73 testNestedSelector(":hover&"); 74 testNestedSelector("&:hover"); 75 testNestedSelector(":is(div)&"); 76 testNestedSelector("&:is(div)"); 77 78 // Multiple nesting selectors 79 testNestedSelector("& .bar & .baz & .qux"); 80 testNestedSelector("&&"); 81 82 // Selector list in inner rule 83 testNestedSelector("& > section, & > article"); 84 85 // Selector list in both inner and outer rule. 86 testNestedSelector("& + .baz, &.qux", {parent:".foo, .bar"}); 87 </script>