зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1312165 - Honor `scroll-snap-stop: always`. r=botond
Depends on D145851 Differential Revision: https://phabricator.services.mozilla.com/D145852
This commit is contained in:
Родитель
17647a8cc5
Коммит
d2f6bd5b5c
|
@ -25,19 +25,34 @@ class CalcSnapPoints final {
|
|||
public:
|
||||
CalcSnapPoints(ScrollUnit aUnit, ScrollSnapFlags aSnapFlags,
|
||||
const nsPoint& aDestination, const nsPoint& aStartPos);
|
||||
void AddHorizontalEdge(nscoord aEdge);
|
||||
void AddVerticalEdge(nscoord aEdge);
|
||||
struct SnapPosition {
|
||||
SnapPosition() = default;
|
||||
|
||||
SnapPosition(nscoord aPosition, StyleScrollSnapStop aScrollSnapStop)
|
||||
: mPosition(aPosition), mScrollSnapStop(aScrollSnapStop) {}
|
||||
|
||||
nscoord mPosition;
|
||||
StyleScrollSnapStop mScrollSnapStop;
|
||||
};
|
||||
|
||||
void AddHorizontalEdge(const SnapPosition& aEdge);
|
||||
void AddVerticalEdge(const SnapPosition& aEdge);
|
||||
void AddEdge(const SnapPosition& aEdge, nscoord aDestination,
|
||||
nscoord aStartPos, nscoord aScrollingDirection,
|
||||
SnapPosition* aBestEdge, SnapPosition* aSecondBestEdge,
|
||||
bool* aEdgeFound);
|
||||
|
||||
void AddEdge(nscoord aEdge, nscoord aDestination, nscoord aStartPos,
|
||||
nscoord aScrollingDirection, nscoord* aBestEdge,
|
||||
nscoord* aSecondBestEdge, bool* aEdgeFound);
|
||||
nsPoint GetBestEdge() const;
|
||||
nscoord XDistanceBetweenBestAndSecondEdge() const {
|
||||
return std::abs(
|
||||
NSCoordSaturatingSubtract(mSecondBestEdge.x, mBestEdge.x, nscoord_MAX));
|
||||
return std::abs(NSCoordSaturatingSubtract(
|
||||
mSecondBestEdgeX.mPosition, mBestEdgeX.mPosition, nscoord_MAX));
|
||||
}
|
||||
nscoord YDistanceBetweenBestAndSecondEdge() const {
|
||||
return std::abs(
|
||||
NSCoordSaturatingSubtract(mSecondBestEdge.y, mBestEdge.y, nscoord_MAX));
|
||||
return std::abs(NSCoordSaturatingSubtract(
|
||||
mSecondBestEdgeY.mPosition, mBestEdgeY.mPosition, nscoord_MAX));
|
||||
}
|
||||
const nsPoint& Destination() const { return mDestination; }
|
||||
|
||||
|
@ -48,14 +63,20 @@ class CalcSnapPoints final {
|
|||
// snapping
|
||||
nsPoint mStartPos; // gives the position before scrolling
|
||||
nsIntPoint mScrollingDirection; // always -1, 0, or 1
|
||||
nsPoint mBestEdge; // keeps track of the position of the current best edge
|
||||
nsPoint mSecondBestEdge; // keeps track of the position of the current
|
||||
// second best edge on the opposite side of the best
|
||||
SnapPosition mBestEdgeX; // keeps track of the position of the current best
|
||||
// edge on X axis
|
||||
SnapPosition mBestEdgeY; // keeps track of the position of the current best
|
||||
// edge on Y axis
|
||||
SnapPosition mSecondBestEdgeX; // keeps track of the position of the current
|
||||
// second best edge on the opposite side of
|
||||
// the best edge on X axis
|
||||
SnapPosition mSecondBestEdgeY; // keeps track of the position of the current
|
||||
// second best edge on the opposite side of
|
||||
// the best edge on Y axis
|
||||
bool mHorizontalEdgeFound; // true if mBestEdge.x is storing a valid
|
||||
// horizontal edge
|
||||
bool mVerticalEdgeFound; // true if mBestEdge.y is storing a valid vertical
|
||||
// edge
|
||||
bool mHorizontalEdgeFound; // true if mBestEdge.x is storing a valid
|
||||
// horizontal edge
|
||||
bool mVerticalEdgeFound; // true if mBestEdge.y is storing a valid vertical
|
||||
// edge
|
||||
};
|
||||
|
||||
CalcSnapPoints::CalcSnapPoints(ScrollUnit aUnit, ScrollSnapFlags aSnapFlags,
|
||||
|
@ -82,40 +103,42 @@ CalcSnapPoints::CalcSnapPoints(ScrollUnit aUnit, ScrollSnapFlags aSnapFlags,
|
|||
if (direction.y > 0) {
|
||||
mScrollingDirection.y = 1;
|
||||
}
|
||||
mBestEdge = aDestination;
|
||||
mBestEdgeX = SnapPosition{aDestination.x, StyleScrollSnapStop::Normal};
|
||||
mBestEdgeY = SnapPosition{aDestination.y, StyleScrollSnapStop::Normal};
|
||||
// We use NSCoordSaturatingSubtract to calculate the distance between a given
|
||||
// position and this second best edge position so that it can be an
|
||||
// uninitialized value as the maximum possible value, because the first
|
||||
// distance calculation would always be nscoord_MAX.
|
||||
mSecondBestEdge = nsPoint(nscoord_MAX, nscoord_MAX);
|
||||
mSecondBestEdgeX = SnapPosition{nscoord_MAX, StyleScrollSnapStop::Normal};
|
||||
mSecondBestEdgeY = SnapPosition{nscoord_MAX, StyleScrollSnapStop::Normal};
|
||||
mHorizontalEdgeFound = false;
|
||||
mVerticalEdgeFound = false;
|
||||
}
|
||||
|
||||
nsPoint CalcSnapPoints::GetBestEdge() const {
|
||||
return nsPoint(mVerticalEdgeFound ? mBestEdge.x : mStartPos.x,
|
||||
mHorizontalEdgeFound ? mBestEdge.y : mStartPos.y);
|
||||
return nsPoint(mVerticalEdgeFound ? mBestEdgeX.mPosition : mStartPos.x,
|
||||
mHorizontalEdgeFound ? mBestEdgeY.mPosition : mStartPos.y);
|
||||
}
|
||||
|
||||
void CalcSnapPoints::AddHorizontalEdge(nscoord aEdge) {
|
||||
void CalcSnapPoints::AddHorizontalEdge(const SnapPosition& aEdge) {
|
||||
AddEdge(aEdge, mDestination.y, mStartPos.y, mScrollingDirection.y,
|
||||
&mBestEdge.y, &mSecondBestEdge.y, &mHorizontalEdgeFound);
|
||||
&mBestEdgeY, &mSecondBestEdgeY, &mHorizontalEdgeFound);
|
||||
}
|
||||
|
||||
void CalcSnapPoints::AddVerticalEdge(nscoord aEdge) {
|
||||
void CalcSnapPoints::AddVerticalEdge(const SnapPosition& aEdge) {
|
||||
AddEdge(aEdge, mDestination.x, mStartPos.x, mScrollingDirection.x,
|
||||
&mBestEdge.x, &mSecondBestEdge.x, &mVerticalEdgeFound);
|
||||
&mBestEdgeX, &mSecondBestEdgeX, &mVerticalEdgeFound);
|
||||
}
|
||||
|
||||
void CalcSnapPoints::AddEdge(nscoord aEdge, nscoord aDestination,
|
||||
void CalcSnapPoints::AddEdge(const SnapPosition& aEdge, nscoord aDestination,
|
||||
nscoord aStartPos, nscoord aScrollingDirection,
|
||||
nscoord* aBestEdge, nscoord* aSecondBestEdge,
|
||||
bool* aEdgeFound) {
|
||||
SnapPosition* aBestEdge,
|
||||
SnapPosition* aSecondBestEdge, bool* aEdgeFound) {
|
||||
if (mSnapFlags & ScrollSnapFlags::IntendedDirection) {
|
||||
// In the case of intended direction, we only want to snap to points ahead
|
||||
// of the direction we are scrolling.
|
||||
if (aScrollingDirection == 0 ||
|
||||
(aEdge - aStartPos) * aScrollingDirection <= 0) {
|
||||
(aEdge.mPosition - aStartPos) * aScrollingDirection <= 0) {
|
||||
// The scroll direction is neutral - will not hit a snap point, or the
|
||||
// edge is not in the direction we are scrolling, skip it.
|
||||
return;
|
||||
|
@ -128,19 +151,52 @@ void CalcSnapPoints::AddEdge(nscoord aEdge, nscoord aDestination,
|
|||
return;
|
||||
}
|
||||
|
||||
const bool isOnOppositeSide =
|
||||
((aEdge - aDestination) > 0) != ((*aBestEdge - aDestination) > 0);
|
||||
auto isPreferredStopAlways = [&](const SnapPosition& aSnapPosition) -> bool {
|
||||
MOZ_ASSERT(mSnapFlags & ScrollSnapFlags::IntendedDirection);
|
||||
// In the case of intended direction scroll operations, `scroll-snap-stop:
|
||||
// always` snap points in between the start point and the scroll destination
|
||||
// are preferable preferable. In other words any `scroll-snap-stop: always`
|
||||
// snap points can be handled as if it's `scroll-snap-stop: normal`.
|
||||
return aSnapPosition.mScrollSnapStop == StyleScrollSnapStop::Always &&
|
||||
std::abs(aSnapPosition.mPosition - aStartPos) <
|
||||
std::abs(aDestination - aStartPos);
|
||||
};
|
||||
|
||||
const bool isOnOppositeSide = ((aEdge.mPosition - aDestination) > 0) !=
|
||||
((aBestEdge->mPosition - aDestination) > 0);
|
||||
const nscoord distanceFromStart = aEdge.mPosition - aStartPos;
|
||||
// A utility function to update the best and the second best edges in the
|
||||
// given conditions.
|
||||
// |aIsCloserThanBest| True if the current candidate is closer than the best
|
||||
// edge.
|
||||
// |aIsCloserThanSecond| True if the current candidate is closer than
|
||||
// the second best edge.
|
||||
const nscoord distanceFromDestination = aEdge.mPosition - aDestination;
|
||||
auto updateBestEdges = [&](bool aIsCloserThanBest, bool aIsCloserThanSecond) {
|
||||
if (aIsCloserThanBest) {
|
||||
// Replace the second best edge with the current best edge only if the new
|
||||
// best edge (aEdge) is on the opposite side of the current best edge.
|
||||
if (isOnOppositeSide) {
|
||||
if (mSnapFlags & ScrollSnapFlags::IntendedDirection &&
|
||||
isPreferredStopAlways(aEdge)) {
|
||||
// In the case of intended direction scroll operations and the new best
|
||||
// candidate is `scroll-snap-stop: always` and if it's closer to the
|
||||
// start position than the destination, thus we won't use the second
|
||||
// best edge since even if the snap port of the best edge covers entire
|
||||
// snapport, the `scroll-snap-stop: always` snap point is preferred than
|
||||
// any points.
|
||||
// NOTE: We've already ignored snap points behind start points so that
|
||||
// we can use std::abs here in the comparison.
|
||||
//
|
||||
// For example, if there's a `scroll-snap-stop: always` in between the
|
||||
// start point and destination, no `snap-overflow` mechanism should
|
||||
// happen, if there's `scroll-snap-stop: always` further than the
|
||||
// destination, `snap-overflow` might happen something like below
|
||||
// diagram.
|
||||
// start always dest other always
|
||||
// |------------|---------|------|
|
||||
*aSecondBestEdge = aEdge;
|
||||
} else if (isOnOppositeSide) {
|
||||
// Replace the second best edge with the current best edge only if the
|
||||
// new best edge (aEdge) is on the opposite side of the current best
|
||||
// edge.
|
||||
*aSecondBestEdge = *aBestEdge;
|
||||
}
|
||||
*aBestEdge = aEdge;
|
||||
|
@ -157,23 +213,25 @@ void CalcSnapPoints::AddEdge(nscoord aEdge, nscoord aDestination,
|
|||
case ScrollUnit::DEVICE_PIXELS:
|
||||
case ScrollUnit::LINES:
|
||||
case ScrollUnit::WHOLE: {
|
||||
nscoord distance = std::abs(aEdge - aDestination);
|
||||
isCandidateOfBest = distance < std::abs(*aBestEdge - aDestination);
|
||||
isCandidateOfBest = std::abs(distanceFromDestination) <
|
||||
std::abs(aBestEdge->mPosition - aDestination);
|
||||
isCandidateOfSecondBest =
|
||||
distance < std::abs(NSCoordSaturatingSubtract(
|
||||
*aSecondBestEdge, aDestination, nscoord_MAX));
|
||||
std::abs(distanceFromDestination) <
|
||||
std::abs(NSCoordSaturatingSubtract(aSecondBestEdge->mPosition,
|
||||
aDestination, nscoord_MAX));
|
||||
break;
|
||||
}
|
||||
case ScrollUnit::PAGES: {
|
||||
// distance to the edge from the scrolling destination in the direction of
|
||||
// scrolling
|
||||
nscoord overshoot = (aEdge - aDestination) * aScrollingDirection;
|
||||
nscoord overshoot = distanceFromDestination * aScrollingDirection;
|
||||
// distance to the current best edge from the scrolling destination in the
|
||||
// direction of scrolling
|
||||
nscoord curOvershoot = (*aBestEdge - aDestination) * aScrollingDirection;
|
||||
nscoord curOvershoot =
|
||||
(aBestEdge->mPosition - aDestination) * aScrollingDirection;
|
||||
|
||||
nscoord secondOvershoot =
|
||||
NSCoordSaturatingSubtract(*aSecondBestEdge, aDestination,
|
||||
NSCoordSaturatingSubtract(aSecondBestEdge->mPosition, aDestination,
|
||||
nscoord_MAX) *
|
||||
aScrollingDirection;
|
||||
|
||||
|
@ -193,6 +251,21 @@ void CalcSnapPoints::AddEdge(nscoord aEdge, nscoord aDestination,
|
|||
}
|
||||
}
|
||||
|
||||
if (mSnapFlags & ScrollSnapFlags::IntendedDirection) {
|
||||
if (isPreferredStopAlways(aEdge)) {
|
||||
// If the given position is `scroll-snap-stop: always` and if the position
|
||||
// is in between the start and the destination positions, update the best
|
||||
// position based on the distance from the __start__ point.
|
||||
isCandidateOfBest = std::abs(distanceFromStart) <
|
||||
std::abs(aBestEdge->mPosition - aStartPos);
|
||||
} else if (isPreferredStopAlways(*aBestEdge)) {
|
||||
// If we've found a preferable `scroll-snap-stop:always` position as the
|
||||
// best, do not update it unless the given position is also
|
||||
// `scroll-snap-stop: always`.
|
||||
isCandidateOfBest = false;
|
||||
}
|
||||
}
|
||||
|
||||
updateBestEdges(isCandidateOfBest, isCandidateOfSecondBest);
|
||||
}
|
||||
|
||||
|
@ -213,11 +286,13 @@ static void ProcessSnapPositions(CalcSnapPoints& aCalcSnapPoints,
|
|||
|
||||
if (target.mSnapPositionX &&
|
||||
aSnapInfo.mScrollSnapStrictnessX != StyleScrollSnapStrictness::None) {
|
||||
aCalcSnapPoints.AddVerticalEdge(*target.mSnapPositionX);
|
||||
aCalcSnapPoints.AddVerticalEdge(
|
||||
{*target.mSnapPositionX, target.mScrollSnapStop});
|
||||
}
|
||||
if (target.mSnapPositionY &&
|
||||
aSnapInfo.mScrollSnapStrictnessY != StyleScrollSnapStrictness::None) {
|
||||
aCalcSnapPoints.AddHorizontalEdge(*target.mSnapPositionY);
|
||||
aCalcSnapPoints.AddHorizontalEdge(
|
||||
{*target.mSnapPositionY, target.mScrollSnapStop});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -251,7 +326,8 @@ Maybe<nsPoint> ScrollSnapUtils::GetSnapPointForDestination(
|
|||
if (range.IsValid(clampedDestination.x, aSnapInfo.mSnapportSize.width) &&
|
||||
calcSnapPoints.XDistanceBetweenBestAndSecondEdge() >
|
||||
aSnapInfo.mSnapportSize.width) {
|
||||
calcSnapPoints.AddVerticalEdge(clampedDestination.x);
|
||||
calcSnapPoints.AddVerticalEdge(CalcSnapPoints::SnapPosition{
|
||||
clampedDestination.x, StyleScrollSnapStop::Normal});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -259,7 +335,8 @@ Maybe<nsPoint> ScrollSnapUtils::GetSnapPointForDestination(
|
|||
if (range.IsValid(clampedDestination.y, aSnapInfo.mSnapportSize.height) &&
|
||||
calcSnapPoints.YDistanceBetweenBestAndSecondEdge() >
|
||||
aSnapInfo.mSnapportSize.height) {
|
||||
calcSnapPoints.AddHorizontalEdge(clampedDestination.y);
|
||||
calcSnapPoints.AddHorizontalEdge(CalcSnapPoints::SnapPosition{
|
||||
clampedDestination.y, StyleScrollSnapStop::Normal});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
[scroll-snap-stop-change.html]
|
||||
[scroll-snap-stop for areas on HTML should control snapping behavior and changing it takes effect]
|
||||
expected: FAIL
|
||||
|
||||
[scroll-snap-stop for areas on DIV should control snapping behavior and changing it takes effect]
|
||||
expected: FAIL
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
[scroll-snap-stop.html]
|
||||
[A scroll outside bounds in the non-snapping axis with intended direction and end position should not pass a snap area with scroll-snap-stop: always.]
|
||||
expected: FAIL
|
||||
|
||||
[A scroll outside bounds in the snapping axis with intended direction and end position should not pass a snap area with scroll-snap-stop: always.]
|
||||
expected: FAIL
|
||||
|
||||
[A scroll with intended direction and end position should not pass a snap area with scroll-snap-stop: always.]
|
||||
expected: FAIL
|
|
@ -0,0 +1,238 @@
|
|||
<!DOCTYPE html>
|
||||
<link rel="help" href="https://drafts.csswg.org/css-scroll-snap/#scroll-snap-stop" />
|
||||
<link rel="help" href="https://drafts.csswg.org/css-scroll-snap-1/#snap-overflow" />
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<style>
|
||||
div {
|
||||
position: absolute;
|
||||
}
|
||||
.scroller {
|
||||
width: 400px;
|
||||
height: 100px;
|
||||
overflow: scroll;
|
||||
scroll-snap-type: x mandatory;
|
||||
}
|
||||
#space {
|
||||
left: 0px;
|
||||
top: 0px;
|
||||
width: 2100px;
|
||||
height: 50px;
|
||||
}
|
||||
.target {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
scroll-snap-align: start;
|
||||
top: 0px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!--
|
||||
start dest closest always
|
||||
|------------------------------|--------|--------|
|
||||
-->
|
||||
<div class="scroller" id="scroller1">
|
||||
<div id="space"></div>
|
||||
<div class="target" style="left: 0px;"></div>
|
||||
<!-- Add `scroll-snap-stop: always` element into the DOM tree prior to the
|
||||
closest snap point -->
|
||||
<div class="target" style="left: 120px; scroll-snap-stop: always;"></div>
|
||||
<!-- Add a snap point closest-to-destination but further than the destination
|
||||
from the start position -->
|
||||
<div class="target" style="left: 110px;"></div>
|
||||
</div>
|
||||
|
||||
<!--
|
||||
start closest dest always
|
||||
|------------------------------|------|--------|
|
||||
-->
|
||||
<div class="scroller" id="scroller2">
|
||||
<div id="space"></div>
|
||||
<div class="target" style="left: 0px;"></div>
|
||||
<div class="target" style="left: 120px; scroll-snap-stop: always;"></div>
|
||||
<!-- Add a snap point closest-to-destination and closer than the destination
|
||||
from the start position -->
|
||||
<div class="target" style="left: 95px;"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--
|
||||
A test case where there's a snap point whose snap area covers the snapport and
|
||||
there's a `scroll-snap-stop: always` snap point on the opposite side.
|
||||
-->
|
||||
<div class="scroller" id="scroller3">
|
||||
<div id="space"></div>
|
||||
<div class="target" style="left: 0px;"></div>
|
||||
<div class="target" style="left: 700px; scroll-snap-stop: always;"></div>
|
||||
<!-- Add a snap point where the snap area covers the snapport entirely -->
|
||||
<div class="target" style="left: 100px; width: 500px;"></div>
|
||||
<!-- Add a snap point where the distance between this and the 100px point is
|
||||
larger than the snapport size (400px) -->
|
||||
<div class="target" style="left: 600px;"></div>
|
||||
</div>
|
||||
|
||||
<!--
|
||||
A similar case above, but two `scroll-snap-stop: always` snap points.
|
||||
-->
|
||||
<div class="scroller" id="scroller4">
|
||||
<div id="space"></div>
|
||||
<div class="target" style="left: 0px;"></div>
|
||||
<div class="target" style="left: 700px; scroll-snap-stop: always;"></div>
|
||||
<!-- Add a snap point where the snap area covers the snapport entirely -->
|
||||
<div class="target" style="left: 100px; width: 500px;"></div>
|
||||
<!-- Add a snap point where the distance between this and the 100px point is
|
||||
larger than the snapport size (400px) -->
|
||||
<div class="target" style="left: 600px; scroll-snap-stop: always;"></div>
|
||||
</div>
|
||||
|
||||
<!--
|
||||
Another similar case, but the nearest snap point to the start point is
|
||||
`scroll-snap-stop: always`.
|
||||
-->
|
||||
<div class="scroller" id="scroller5">
|
||||
<div id="space"></div>
|
||||
<div class="target" style="left: 0px;"></div>
|
||||
<div class="target" style="left: 700px; scroll-snap-stop: always;"></div>
|
||||
<!-- Add a snap point where the snap area covers the snapport entirely -->
|
||||
<div class="target" style="left: 100px; width: 500px; scroll-snap-stop: always;"></div>
|
||||
<!-- Add a snap point where the distance between this and the 100px point is
|
||||
larger than the snapport size (400px) -->
|
||||
<div class="target" style="left: 600px;"></div>
|
||||
</div>
|
||||
|
||||
<!--
|
||||
A test case that a `scroll-snap-stop: always` snap point is further than the
|
||||
scroll destination.
|
||||
-->
|
||||
<div class="scroller" id="scroller6">
|
||||
<div id="space"></div>
|
||||
<div class="target" style="left: 0px;"></div>
|
||||
<div class="target" style="left: 400px;"></div>
|
||||
<div class="target" style="left: 700px; scroll-snap-stop: always;"></div
|
||||
</div>
|
||||
|
||||
<!--
|
||||
Similar to above but a snap area covers the snapport.
|
||||
-->
|
||||
<div class="scroller" id="scroller7">
|
||||
<div id="space"></div>
|
||||
<div class="target" style="left: 0px;"></div>
|
||||
<div class="target" style="left: 400px; width: 900px;"></div>
|
||||
<div class="target" style="left: 900px; scroll-snap-stop: always;"></div
|
||||
</div>
|
||||
|
||||
<script>
|
||||
|
||||
test(() => {
|
||||
assert_equals(scroller1.scrollLeft, 0);
|
||||
assert_equals(scroller1.scrollTop, 0);
|
||||
|
||||
// start dest closest always
|
||||
// |------------------------------|--------|--------|
|
||||
// 0 100 110 120
|
||||
scroller1.scrollBy(100, 0);
|
||||
assert_equals(scroller1.scrollLeft, 110);
|
||||
assert_equals(scroller1.scrollTop, 0);
|
||||
}, "The closest snap point is preferred than scroll-snap-stop: always where " +
|
||||
"it's further than the destination (the closest one is closer to the " +
|
||||
"scroll start position than the destination)");
|
||||
|
||||
test(() => {
|
||||
assert_equals(scroller2.scrollLeft, 0);
|
||||
assert_equals(scroller2.scrollTop, 0);
|
||||
|
||||
// start closest dest always
|
||||
// |------------------------------|------|--------|
|
||||
// 0 95 100 120
|
||||
scroller2.scrollBy(100, 0);
|
||||
assert_equals(scroller2.scrollLeft, 95);
|
||||
assert_equals(scroller2.scrollTop, 0);
|
||||
}, "The closest snap point is preferred than scroll-snap-stop: always where " +
|
||||
"it's further than the destination (the closest one is futrher than the " +
|
||||
"destination from the start position)");
|
||||
|
||||
test(() => {
|
||||
assert_equals(scroller3.scrollLeft, 0);
|
||||
assert_equals(scroller3.scrollTop, 0);
|
||||
|
||||
// start dest always
|
||||
// |-----|===|============================|------|
|
||||
// 0 100 150 600 700
|
||||
|
||||
// Scoll on the element whose snap area is larger than the snapport.
|
||||
scroller3.scrollBy(150, 0);
|
||||
assert_equals(scroller3.scrollLeft, 150);
|
||||
assert_equals(scroller3.scrollTop, 0);
|
||||
}, "The scroll destination on a large element whose snap area covers " +
|
||||
"the snapport entirely is a valid snap position");
|
||||
|
||||
test(() => {
|
||||
assert_equals(scroller4.scrollLeft, 0);
|
||||
assert_equals(scroller4.scrollTop, 0);
|
||||
|
||||
// start dest always always
|
||||
// |-----|====|============================|------|
|
||||
// 0 100 150 600 700
|
||||
|
||||
// Scoll on the element whose snap area is larger than the snapport.
|
||||
scroller4.scrollBy(150, 0);
|
||||
assert_equals(scroller4.scrollLeft, 150);
|
||||
assert_equals(scroller4.scrollTop, 0);
|
||||
}, "The scroll destination on a large element whose snap area covers " +
|
||||
"the snapport entirely is a valid snap position (with two " +
|
||||
"`scroll-snap-stop: always` snap points");
|
||||
|
||||
test(() => {
|
||||
assert_equals(scroller5.scrollLeft, 0);
|
||||
assert_equals(scroller5.scrollTop, 0);
|
||||
|
||||
// start always dest always
|
||||
// |-----|=====|============================|------|
|
||||
// 0 100 150 600 700
|
||||
|
||||
// Scoll on the element whose snap area is larger than the snapport, but
|
||||
// the scroll-snap-stop property is `always`.
|
||||
scroller5.scrollBy(150, 0);
|
||||
assert_equals(scroller5.scrollLeft, 100);
|
||||
assert_equals(scroller5.scrollTop, 0);
|
||||
|
||||
// Scroll the direction further, it should NOT be trapped by the
|
||||
// `scroll-snap-stop: always` snap point.
|
||||
scroller5.scrollBy(50, 0);
|
||||
assert_equals(scroller5.scrollLeft, 150);
|
||||
assert_equals(scroller5.scrollTop, 0);
|
||||
}, "`scroll-snap-stop: always` snap point is preferred even if the snap area " +
|
||||
"entire snapport");
|
||||
|
||||
test(() => {
|
||||
assert_equals(scroller6.scrollLeft, 0);
|
||||
assert_equals(scroller6.scrollTop, 0);
|
||||
|
||||
// start dest always
|
||||
// |-------------------------|-----------------|------|
|
||||
// 0 400 600 700
|
||||
|
||||
// Scroll to a point where it's closer to a `scroll-snap-stop: always` snap
|
||||
// position.
|
||||
scroller6.scrollBy(600, 0);
|
||||
assert_equals(scroller6.scrollLeft, 700);
|
||||
assert_equals(scroller6.scrollTop, 0);
|
||||
}, "`scroll-snap-stop: always` snap point is further than the scroll " +
|
||||
"destination");
|
||||
|
||||
test(() => {
|
||||
assert_equals(scroller7.scrollLeft, 0);
|
||||
assert_equals(scroller7.scrollTop, 0);
|
||||
|
||||
// start dest always
|
||||
// |-------------------------|================|=====|=====
|
||||
// 0 400 700 900
|
||||
|
||||
// Scoll on the element whose snap area is larger than the snapport.
|
||||
scroller7.scrollBy(700, 0);
|
||||
assert_equals(scroller7.scrollLeft, 700);
|
||||
assert_equals(scroller7.scrollTop, 0);
|
||||
}, "`scroll-snap-stop: always` snap point is further than the scroll " +
|
||||
"destination and a snap area covers the snapport");
|
||||
|
||||
</script>
|
Загрузка…
Ссылка в новой задаче