| <!DOCTYPE html> | |
| <meta charset="utf-8"> | |
| <title>CSS Pseudo Test: CSSPseudoElement for ::scroll-button()</title> | |
| <link rel="help" href="https://drafts.csswg.org/css-pseudo-4/#CSSPseudoElement-interface"> | |
| <link rel="help" href="https://drafts.csswg.org/css-overflow-5/#scroll-buttons"> | |
| <script src="/resources/testharness.js"></script> | |
| <script src="/resources/testharnessreport.js"></script> | |
| <style> | |
| #scroller { | |
| width: 100px; | |
| height: 100px; | |
| overflow: auto; | |
| } | |
| #scroller::scroll-button(*) { | |
| content: ""; | |
| display: inline-block; | |
| height: 10px; | |
| padding: 0; | |
| border: none; | |
| } | |
| /* Each scroll button has its own width, to tell them apart. */ | |
| #scroller::scroll-button(block-start) { width: 10px; } | |
| #scroller::scroll-button(inline-start) { width: 20px; } | |
| #scroller::scroll-button(inline-end) { width: 30px; } | |
| #scroller::scroll-button(block-end) { width: 40px; } | |
| </style> | |
| <div id="scroller"> | |
| <div style="width: 500px; height: 500px"></div> | |
| </div> | |
| <script> | |
| function scrollButton(direction) { | |
| const pseudo = scroller.pseudo(`::scroll-button(${direction})`); | |
| assert_true(pseudo instanceof CSSPseudoElement, | |
| `::scroll-button(${direction}) is a CSSPseudoElement`); | |
| return pseudo; | |
| } | |
| function width(pseudo) { | |
| return pseudo.getBoxQuads()[0].getBounds().width; | |
| } | |
| test(() => { | |
| const button = scrollButton("block-start"); | |
| assert_equals(button.type, "::scroll-button"); | |
| assert_equals(button.element, scroller); | |
| assert_equals(button.parent, scroller); | |
| }, "pseudo() returns a CSSPseudoElement for ::scroll-button()"); | |
| test(() => { | |
| assert_equals(width(scrollButton("block-start")), 10, "block-start"); | |
| assert_equals(width(scrollButton("inline-start")), 20, "inline-start"); | |
| assert_equals(width(scrollButton("inline-end")), 30, "inline-end"); | |
| assert_equals(width(scrollButton("block-end")), 40, "block-end"); | |
| }, "Each direction refers to its own scroll button"); | |
| test(() => { | |
| assert_equals(scrollButton("up"), scrollButton("block-start"), "up"); | |
| assert_equals(scrollButton("right"), scrollButton("inline-end"), "right"); | |
| }, "A physical direction returns the CSSPseudoElement of the logical direction it maps to"); | |
| test(t => { | |
| t.add_cleanup(() => { scroller.style.writingMode = ""; }); | |
| scroller.style.writingMode = "vertical-rl"; | |
| assert_equals(scrollButton("up"), scrollButton("inline-start")); | |
| }, "Physical directions map according to the writing mode"); | |
| test(() => { | |
| assert_equals(scrollButton("BLOCK-START"), scrollButton("block-start"), | |
| "BLOCK-START"); | |
| assert_equals(scrollButton("UP"), scrollButton("block-start"), "UP"); | |
| }, "The direction is ASCII case-insensitive"); | |
| const logicalDirections = | |
| ["block-start", "inline-start", "inline-end", "block-end"]; | |
| test(() => { | |
| for (const direction of logicalDirections) { | |
| assert_equals(scrollButton(direction).selectorText, | |
| `::scroll-button(${direction})`, direction); | |
| } | |
| assert_equals(scrollButton("INLINE-END").selectorText, | |
| "::scroll-button(inline-end)", "INLINE-END"); | |
| }, "selectorText of ::scroll-button() includes the logical direction"); | |
| // Physical directions return the CSSPseudoElement of the logical direction | |
| // they map to, so that's what selectorText reflects. | |
| test(() => { | |
| const expected = { | |
| up: "block-start", | |
| left: "inline-start", | |
| right: "inline-end", | |
| down: "block-end", | |
| }; | |
| for (const [physical, logical] of Object.entries(expected)) { | |
| assert_equals(scrollButton(physical).selectorText, | |
| `::scroll-button(${logical})`, physical); | |
| } | |
| assert_equals(scrollButton("UP").selectorText, | |
| "::scroll-button(block-start)", "UP"); | |
| }, "selectorText of ::scroll-button() with a physical direction is the logical direction it maps to"); | |
| test(t => { | |
| t.add_cleanup(() => { scroller.style.writingMode = ""; }); | |
| scroller.style.writingMode = "vertical-rl"; | |
| const expected = { | |
| up: "inline-start", | |
| left: "block-end", | |
| right: "block-start", | |
| down: "inline-end", | |
| }; | |
| for (const [physical, logical] of Object.entries(expected)) { | |
| assert_equals(scrollButton(physical).selectorText, | |
| `::scroll-button(${logical})`, physical); | |
| } | |
| }, "selectorText of ::scroll-button() with a physical direction depends on the writing mode"); | |
| test(t => { | |
| t.add_cleanup(() => { scroller.style.direction = ""; }); | |
| scroller.style.direction = "rtl"; | |
| assert_equals(scrollButton("left").selectorText, | |
| "::scroll-button(inline-end)", "left"); | |
| assert_equals(scrollButton("right").selectorText, | |
| "::scroll-button(inline-start)", "right"); | |
| }, "selectorText of ::scroll-button() with a physical direction depends on the direction"); | |
| test(() => { | |
| assert_equals(scroller.pseudo("::scroll-button(*)"), null); | |
| }, "pseudo() returns null for ::scroll-button(*)"); | |
| test(() => { | |
| const before = scroller.pseudo("::before"); | |
| assert_equals(before.pseudo("::scroll-button(block-start)"), null); | |
| }, "Pseudo-elements don't have scroll buttons"); | |
| test(() => { | |
| const div = document.createElement("div"); | |
| assert_true(div.pseudo("::scroll-button(up)") instanceof CSSPseudoElement); | |
| }, "pseudo() returns a CSSPseudoElement for ::scroll-button() of a disconnected element"); | |
| </script> |