css-style-attr-decl-block.html (6863B)
1 <!DOCTYPE html> 2 <meta charset="UTF-8"> 3 <link rel="author" title="Xidorn Quan" href="mailto:me@upsuper.org"> 4 <link rel="help" href="https://drafts.csswg.org/cssom-1/#css-declaration-blocks"> 5 <script src="/resources/testharness.js"></script> 6 <script src="/resources/testharnessreport.js"></script> 7 <body> 8 <script> 9 function createTestElement(style) { 10 let wrapper = document.createElement("div"); 11 wrapper.innerHTML = `<div id="test" style="${style}"></div>`; 12 return wrapper.querySelector("#test"); 13 } 14 15 test(function() { 16 let elem = createTestElement("z-index: 10;"); 17 assert_equals(elem.style.cssText, "z-index: 10;"); 18 }, "Style attribute should create CSS declaration block based on its content"); 19 20 test(function() { 21 let elem = createTestElement("z-index: 20;"); 22 let style = elem.style; 23 assert_equals(style.cssText, "z-index: 20;"); 24 function assert_css_text(value, action) { 25 assert_equals(style.cssText, value, "CSS declaration block after " + action); 26 } 27 elem.setAttribute("style", "z-index: 21;"); 28 assert_css_text("z-index: 21;", "changing the style attribute"); 29 elem.removeAttribute("style"); 30 assert_css_text("", "removing the style attribute"); 31 elem.setAttribute("style", "position: absolute;"); 32 assert_css_text("position: absolute;", "adding style attribute again"); 33 }, "Changes to style attribute should reflect on CSS declaration block"); 34 35 test(function() { 36 let elem = createTestElement("z-index: 30;"); 37 let style = elem.style; 38 assert_equals(style.cssText, "z-index: 30;"); 39 function assert_attr(value, action) { 40 assert_equals(elem.getAttribute("style"), value, "style attribute after " + action); 41 } 42 style.setProperty("z-index", "31"); 43 assert_attr("z-index: 31;", "changing property in CSS declaration block"); 44 style.removeProperty("z-index"); 45 assert_attr("", "removing property from CSS declaration block"); 46 style.setProperty("position", "absolute"); 47 assert_attr("position: absolute;", "adding property to CSS declaration block"); 48 style.cssText = "z-index: 32;"; 49 assert_attr("z-index: 32;", "changing cssText"); 50 style.cssText = "z-index: 33; invalid"; 51 assert_attr("z-index: 33;", "changing cssText to a partial invalid value"); 52 }, "Changes to CSS declaration block should reflect on style attribute"); 53 54 test(function() { 55 let elem = createTestElement("z-index: 40;"); 56 let style = elem.style; 57 assert_equals(style.cssText, "z-index: 40;"); 58 // Create an observer for the element. 59 let observer = new MutationObserver(function() {}); 60 observer.observe(elem, {attributes: true, attributeOldValue: true}); 61 function assert_record_with_old_value(oldValue, action) { 62 let records = observer.takeRecords(); 63 assert_equals(records.length, 1, "number of mutation records after " + action); 64 let record = records[0]; 65 assert_equals(record.type, "attributes", "mutation type after " + action); 66 assert_equals(record.attributeName, "style", "mutated attribute after " + action); 67 assert_equals(record.oldValue, oldValue, "old value after " + action); 68 } 69 style.setProperty("z-index", "41"); 70 assert_record_with_old_value("z-index: 40;", "changing property in CSS declaration block"); 71 style.cssText = "z-index: 42;"; 72 assert_record_with_old_value("z-index: 41;", "changing cssText"); 73 style.cssText = "z-index: 42;"; 74 assert_record_with_old_value("z-index: 42;", "changing cssText with the same content"); 75 style.removeProperty("z-index"); 76 assert_record_with_old_value("z-index: 42;", "removing property from CSS declaration block"); 77 // Mutation to shorthand properties should also trigger only one mutation record. 78 style.setProperty("margin", "1px"); 79 assert_record_with_old_value("", "adding shorthand property to CSS declaration block"); 80 style.removeProperty("margin"); 81 assert_record_with_old_value("margin: 1px;", "removing shorthand property from CSS declaration block"); 82 // Final sanity check. 83 assert_equals(elem.getAttribute("style"), ""); 84 }, "Changes to CSS declaration block should queue mutation record for style attribute"); 85 86 test(function() { 87 let elem = createTestElement("z-index: 50; invalid"); 88 let style = elem.style; 89 assert_equals(style.cssText, "z-index: 50;"); 90 // Create an observer for the element. 91 let observer = new MutationObserver(function() {}); 92 observer.observe(elem, {attributes: true}); 93 function assert_no_record(action) { 94 let records = observer.takeRecords(); 95 assert_equals(records.length, 0, "expect no record after " + action); 96 } 97 style.setProperty("z-index", "invalid"); 98 assert_no_record("setting invalid value to property"); 99 // Longhand property. 100 style.removeProperty("position"); 101 assert_no_record("removing non-existing longhand property"); 102 style.setProperty("position", ""); 103 assert_no_record("setting empty string to non-existing longhand property"); 104 // Shorthand property. 105 style.removeProperty("margin"); 106 assert_no_record("removing non-existing shorthand property"); 107 style.setProperty("margin", ""); 108 assert_no_record("setting empty string to non-existing shorthand property"); 109 // Check that the value really isn't changed. 110 assert_equals(elem.getAttribute("style"), "z-index: 50; invalid", 111 "style attribute after removing non-existing properties"); 112 }, "Removing non-existing property or setting invalid value on CSS declaration block shouldn't queue mutation record"); 113 114 test(function() { 115 let elem = createTestElement("background-image: url(./);"); 116 let style = elem.style; 117 let base = document.createElement("base"); 118 base.href = "/"; 119 document.body.appendChild(elem); 120 let originalComputedValue = getComputedStyle(elem).backgroundImage; 121 document.head.appendChild(base); 122 this.add_cleanup(() => { 123 document.head.removeChild(base); 124 document.body.removeChild(elem); 125 }); 126 style.setProperty("background-color", "green"); 127 assert_equals(getComputedStyle(elem).backgroundImage, originalComputedValue, 128 "getComputedStyle(elem).backgroundImage after setting background-color"); 129 style.setProperty("background-image", "url(./)"); 130 assert_not_equals(getComputedStyle(elem).backgroundImage, originalComputedValue, 131 "getComputedStyle(elem).backgroundImage after setting background-image"); 132 }, "Changes to CSS declaration block after a base URL change"); 133 134 test(function() { 135 let e1 = document.createElement('div'); 136 let e2 = document.createElement('div'); 137 document.body.append(e1, e2); 138 this.add_cleanup(() => { 139 e1.remove(); 140 e2.remove(); 141 }); 142 e1.style.cssText = "all:revert;border-bottom-left-radius:1px;"; 143 e2.style.cssText = "all:unset;border-bottom-left-radius:1px;"; 144 let processed = e1.style.cssText.split(';') 145 .map(x => x.replace(/revert$/, 'unset')).join(';'); 146 assert_equals(processed, e2.style.cssText); 147 }, "Expansion of all:unset and all:revert treated identically"); 148 </script>