tor-browser

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

getComputedStyle-pseudo.html (10458B)


      1 <!doctype html>
      2 <meta charset="utf-8">
      3 <title>CSSOM: Correct resolution of resolved value for display-affected pseudo-elements</title>
      4 <link rel="help" href="https://drafts.csswg.org/cssom/#dom-window-getcomputedstyle">
      5 <link rel="help" href="https://drafts.csswg.org/cssom/#resolved-values">
      6 <link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
      7 <link rel="author" title="Karl Dubost" href="https://github.com/karlcow">
      8 <script src=/resources/testharness.js></script>
      9 <script src=/resources/testharnessreport.js></script>
     10 <style>
     11 #test { width: 100px; }
     12 
     13 #contents {
     14  display: contents;
     15  border: 10px solid red;
     16 }
     17 
     18 #test::before,
     19 #test::after,
     20 #contents::before,
     21 #contents::after,
     22 #flex::before,
     23 #flex::after {
     24  content: " ";
     25  width: 50%;
     26  height: 10px;
     27  display: block;
     28 }
     29 #none {
     30  display: none;
     31 }
     32 #none::before,
     33 #none::after {
     34  content: "Foo";
     35 }
     36 #flex {
     37  display: flex;
     38 }
     39 #flex-no-pseudo {
     40  display: flex;
     41 }
     42 #contents-pseudos::before,
     43 #contents-pseudos::after {
     44  display: contents;
     45  content: "foo";
     46  position: absolute;
     47 }
     48 #contents-pseudos-dynamic::before,
     49 #contents-pseudos-dynamic::after {
     50  display: block;
     51  content: "foo";
     52  position: absolute;
     53 }
     54 #contents-pseudos-dynamic.contents::before,
     55 #contents-pseudos-dynamic.contents::after {
     56  display: contents;
     57 }
     58 #pseudo-invalid::backdrop {
     59  color: rgb(0, 128, 0);
     60 }
     61 #pseudo-invalid::file-selector-button {
     62  color: rgb(0, 128, 0);
     63 }
     64 #pseudo-invalid::grammar-error {
     65  color: rgb(0, 128, 0);
     66 }
     67 #pseudo-invalid::highlight(name) {
     68  color: rgb(0, 128, 0);
     69 }
     70 #pseudo-invalid::marker {
     71  color: rgb(0, 128, 0);
     72 }
     73 #pseudo-invalid::placeholder {
     74  color: rgb(0, 128, 0);
     75 }
     76 #pseudo-invalid::spelling-error {
     77  color: rgb(0, 128, 0);
     78 }
     79 #pseudo-invalid::view-transition {
     80  color: rgb(0, 128, 0);
     81 }
     82 #pseudo-invalid::view-transition-image-pair(name) {
     83  color: rgb(0, 128, 0);
     84 }
     85 #pseudo-invalid::view-transition-group(name) {
     86  color: rgb(0, 128, 0);
     87 }
     88 #pseudo-invalid::view-transition-old(name) {
     89  color: rgb(0, 128, 0);
     90 }
     91 #pseudo-invalid::view-transition-new(name) {
     92  color: rgb(0, 128, 0);
     93 }
     94 #pseudo-invalid {
     95  color: rgb(255, 0, 0)
     96 }
     97 </style>
     98 <div id="test">
     99  <div id="contents"></div>
    100  <div id="none"></div>
    101  <div id="flex"></div>
    102  <div id="flex-no-pseudo"></div>
    103  <div id="contents-pseudos"></div>
    104  <div id="contents-pseudos-dynamic"></div>
    105  <ul><li id="pseudo-invalid">Item</li></ul>
    106 </div>
    107 <script>
    108 test(() => {
    109  const div = document.getElementById('test');
    110  ["before", "after"].forEach(pseudo => {
    111    assert_equals(getComputedStyle(div, pseudo).width, "100px");
    112  });
    113 }, "Resolution of width is correct when pseudo-element argument is ignored (due to no colon)");
    114 
    115 test(() => {
    116  const div = document.getElementById('test');
    117  [
    118    ":before ",
    119    "::before ",
    120    "::before\t",
    121    "::before\f",
    122    "::before\n",
    123    "::before,",
    124    "::before,::after",
    125    "::before@after",
    126    "::before#after",
    127    "::\"before\"",
    128    "::before\u0000",
    129    "::before-->",
    130    "::before0",
    131  ].forEach(pseudo => {
    132    assert_equals(getComputedStyle(div, pseudo).width, "", pseudo);
    133  });
    134 }, "Resolution of width is correct when pseudo-element argument is invalid (due to a trailing token)");
    135 
    136 test(() => {
    137  const div = document.getElementById('test');
    138  [":before", ":after"].forEach(pseudo => {
    139    assert_equals(getComputedStyle(div, pseudo).width, "50px");
    140  });
    141 }, "Resolution of width is correct for ::before and ::after pseudo-elements (single-colon)");
    142 
    143 test(() => {
    144  const div = document.getElementById('test');
    145  ["::before", "::after"].forEach(pseudo => {
    146    assert_equals(getComputedStyle(div, pseudo).width, "50px");
    147  });
    148 }, "Resolution of width is correct for ::before and ::after pseudo-elements (double-colon)");
    149 
    150 test(function() {
    151  const div = document.getElementById('test');
    152  [":bef\\oRE", "::\\000041fter"].forEach(pseudo => {
    153    assert_equals(getComputedStyle(div, pseudo).width, "50px");
    154  });
    155 }, "Pseudo-elements can use the full range of CSS syntax");
    156 
    157 test(function() {
    158  var contents = document.getElementById('contents');
    159  [":before", ":after"].forEach(function(pseudo) {
    160    assert_equals(getComputedStyle(contents, pseudo).width, "50px");
    161  });
    162 }, "Resolution of width is correct for ::before and ::after pseudo-elements of display: contents elements");
    163 
    164 test(function() {
    165  var has_no_pseudos = document.body;
    166  has_no_pseudos.style.position = "relative";
    167  [":before", ":after"].forEach(function(pseudo) {
    168    assert_equals(getComputedStyle(has_no_pseudos, pseudo).position, "static",
    169                  "Nonexistent " + pseudo + " pseudo-element shouldn't claim to have " +
    170                  "the same style as the originating element");
    171    assert_equals(getComputedStyle(has_no_pseudos, pseudo).width, "auto",
    172                  "Nonexistent " + pseudo + " pseudo-element shouldn't claim to have " +
    173                  "definite size");
    174  });
    175 }, "Resolution of nonexistent pseudo-element styles");
    176 
    177 test(function() {
    178  var none = document.getElementById('none');
    179  [":before", ":after"].forEach(function(pseudo) {
    180    assert_equals(getComputedStyle(none, pseudo).content, "\"Foo\"",
    181                  "Pseudo-styles of display: none elements should be correct");
    182  });
    183 }, "Resolution of pseudo-element styles in display: none elements");
    184 
    185 test(function() {
    186  var flex = document.getElementById('flex');
    187  [":before", ":after"].forEach(function(pseudo) {
    188    assert_equals(getComputedStyle(flex, pseudo).display, "block",
    189                  "Pseudo-styles of display: flex elements should get blockified");
    190  });
    191 }, "Item-based blockification of pseudo-elements");
    192 
    193 test(function() {
    194  var flexNoPseudo = document.getElementById('flex-no-pseudo');
    195  [":before", ":after"].forEach(function(pseudo) {
    196    assert_equals(getComputedStyle(flexNoPseudo, pseudo).display, "block",
    197                  "Pseudo-styles of display: flex elements should get blockified");
    198  });
    199 }, "Item-based blockification of nonexistent pseudo-elements");
    200 
    201 test(function() {
    202  var contentsPseudos = document.getElementById('contents-pseudos');
    203  [":before", ":after"].forEach(function(pseudo) {
    204    assert_equals(getComputedStyle(contentsPseudos, pseudo).display, "contents",
    205                  "display: contents in " + pseudo + " should get reflected on CSSOM");
    206    assert_equals(getComputedStyle(contentsPseudos, pseudo).width, "auto",
    207                  pseudo + " with display: contents should have no box");
    208    assert_equals(getComputedStyle(contentsPseudos, pseudo).position, "absolute",
    209                  "display: contents in " + pseudo + " should reflect other non-inherited properties in CSSOM");
    210  });
    211 }, "display: contents on pseudo-elements");
    212 
    213 test(function() {
    214  var contentsPseudosDynamic = document.getElementById('contents-pseudos-dynamic');
    215  [":before", ":after"].forEach(function(pseudo) {
    216    assert_equals(getComputedStyle(contentsPseudosDynamic, pseudo).display, "block",
    217                  "Check that display for " + pseudo + " is block before change");
    218  });
    219  contentsPseudosDynamic.className = "contents";
    220  [":before", ":after"].forEach(function(pseudo) {
    221    assert_equals(getComputedStyle(contentsPseudosDynamic, pseudo).display, "contents",
    222                  "display: contents in " + pseudo + " should get reflected on CSSOM");
    223    assert_equals(getComputedStyle(contentsPseudosDynamic, pseudo).width, "auto",
    224                  pseudo + " with display: contents should have no box");
    225    assert_equals(getComputedStyle(contentsPseudosDynamic, pseudo).position, "absolute",
    226                  "display: contents in " + pseudo + " should reflect other non-inherited properties in CSSOM");
    227  });
    228 }, "Dynamically change to display: contents on pseudo-elements");
    229 
    230 test(() => {
    231  const div = document.getElementById('test');
    232  // Note that these assertions deliberately avoid assert_[not_]equals to
    233  // avoid gCS().length in the failure output.
    234  assert_true(
    235    getComputedStyle(div, "totallynotapseudo").length != 0,
    236    "Should return the element's style for unknown pseudo-elements that don't start with a colon");
    237  assert_true(
    238    getComputedStyle(div, "::totallynotapseudo").length == 0,
    239    "Should return an empty style for unknown pseudo-elements starting with double-colon");
    240  assert_true(
    241    getComputedStyle(div, ":totallynotapseudo").length == 0,
    242    "Should return an empty style for unknown pseudo-elements starting with colon");
    243 }, "Unknown pseudo-elements");
    244 
    245 test(() => {
    246  const div = document.getElementById('test');
    247 
    248  const style1 = getComputedStyle(div, "totallynotapseudo");
    249  assert_throws_dom("NoModificationAllowedError", () => style1.color = "1");
    250  assert_throws_dom("NoModificationAllowedError", () => style1.margin = "10px");
    251 
    252  const style2 = getComputedStyle(div, "::totallynotapseudo");
    253  assert_throws_dom("NoModificationAllowedError", () => style2.color = "1");
    254  assert_throws_dom("NoModificationAllowedError", () => style2.margin = "10px");
    255 
    256  const style3 = getComputedStyle(div, ":totallynotapseudo");
    257  assert_throws_dom("NoModificationAllowedError", () => style3.color = "1");
    258  assert_throws_dom("NoModificationAllowedError", () => style3.margin = "10px");
    259 }, "CSSStyleDeclaration is immutable");
    260 
    261 // If you add a pseudo-element identifier here, don't forget to add the corresponding style rule in
    262 // <style> above.
    263 [
    264  "backdrop",
    265  "file-selector-button",
    266  "grammar-error",
    267  "highlight(name)",
    268  "marker",
    269  "placeholder",
    270  "spelling-error",
    271  "view-transition",
    272  "view-transition-image-pair(name)",
    273  "view-transition-group(name)",
    274  "view-transition-old(name)",
    275  "view-transition-new(name)"
    276 ].forEach(pseudoIdentifier => {
    277  test(() => {
    278    assert_implements_optional(CSS.supports(`selector(::${pseudoIdentifier})`), `::${pseudoIdentifier}`);
    279    const li = document.querySelector('li');
    280    assert_true(
    281      getComputedStyle(li, `:${pseudoIdentifier}`).length == 0,
    282      `Should return an empty style for :${pseudoIdentifier}`);
    283    assert_true(
    284      getComputedStyle(li, pseudoIdentifier).length != 0,
    285      `Should return the element style for ${pseudoIdentifier}`);
    286    assert_equals(
    287      getComputedStyle(li, pseudoIdentifier).color, "rgb(255, 0, 0)",
    288      `Should return the element style for ${pseudoIdentifier}`);
    289    assert_equals(
    290    getComputedStyle(li, `::${pseudoIdentifier}`).color, "rgb(0, 128, 0)",
    291    `Should return the ::${pseudoIdentifier} style`);
    292  }, `Unknown pseudo-element with a known identifier: ${pseudoIdentifier}`);
    293 });
    294 </script>