Commit fd94f87e authored by Stephen McGruer's avatar Stephen McGruer Committed by Commit Bot

Port nested sticky tests from reftests to JS tests

Bug: 699244
Change-Id: Ia85a44be9d9f7b0d0db382892520f2755523f514
Reviewed-on: https://chromium-review.googlesource.com/980236Reviewed-by: default avatarRobert Flack <flackr@chromium.org>
Commit-Queue: Stephen McGruer <smcgruer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#546172}
parent 4c97ba8c
...@@ -12,29 +12,29 @@ ...@@ -12,29 +12,29 @@
<script> <script>
test(() => { test(() => {
const elements = setupStickyTest('left', 50, true); const elements = setupStickyTest('left', 50);
elements.scroller.scrollLeft = 100; elements.scroller.scrollLeft = 100;
const nonStickyLeftY = elements.container.offsetLeft + const nonStickyLeftX = elements.container.offsetLeft +
elements.filler.clientWidth; elements.filler.clientWidth;
assert_equals(elements.sticky.offsetLeft, nonStickyLeftY); assert_equals(elements.sticky.offsetLeft, nonStickyLeftX);
}, 'before reaching the sticking point the sticky box should not be offset'); }, 'before reaching the sticking point the sticky box should not be offset');
test(() => { test(() => {
const elements = setupStickyTest('left', 50, true); const elements = setupStickyTest('left', 50);
elements.scroller.scrollLeft = 200; elements.scroller.scrollLeft = 200;
// This math actually cancels to sticky.offsetLeft == (scroller.scrollLeft + 50), // This math actually cancels to sticky.offsetLeft == (scroller.scrollLeft + 50),
// but for clarity the calculations are left explicit. // but for clarity the calculations are left explicit.
const nonStickyLeftY = elements.container.offsetLeft + const nonStickyLeftX = elements.container.offsetLeft +
elements.filler.clientWidth; elements.filler.clientWidth;
const targetLeftY = elements.scroller.scrollLeft + 50; const targetLeftX = elements.scroller.scrollLeft + 50;
const stickyOffset = targetLeftY - nonStickyLeftY; const stickyOffset = targetLeftX - nonStickyLeftX;
assert_equals(elements.sticky.offsetLeft, nonStickyLeftY + stickyOffset); assert_equals(elements.sticky.offsetLeft, nonStickyLeftX + stickyOffset);
}, 'after reaching the sticking point the sticky box should be offset'); }, 'after reaching the sticking point the sticky box should be offset');
test(() => { test(() => {
const elements = setupStickyTest('left', 50, true); const elements = setupStickyTest('left', 50);
elements.scroller.scrollLeft = 300; elements.scroller.scrollLeft = 300;
const maxOffsetInContainer = elements.container.offsetLeft + const maxOffsetInContainer = elements.container.offsetLeft +
elements.container.clientWidth - elements.sticky.clientWidth; elements.container.clientWidth - elements.sticky.clientWidth;
......
<!DOCTYPE html>
<title>Reference for nested bottom-constrained position:sticky elements should render correctly</title>
<style>
.group {
display: inline-block;
position: relative;
width: 150px;
height: 250px;
}
.scroller {
position: relative;
width: 100px;
height: 200px;
overflow-x: hidden;
overflow-y: auto;
}
.contents {
height: 500px;
}
.outerIndicator {
background-color: green;
position: absolute;
left: 0;
width: 100%;
height: 100px;
}
.innerIndicator {
background-color: blue;
position: absolute;
left: 0;
width: 100%;
height: 50px;
}
</style>
<script>
window.addEventListener('load', function() {
document.getElementById('scroller1').scrollTop = 75;
document.getElementById('scroller2').scrollTop = 175;
document.getElementById('scroller3').scrollTop = 250;
});
</script>
<div class="group">
<div id="scroller1" class="scroller">
<div class="contents">
<div class="outerIndicator" style="top: 200px;"></div>
<div class="innerIndicator" style="top: 200px;"></div>
</div>
</div>
</div>
<div class="group">
<div id="scroller2" class="scroller">
<div class="contents">
<div class="outerIndicator" style="top: 250px;"></div>
<div class="innerIndicator" style="top: 290px;"></div>
</div>
</div>
</div>
<div class="group">
<div id="scroller3" class="scroller">
<div class="contents">
<div class="outerIndicator" style="top: 300px;"></div>
<div class="innerIndicator" style="top: 350px;"></div>
</div>
</div>
</div>
<div>You should see three green and three blue boxes above. No red should be visible.</div>
<!DOCTYPE html> <!DOCTYPE html>
<title>Nested bottom-constrained position:sticky elements should render correctly</title> <title>Nested bottom-constrained position:sticky elements should render correctly</title>
<link rel="match" href="position-sticky-nested-bottom-ref.html" />
<link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos" /> <link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos" />
<meta name="assert" content="This test checks that nested position:sticky elements with a bottom constraint render correctly" /> <meta name="assert" content="This test checks that nested position:sticky elements with a bottom constraint render correctly" />
<style> <script src="/resources/testharness.js"></script>
.group { <script src="/resources/testharnessreport.js"></script>
display: inline-block;
position: relative;
width: 150px;
height: 250px;
}
.scroller {
position: relative;
width: 100px;
height: 200px;
overflow-x: hidden;
overflow-y: auto;
}
.contents {
height: 500px;
}
.prepadding {
height: 200px;
}
.container {
height: 200px;
}
.filler {
height: 100px;
}
.outerIndicator {
background-color: red;
position: absolute;
left: 0;
width: 100%;
height: 100px;
}
.innerIndicator { <script src="resources/sticky-util.js"></script>
background-color: red;
position: absolute;
left: 0;
width: 100%;
height: 50px;
}
.outerSticky { <body></body>
background-color: green;
position: sticky;
bottom: 25px;
width: 100%;
height: 100px;
}
.innerFiller {
height: 50px;
}
.innerSticky {
background-color: blue;
position: sticky;
bottom: 35px;
width: 100%;
height: 50px;
}
</style>
<script> <script>
window.addEventListener('load', function() { test(() => {
document.getElementById('scroller1').scrollTop = 75; const elements = setupNestedStickyTest('bottom', 25, 35);
document.getElementById('scroller2').scrollTop = 175; elements.scroller.scrollTop = 300;
document.getElementById('scroller3').scrollTop = 250; const nonStickyTopY = elements.container.offsetTop +
}); elements.filler.clientHeight;
assert_equals(elements.sticky.offsetTop, nonStickyTopY);
// The inner sticky should not be offset from the outer.
const nonStickyInnerTopY = elements.sticky.clientHeight -
elements.innerSticky.clientHeight;
assert_equals(elements.innerSticky.offsetTop, nonStickyInnerTopY);
}, 'before reaching the sticking point, neither sticky box should be offset');
test(() => {
const elements = setupNestedStickyTest('bottom', 25, 50);
elements.scroller.scrollTop = 150;
const nonStickyTopY = elements.container.offsetTop +
elements.filler.clientHeight;
assert_equals(elements.sticky.offsetTop, nonStickyTopY);
assert_equals(elements.innerSticky.offsetTop, 35);
}, 'the inner sticky can stick before the outer one if necessary');
test(() => {
const elements = setupNestedStickyTest('bottom', 25, 35);
elements.scroller.scrollTop = 100;
const nonStickyTopY = elements.container.offsetTop +
elements.filler.clientHeight;
const nonStickyBottomY = nonStickyTopY + elements.sticky.clientHeight;
const targetBottomY = elements.scroller.clientHeight +
elements.scroller.scrollTop - 25;
const stickyOffset = nonStickyBottomY - targetBottomY;
assert_equals(elements.sticky.offsetTop, nonStickyTopY - stickyOffset);
// The inner sticky has similar math, but its offsetTop is relative to the
// sticky element and in this test is (height - the difference between the
// top values).
assert_equals(elements.innerSticky.offsetTop, 40);
}, 'both sticky boxes can be stuck at the same time');
test(() => {
const elements = setupNestedStickyTest('bottom', 25, 35);
elements.scroller.scrollTop = 0;
assert_equals(elements.sticky.offsetTop, elements.container.offsetTop);
assert_equals(elements.innerSticky.offsetTop, 0);
}, 'neither sticky can escape their containing block');
test(() => {
const elements = setupNestedStickyTest('bottom', 25, 500);
elements.scroller.scrollTop = 200;
// It doesn't matter how big the inner sticky offset is, it cannot escape its
// containing block (the outer sticky).
assert_equals(elements.innerSticky.offsetTop, 0);
}, 'the inner sticky cannot be pushed outside the outer sticky');
</script> </script>
<div class="group">
<div id="scroller1" class="scroller">
<div class="outerIndicator" style="top: 200px;"></div>
<div class="contents">
<div class="prepadding"></div>
<div class="container">
<div class="filler"></div>
<div class="outerSticky">
<div class="innerIndicator" style="top: 0;"></div>
<div class="innerFiller"></div>
<div class="innerSticky"></div>
</div>
</div>
</div>
</div>
</div>
<div class="group">
<div id="scroller2" class="scroller">
<div class="outerIndicator" style="top: 250px;"></div>
<div class="contents">
<div class="prepadding"></div>
<div class="container">
<div class="filler"></div>
<div class="outerSticky">
<div class="innerIndicator" style="top: 40px;"></div>
<div class="innerFiller"></div>
<div class="innerSticky"></div>
</div>
</div>
</div>
</div>
</div>
<div class="group">
<div id="scroller3" class="scroller">
<div class="outerIndicator" style="top: 300px;"></div>
<div class="contents">
<div class="prepadding"></div>
<div class="container">
<div class="filler"></div>
<div class="outerSticky">
<div class="innerIndicator" style="top: 50px;"></div>
<div class="innerFiller"></div>
<div class="innerSticky"></div>
</div>
</div>
</div>
</div>
</div>
<div>You should see three green and three blue boxes above. No red should be visible.</div>
<!DOCTYPE html>
<title>Reference for nested left-constrained position:sticky elements should render correctly</title>
<style>
.group {
position: relative;
width: 250px;
height: 150px;
}
.scroller {
position: relative;
width: 200px;
height: 100px;
overflow-x: auto;
overflow-y: hidden;
}
.contents {
height: 100%;
width: 500px;
}
.outerIndicator {
background-color: green;
position: absolute;
top: 0;
height: 100%;
width: 100px;
}
.innerIndicator {
background-color: blue;
position: absolute;
top: 0;
height: 100%;
width: 50px;
}
</style>
<script>
window.addEventListener('load', function() {
document.getElementById('scroller1').scrollLeft = 50;
document.getElementById('scroller2').scrollLeft = 125;
document.getElementById('scroller3').scrollLeft = 225;
});
</script>
<div class="group">
<div id="scroller1" class="scroller">
<div class="contents">
<div class="outerIndicator" style="left: 150px;"></div>
<div class="innerIndicator" style="left: 150px;"></div>
</div>
</div>
</div>
<div class="group">
<div id="scroller2" class="scroller">
<div class="contents">
<div class="outerIndicator" style="left: 175px;"></div>
<div class="innerIndicator" style="left: 185px;"></div>
</div>
</div>
</div>
<div class="group">
<div id="scroller3" class="scroller">
<div class="contents">
<div class="outerIndicator" style="left: 200px;"></div>
<div class="innerIndicator" style="left: 250px;"></div>
</div>
</div>
</div>
<div>You should see three green and three blue boxes above. No red should be visible.</div>
<!DOCTYPE html> <!DOCTYPE html>
<title>Nested left-constrained position:sticky elements should render correctly</title> <title>Nested left-constrained position:sticky elements should render correctly</title>
<link rel="match" href="position-sticky-nested-left-ref.html" />
<link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos" /> <link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos" />
<meta name="assert" content="This test checks that nested position:sticky elements with a left constraint render correctly" /> <meta name="assert" content="This test checks that nested position:sticky elements with a left constraint render correctly" />
<style> <script src="/resources/testharness.js"></script>
.group { <script src="/resources/testharnessreport.js"></script>
position: relative;
width: 250px;
height: 150px;
}
.scroller {
position: relative;
width: 200px;
height: 100px;
overflow-x: auto;
overflow-y: hidden;
}
.contents {
height: 100%;
width: 500px;
/* Allow nice formatting of inline divs. Fonts are not used in this test. */
font-size: 0;
}
.prepadding {
display: inline-block;
height: 100%;
width: 100px;
}
.container {
display: inline-block;
height: 100%;
width: 200px;
}
.innerpadding {
display: inline-block;
height: 100%;
width: 50px;
}
.outerIndicator {
background-color: red;
position: absolute;
top: 0;
display: inline-block;
height: 100%;
width: 100px;
}
.innerIndicator { <script src="resources/sticky-util.js"></script>
background-color: red;
position: absolute;
top: 0;
display: inline-block;
height: 100%;
width: 50px;
}
.outerSticky { <body></body>
background-color: green;
position: sticky;
left: 50px;
display: inline-block;
height: 100%;
width: 100px;
}
.innerSticky {
background-color: blue;
position: sticky;
left: 60px;
display: inline-block;
height: 100%;
width: 50px;
}
</style>
<script> <script>
window.addEventListener('load', function() { test(() => {
document.getElementById('scroller1').scrollLeft = 50; const elements = setupNestedStickyTest('left', 50, 60);
document.getElementById('scroller2').scrollLeft = 125; elements.scroller.scrollLeft = 100;
document.getElementById('scroller3').scrollLeft = 225; const nonStickyLeftX = elements.container.offsetLeft +
}); elements.filler.clientWidth;
assert_equals(elements.sticky.offsetLeft, nonStickyLeftX);
// The inner sticky should not be offset from the outer.
assert_equals(elements.innerSticky.offsetLeft, 0);
}, 'before reaching the sticking point, neither sticky box should be offset');
test(() => {
const elements = setupNestedStickyTest('left', 50, 60);
elements.scroller.scrollLeft = 145;
const nonStickyLeftX = elements.container.offsetLeft +
elements.filler.clientWidth;
assert_equals(elements.sticky.offsetLeft, nonStickyLeftX);
assert_equals(elements.innerSticky.offsetLeft, 5);
}, 'the inner sticky can stick before the outer one if necessary');
test(() => {
const elements = setupNestedStickyTest('left', 50, 60);
elements.scroller.scrollLeft = 200;
// This math cancels to sticky.offsetLeft == (scroller.scrollLeft + 50), but
// for clarity the calculations are left explicit.
const nonStickyLeftX = elements.container.offsetLeft +
elements.filler.clientWidth;
const targetLeftX = elements.scroller.scrollLeft + 50;
const stickyOffset = targetLeftX - nonStickyLeftX;
assert_equals(elements.sticky.offsetLeft, nonStickyLeftX + stickyOffset);
// The inner sticky has similar math, but its offsetLeft is relative to the
// sticky element and in this test is the difference between the left values.
assert_equals(elements.innerSticky.offsetLeft, 10);
}, 'both sticky boxes can be stuck at the same time');
test(() => {
const elements = setupNestedStickyTest('left', 50, 60);
elements.scroller.scrollLeft = 300;
const maxOffsetInContainer = elements.container.offsetLeft +
elements.container.clientWidth - elements.sticky.clientWidth;
assert_equals(elements.sticky.offsetLeft, maxOffsetInContainer);
const maxOffsetInOuterSticky = elements.sticky.clientWidth -
elements.innerSticky.clientWidth;
assert_equals(elements.innerSticky.offsetLeft, maxOffsetInOuterSticky);
}, 'neither sticky can escape their containing block');
test(() => {
const elements = setupNestedStickyTest('left', 50, 300);
elements.scroller.scrollLeft = 100;
// The outer sticky has not stuck yet.
const nonStickyLeftX = elements.container.offsetLeft +
elements.filler.clientWidth;
assert_equals(elements.sticky.offsetLeft, nonStickyLeftX);
// But the inner sticky still cannot escape the outer sticky (as it is the
// containing block).
const maxOffsetInOuterSticky = elements.sticky.clientWidth -
elements.innerSticky.clientWidth;
assert_equals(elements.innerSticky.offsetLeft, maxOffsetInOuterSticky);
}, 'the inner sticky cannot be pushed outside the outer sticky');
</script> </script>
<div class="group">
<div id="scroller1" class="scroller">
<div class="outerIndicator" style="left: 150px;"></div>
<div class="contents">
<div class="prepadding"></div>
<div class="container">
<div class="innerpadding"></div>
<div class="outerSticky">
<div class="innerIndicator" style="left: 0;"></div>
<div class="innerSticky"></div>
</div>
</div>
</div>
</div>
</div>
<div class="group">
<div id="scroller2" class="scroller">
<div class="outerIndicator" style="left: 175px;"></div>
<div class="contents">
<div class="prepadding"></div>
<div class="container">
<div class="innerpadding">
</div><div class="outerSticky">
<div class="innerIndicator" style="left: 10px;"></div>
<div class="innerSticky"></div>
</div>
</div>
</div>
</div>
</div>
<div class="group">
<div id="scroller3" class="scroller">
<div class="outerIndicator" style="left: 200px;"></div>
<div class="contents">
<div class="prepadding"></div>
<div class="container">
<div class="innerpadding"></div>
<div class="outerSticky">
<div class="innerIndicator" style="left: 50px;"></div>
<div class="innerSticky"></div>
</div>
</div>
</div>
</div>
</div>
<div>You should see three green and three blue boxes above. No red should be visible.</div>
<!DOCTYPE html>
<title>Reference for position:sticky elements should respect the right constraint</title>
<style>
.group {
position: relative;
width: 250px;
height: 150px;
}
.scroller {
position: relative;
width: 200px;
height: 100px;
overflow-x: auto;
overflow-y: hidden;
}
.contents {
height: 100%;
width: 500px;
}
.outerIndicator {
background-color: green;
position: absolute;
top: 0;
height: 100%;
width: 100px;
}
.innerIndicator {
background-color: blue;
position: absolute;
top: 0;
height: 100%;
width: 50px;
}
</style>
<script>
window.addEventListener('load', function() {
document.getElementById('scroller1').scrollLeft = 75;
document.getElementById('scroller2').scrollLeft = 175;
document.getElementById('scroller3').scrollLeft = 250;
});
</script>
<div class="group">
<div id="scroller1" class="scroller">
<div class="contents">
<div class="outerIndicator" style="left: 200px;"></div>
<div class="innerIndicator" style="left: 200px;"></div>
</div>
</div>
</div>
<div class="group">
<div id="scroller2" class="scroller">
<div class="contents">
<div class="outerIndicator" style="left: 250px;"></div>
<div class="innerIndicator" style="left: 290px;"></div>
</div>
</div>
</div>
<div class="group">
<div id="scroller3" class="scroller">
<div class="contents">
<div class="outerIndicator" style="left: 300px;"></div>
<div class="innerIndicator" style="left: 350px;"></div>
</div>
</div>
</div>
<div>You should see three green and three blue boxes above. No red should be visible.</div>
<!DOCTYPE html> <!DOCTYPE html>
<title>Nested right-constrained position:sticky elements should render correctly</title> <title>Nested right-constrained position:sticky elements should render correctly</title>
<link rel="match" href="position-sticky-nested-right-ref.html" />
<link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos" /> <link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos" />
<meta name="assert" content="This test checks that nested position:sticky elements with a right constraint render correctly" /> <meta name="assert" content="This test checks that nested position:sticky elements with a right constraint render correctly" />
<style> <script src="/resources/testharness.js"></script>
.group { <script src="/resources/testharnessreport.js"></script>
position: relative;
width: 250px;
height: 150px;
}
.scroller {
position: relative;
width: 200px;
height: 100px;
overflow-x: auto;
overflow-y: hidden;
}
.contents {
height: 100%;
width: 500px;
/* Allow nice formatting of inline divs. Fonts are not used in this test. */
font-size: 0;
}
.prepadding {
display: inline-block;
height: 100%;
width: 200px;
}
.container {
display: inline-block;
height: 100%;
width: 200px;
}
.filler {
display: inline-block;
height: 100%;
width: 100px;
}
.outerIndicator {
background-color: red;
position: absolute;
top: 0;
display: inline-block;
height: 100%;
width: 100px;
}
.innerIndicator { <script src="resources/sticky-util.js"></script>
background-color: red;
position: absolute;
top: 0;
display: inline-block;
height: 100%;
width: 50px;
}
.outerSticky { <body></body>
background-color: green;
position: sticky;
right: 25px;
display: inline-block;
height: 100%;
width: 100px;
}
.innerFiller {
display: inline-block;
height: 100%;
width: 50px;
}
.innerSticky {
background-color: blue;
position: sticky;
right: 35px;
display: inline-block;
height: 100%;
width: 50px;
}
</style>
<script> <script>
window.addEventListener('load', function() { test(() => {
document.getElementById('scroller1').scrollLeft = 75; const elements = setupNestedStickyTest('right', 25, 35);
document.getElementById('scroller2').scrollLeft = 175; elements.scroller.scrollLeft = 200;
document.getElementById('scroller3').scrollLeft = 250; const nonStickyLeftX = elements.container.offsetLeft +
}); elements.filler.clientWidth;
</script> assert_equals(elements.sticky.offsetLeft, nonStickyLeftX);
// The inner sticky should not be offset from the outer.
<div class="group"> const nonStickyInnerLeftX = elements.sticky.clientWidth -
<div id="scroller1" class="scroller"> elements.innerSticky.clientWidth;
<div class="outerIndicator" style="left: 200px;"></div> assert_equals(elements.innerSticky.offsetLeft, nonStickyInnerLeftX);
<div class="contents"> }, 'before reaching the sticking point, neither sticky box should be offset');
<div class="prepadding"></div>
<div class="container"> test(() => {
<div class="filler"></div> const elements = setupNestedStickyTest('right', 25, 50);
<div class="outerSticky"> elements.scroller.scrollLeft = 150;
<div class="innerIndicator" style="left: 0;"></div> const nonStickyLeftX = elements.container.offsetLeft +
<div class="innerFiller"></div> elements.filler.clientWidth;
<div class="innerSticky"></div> assert_equals(elements.sticky.offsetLeft, nonStickyLeftX);
</div> assert_equals(elements.innerSticky.offsetLeft, 35);
</div> }, 'the inner sticky can stick before the outer one if necessary');
</div>
</div> test(() => {
</div> const elements = setupNestedStickyTest('right', 25, 35);
elements.scroller.scrollLeft = 100;
const nonStickyLeftX = elements.container.offsetLeft +
elements.filler.clientWidth;
const nonStickyBottomX = nonStickyLeftX + elements.sticky.clientWidth;
const targetBottomX = elements.scroller.clientWidth +
elements.scroller.scrollLeft - 25;
const stickyOffset = nonStickyBottomX - targetBottomX;
assert_equals(elements.sticky.offsetLeft, nonStickyLeftX - stickyOffset);
// The inner sticky has similar math, but its offsetLeft is relative to the
// sticky element and in this test is (height - the difference between the
// top values).
assert_equals(elements.innerSticky.offsetLeft, 40);
}, 'both sticky boxes can be stuck at the same time');
test(() => {
const elements = setupNestedStickyTest('right', 25, 35);
elements.scroller.scrollLeft = 0;
assert_equals(elements.sticky.offsetLeft, elements.container.offsetLeft);
assert_equals(elements.innerSticky.offsetLeft, 0);
}, 'neither sticky can escape their containing block');
test(() => {
const elements = setupNestedStickyTest('right', 25, 500);
elements.scroller.scrollLeft = 200;
// It doesn't matter how big the inner sticky offset is, it cannot escape its
// containing block (the outer sticky).
assert_equals(elements.innerSticky.offsetLeft, 0);
}, 'the inner sticky cannot be pushed outside the outer sticky');
<div class="group"> </script>
<div id="scroller2" class="scroller">
<div class="outerIndicator" style="left: 250px;"></div>
<div class="contents">
<div class="prepadding"></div>
<div class="container">
<div class="filler"></div>
<div class="outerSticky">
<div class="innerIndicator" style="left: 40px;"></div>
<div class="innerFiller"></div>
<div class="innerSticky"></div>
</div>
</div>
</div>
</div>
</div>
<div class="group">
<div id="scroller3" class="scroller">
<div class="outerIndicator" style="left: 300px;"></div>
<div class="contents">
<div class="prepadding"></div>
<div class="container">
<div class="filler"></div>
<div class="outerSticky">
<div class="innerIndicator" style="left: 50px;"></div>
<div class="innerFiller"></div>
<div class="innerSticky"></div>
</div>
</div>
</div>
</div>
</div>
<div>You should see three green and three blue boxes above. No red should be visible.</div>
<!DOCTYPE html>
<title>Reference for nested top-constrained position:sticky elements should render correctly</title>
<style>
.group {
display: inline-block;
position: relative;
width: 150px;
height: 250px;
}
.scroller {
position: relative;
width: 100px;
height: 200px;
overflow-x: hidden;
overflow-y: auto;
}
.contents {
height: 500px;
}
.green {
background-color: green;
}
.blue {
background-color: blue;
}
.indicator {
position: absolute;
left: 0;
}
.bigBox {
width: 100%;
height: 100px;
}
.smallBox {
width: 100%;
height: 50px;
}
</style>
<script>
window.addEventListener('load', function() {
document.getElementById('scroller1').scrollTop = 50;
document.getElementById('scroller2').scrollTop = 125;
document.getElementById('scroller3').scrollTop = 225;
});
</script>
<div class="group">
<div id="scroller1" class="scroller">
<div class="contents">
<div class="green indicator bigBox" style="top: 150px;"></div>
<div class="blue indicator smallBox" style="top: 150px;"></div>
</div>
</div>
</div>
<div class="group">
<div id="scroller2" class="scroller">
<div class="contents">
<div class="green indicator bigBox" style="top: 175px;"></div>
<div class="blue indicator smallBox" style="top: 185px;"></div>
</div>
</div>
</div>
<div class="group">
<div id="scroller3" class="scroller">
<div class="contents">
<div class="green indicator bigBox" style="top: 200px;"></div>
<div class="blue indicator smallBox" style="top: 250px;"></div>
</div>
</div>
</div>
<div>You should see three green and three blue boxes above. No red should be visible.</div>
<!DOCTYPE html> <!DOCTYPE html>
<title>Nested top-constrainted position:sticky elements should render correctly</title> <title>Nested top-constrainted position:sticky elements should render correctly</title>
<link rel="match" href="position-sticky-nested-top-ref.html" />
<link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos" /> <link rel="help" href="https://www.w3.org/TR/css-position-3/#sticky-pos" />
<meta name="assert" content="This test checks that nested position:sticky elements with a top constraint render correctly" /> <meta name="assert" content="This test checks that nested position:sticky elements with a top constraint render correctly" />
<style> <script src="/resources/testharness.js"></script>
.group { <script src="/resources/testharnessreport.js"></script>
display: inline-block;
position: relative;
width: 150px;
height: 250px;
}
.scroller { <script src="resources/sticky-util.js"></script>
position: relative;
width: 100px;
height: 200px;
overflow-x: hidden;
overflow-y: auto;
}
.contents { <body></body>
height: 500px;
}
.prepadding { <script>
height: 100px; test(() => {
} const elements = setupNestedStickyTest('top', 50, 60);
elements.scroller.scrollTop = 100;
.container { const nonStickyTopY = elements.container.offsetTop +
height: 200px; elements.filler.clientHeight;
} assert_equals(elements.sticky.offsetTop, nonStickyTopY);
// The inner sticky should not be offset from the outer.
assert_equals(elements.innerSticky.offsetTop, 0);
}, 'before reaching the sticking point, neither sticky box should be offset');
.innerpadding { test(() => {
height: 50px; const elements = setupNestedStickyTest('top', 50, 60);
} elements.scroller.scrollTop = 145;
const nonStickyTopY = elements.container.offsetTop +
elements.filler.clientHeight;
assert_equals(elements.sticky.offsetTop, nonStickyTopY);
assert_equals(elements.innerSticky.offsetTop, 5);
}, 'the inner sticky can stick before the outer one if necessary');
.outerIndicator { test(() => {
background-color: red; const elements = setupNestedStickyTest('top', 50, 60);
position: absolute; elements.scroller.scrollTop = 200;
left: 0;
height: 100px;
width: 100%;
}
.innerIndicator { // This math cancels to sticky.offsetTop == (scroller.scrollTop + 50), but
background-color: red; // for clarity the calculations are left explicit.
position: absolute; const nonStickyTopY = elements.container.offsetTop +
left: 0; elements.filler.clientHeight;
height: 50px; const targetTopY = elements.scroller.scrollTop + 50;
width: 100%; const stickyOffset = targetTopY - nonStickyTopY;
} assert_equals(elements.sticky.offsetTop, nonStickyTopY + stickyOffset);
.outerSticky { // The inner sticky has similar math, but its offsetTop is relative to the
background-color: green; // sticky element and in this test is the difference between the top values.
position: sticky; assert_equals(elements.innerSticky.offsetTop, 10);
top: 50px; }, 'both sticky boxes can be stuck at the same time');
width: 100%;
height: 100px;
}
.innerSticky { test(() => {
background-color: blue; const elements = setupNestedStickyTest('top', 50, 60);
position: sticky; elements.scroller.scrollTop = 300;
top: 60px; const maxOffsetInContainer = elements.container.offsetTop +
width: 100%; elements.container.clientHeight - elements.sticky.clientHeight;
height: 50px; assert_equals(elements.sticky.offsetTop, maxOffsetInContainer);
} const maxOffsetInOuterSticky = elements.sticky.clientHeight -
</style> elements.innerSticky.clientHeight;
assert_equals(elements.innerSticky.offsetTop, maxOffsetInOuterSticky);
}, 'neither sticky can escape their containing block');
<script> test(() => {
window.addEventListener('load', function() { const elements = setupNestedStickyTest('top', 50, 300);
document.getElementById('scroller1').scrollTop = 50; elements.scroller.scrollTop = 100;
document.getElementById('scroller2').scrollTop = 125; // The outer sticky has not stuck yet.
document.getElementById('scroller3').scrollTop = 225; const nonStickyTopY = elements.container.offsetTop +
}); elements.filler.clientHeight;
assert_equals(elements.sticky.offsetTop, nonStickyTopY);
// But the inner sticky still cannot escape the outer sticky (as it is the
// containing block).
const maxOffsetInOuterSticky = elements.sticky.clientHeight -
elements.innerSticky.clientHeight;
assert_equals(elements.innerSticky.offsetTop, maxOffsetInOuterSticky);
}, 'the inner sticky cannot be pushed outside the outer sticky');
</script> </script>
<div class="group">
<div id="scroller1" class="scroller">
<div class="outerIndicator" style="top: 150px;"></div>
<div class="contents">
<div class="prepadding"></div>
<div class="container">
<div class="innerpadding"></div>
<div class="outerSticky">
<div class="innerIndicator" style="top: 0;"></div>
<div class="innerSticky"></div>
</div>
</div>
</div>
</div>
</div>
<div class="group">
<div id="scroller2" class="scroller">
<div class="outerIndicator" style="top: 175px;"></div>
<div class="contents">
<div class="prepadding"></div>
<div class="container">
<div class="innerpadding"></div>
<div class="outerSticky">
<div class="innerIndicator" style="top: 10px;"></div>
<div class="innerSticky"></div>
</div>
</div>
</div>
</div>
</div>
<div class="group">
<div id="scroller3" class="scroller">
<div class="outerIndicator" style="top: 200px;"></div>
<div class="contents">
<div class="prepadding"></div>
<div class="container">
<div class="innerpadding"></div>
<div class="outerSticky">
<div class="innerIndicator" style="top: 50px;"></div>
<div class="innerSticky"></div>
</div>
</div>
</div>
</div>
</div>
<div>You should see three green and three blue boxes above. No red should be visible.</div>
...@@ -12,29 +12,29 @@ ...@@ -12,29 +12,29 @@
<script> <script>
test(() => { test(() => {
const elements = setupStickyTest('right', 25, true); const elements = setupStickyTest('right', 25);
elements.scroller.scrollLeft = 200; elements.scroller.scrollLeft = 200;
const nonStickyLeftY = elements.container.offsetLeft + const nonStickyLeftX = elements.container.offsetLeft +
elements.filler.clientWidth; elements.filler.clientWidth;
assert_equals(elements.sticky.offsetLeft, nonStickyLeftY); assert_equals(elements.sticky.offsetLeft, nonStickyLeftX);
}, 'before reaching the sticking point the sticky box should not be offset'); }, 'before reaching the sticking point the sticky box should not be offset');
test(() => { test(() => {
const elements = setupStickyTest('right', 25, true); const elements = setupStickyTest('right', 25);
elements.scroller.scrollLeft = 75; elements.scroller.scrollLeft = 75;
const nonStickyLeftY = elements.container.offsetLeft + const nonStickyLeftX = elements.container.offsetLeft +
elements.filler.clientWidth; elements.filler.clientWidth;
const nonStickyBottomY = nonStickyLeftY + elements.sticky.clientWidth; const nonStickyRightX = nonStickyLeftX + elements.sticky.clientWidth;
const targetBottomY = elements.scroller.clientWidth + const targetRightX = elements.scroller.clientWidth +
elements.scroller.scrollLeft - 25; elements.scroller.scrollLeft - 25;
const stickyOffset = nonStickyBottomY - targetBottomY; const stickyOffset = nonStickyRightX - targetRightX;
assert_equals(elements.sticky.offsetLeft, nonStickyLeftY - stickyOffset); assert_equals(elements.sticky.offsetLeft, nonStickyLeftX - stickyOffset);
}, 'after reaching the sticking point the sticky box should be offset'); }, 'after reaching the sticking point the sticky box should be offset');
test(() => { test(() => {
const elements = setupStickyTest('right', 25, true); const elements = setupStickyTest('right', 25);
elements.scroller.scrollLeft = 15; elements.scroller.scrollLeft = 15;
assert_equals(elements.sticky.offsetLeft, elements.container.offsetLeft); assert_equals(elements.sticky.offsetLeft, elements.container.offsetLeft);
}, 'the sticky box should not be pushed outside its containing block'); }, 'the sticky box should not be pushed outside its containing block');
......
...@@ -11,14 +11,15 @@ ...@@ -11,14 +11,15 @@
* </div> * </div>
* </div> * </div>
* *
* If 'inline' is true, the necessary blocks will be marked as inline-block, * If the sticky direction is 'left' or 'right', the necessary blocks will be
* and the dimensions above are flipped. * marked as inline-block and the dimensions above are flipped.
* *
* Returns an 'elements' object which has each of the above elements as an * Returns an 'elements' object which has each of the above elements as an
* accessible property. * accessible property.
*/ */
function setupStickyTest(stickyDirection, stickyOffset, inline = false) { function setupStickyTest(stickyDirection, stickyOffset) {
const elements = {}; const elements = {};
const inline = stickyDirection === 'left' || stickyDirection === 'right';
elements.scroller = document.createElement('div'); elements.scroller = document.createElement('div');
elements.scroller.style.position = 'relative'; elements.scroller.style.position = 'relative';
...@@ -67,3 +68,39 @@ function setupStickyTest(stickyDirection, stickyOffset, inline = false) { ...@@ -67,3 +68,39 @@ function setupStickyTest(stickyDirection, stickyOffset, inline = false) {
return elements; return elements;
} }
/**
* Similar to above, but nests a second sticky (named innerSticky) inside the
* sticky element.
*
* In the 'bottom' and 'right' cases, we also inject some padding before the
* innerSticky element, to give it something to push into. This inner padding is
* not exposed.
*/
function setupNestedStickyTest(stickyDirection, outerStickyOffset,
innerStickyOffset) {
const elements = setupStickyTest(stickyDirection, outerStickyOffset);
const inline = stickyDirection === 'left' || stickyDirection === 'right';
if (stickyDirection === 'bottom' || stickyDirection === 'right') {
const innerPadding = document.createElement('div');
innerPadding.style.height = (inline ? '100%' : '50px');
innerPadding.style.width = (inline ? '50px' : '100%');
if (inline)
innerPadding.style.display = 'inline-block';
elements.sticky.appendChild(innerPadding);
}
elements.innerSticky = document.createElement('div');
elements.innerSticky.style = `${stickyDirection}: ${innerStickyOffset}px;`;
elements.innerSticky.style.position = 'sticky';
elements.innerSticky.style.height = (inline ? '100%' : '50px');
elements.innerSticky.style.width = (inline ? '50px' : '100%');
elements.innerSticky.style.backgroundColor = 'blue';
if (inline)
elements.innerSticky.style.display = 'inline-block';
elements.sticky.appendChild(elements.innerSticky);
return elements;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment