拆分列(每个50%)在相反方向滚动-连续/循环



EDIT仔细观察,在调整视口大小时,这是非常糟糕的。它停止工作或在狭窄的窗口上滚动,滚动速度非常快。所以我把它作为赏金!

--

我看到了类似的东西,并一直在尝试重构JS。我有两列内容,当滚动时会向相反的方向移动。这应该是连续循环的。

问题是,如果我从.project元素中删除了高度。向下滚动但不向上滚动时,内容将平滑滚动。内容的高度/长度会有所不同,所以我不能在这里有一个固定的值。

这似乎取决于视口高度。如果UI的行为符合预期,并且我减小了视口的宽度,它可能会像上面描述的那样停止工作。但如果我降低高度,它就能重新开始正常工作。所以,也许这取决于加载时视口中有多少内容可见?

示例(也在代码片段中(:https://jsfiddle.net/rdowb0y5/1

我将添加一个"媒体查询",这样它只在平板电脑/桌面视图和移动设备上可见,JS被删除,内容被堆叠。

提前感谢-真的很期待在这方面得到一些支持!

$(document).ready(function() {
var num_children=$('.split-loop__left').children().length;
var child_height=$('.split-loop__right').height() / num_children;
var half_way=num_children * child_height / 2;
$(window).scrollTop(half_way);
function crisscross() {
var parent=$(".split-loop"); //.first();
var clone=$(parent).clone();
var leftSide=$(clone).find('.split-loop__left');
var rightSide=$(clone).find('.split-loop__right');
if (window.scrollY > half_way) {
//We are scrolling up
$(window).scrollTop(half_way - child_height);
var firstLeft=$(leftSide).children().first();
var lastRight=$(rightSide).children().last();
lastRight.appendTo(leftSide);
firstLeft.prependTo(rightSide);
}
else if (window.scrollY < half_way - child_height) {
var lastLeft=$(leftSide).children().last();
var firstRight=$(rightSide).children().first();
$(window).scrollTop(half_way);
lastLeft.appendTo(rightSide);
firstRight.prependTo(leftSide);
}
$(leftSide).css('bottom', '-'+ window.scrollY + 'px');
$(rightSide).css('bottom', '-'+ window.scrollY + 'px');
$(parent).replaceWith(clone);
}
$(window).scroll(crisscross);
}
);
/* Hide Scroll Bars */
::-webkit-scrollbar {
display: none;
}
html,
body {
margin: 0;
padding: 0;
-ms-overflow-style: none;
/* IE and Edge */
scrollbar-width: none;
/* Firefox */
}

/* Basic Styling */
img {
border: 1px solid black;
margin-bottom: 24px;
width: 100%;
max-width: 100%;
}
h2 {
font-size: 14px;
font-weight: normal;
margin-bottom: 4px;
font-family: 'Inter', sans-serif;
}
p {
color: black;
font-size: 11px;
font-family: 'Inter', sans-serif;
}

/* Content will be in these eventually */
.bar-left,
.bar-right {
border-right: 1px solid black;
box-sizing: border-box;
height: 100vh;
position: fixed;
top: 0;
left: 0;
width: 48px;
z-index: 10000;
}
.bar-right {
border: none;
border-left: 1px solid black;
left: auto;
right: 0;
}

/* Split Loop */
.split-loop {
position: relative;
margin: 0 48px;
}
.split-loop__left {
// position: absolute;
// left: 0%;
// top: 0%;
// right: auto;
// bottom: auto;
// z-index: 4;
width: 50%;
}
.split-loop__right {
border-left: 1px solid black;
box-sizing: border-box;
position: fixed;
right: 48px;
bottom: 0;
z-index: 5;
width: calc(50% - 48px);
}
.project {
box-sizing: border-box;
border-bottom: 1px solid black;
height: 600px;
padding: 48px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.0/jquery.min.js"></script>
<header class="bar-left">
</header>
<div class="bar-right">
</div>
<div class="view">
<div class="grid split-loop">
<div class="split-loop__left">
<div class="grid__item project">
<img src="https://www.fillmurray.com/600/400" alt="" class="project__media" />
<h2 class="project__title">Project Title</h2>
<p class="project__desc">Short Description</p>
</div>
<div class="grid__item project">
<img src="https://www.fillmurray.com/g/600/400" alt="" class="project__media" />
<h2 class="project__title">Project Title</h2>
<p class="project__desc">Short Description</p>
</div>
<div class="grid__item project">
<img src="https://www.fillmurray.com/600/400" alt="" class="project__media" />
<h2 class="project__title">Project Title</h2>
<p class="project__desc">Short Description</p>
</div>
</div>
<div class="split-loop__right">
<div class="grid__item project">
<img src="https://www.fillmurray.com/g/600/400" alt="" class="project__media" />
<h2 class="project__title">Project Title</h2>
<p class="project__desc">Short Description</p>
</div>
<div class="grid__item project">
<img src="https://www.fillmurray.com/600/400" alt="" class="project__media" />
<h2 class="project__title">Project Title</h2>
<p class="project__desc">Short Description</p>
</div>
<div class="grid__item project">
<img src="https://www.fillmurray.com/g/600/400" alt="" class="project__media" />
<h2 class="project__title">Project Title</h2>
<p class="project__desc">Short Description</p>
</div>
</div>
</div>
</div>

Familytype.co有以下限制:

  1. 需要多一个滚动容器。他们正在使用身体上的滚动条
  2. 两条车道的高度必须相等。他们的幻灯片有不同的高度,但都是50vh的倍数。他们设法拥有相同高度的车道。高度仍然基于视口,请参见它们的.block--50.block--100样式规则
  3. 你们需要在同一条道上重复前两项,才能看到第一张幻灯片的平滑切换

在下文中,familytype.co风格,方法中,我重复了左车道中的前两个元素。然后用javascript将左车道的所有元素克隆到右车道。还添加了一个媒体查询,如果视口宽度低于576px,则只显示一条车道。

let view, parent, leftSide, rightSide;
$(document).ready(function() {
view = $('#view');
parent = $(".split-loop");
leftSide = $(parent).find('.split-loop__left');
rightSide = $(parent).find('.split-loop__right');
centerScrollPosition();
window.onresize = function(event) {
centerScrollPosition();
};
//repeat first 2
$(leftSide).append($($(leftSide).children()[0]).clone());
$(leftSide).append($($(leftSide).children()[1]).clone());
//clone left lane to right      
let arr = [];
$(leftSide).children().each((index, elm) => {
arr.push($(elm).clone());
});
//shift right lane by half
//arr.push.apply(arr, arr.splice(0, arr.length / 2));
//arr.push(arr[0].clone());
//arr.push(arr[1].clone());
$(rightSide).append(arr);
//listen to scroll events
//incase you want movement to happen on user scroll
$(view).add(window).scroll(function() {
//$(view).on('wheel', function (event) {
handleScroll();
});
handleScroll();
});

function centerScrollPosition() {
//center the content
var vh = $(window).height();
var lh = leftSide.height();
var half_way = (lh - vh) / 2;
$(window).scrollTop(half_way);
}
function handleScroll() {
var scroll = $(window).scrollTop();
var sh = $(leftSide).height() - window.innerHeight;
if (scroll >= (sh - 1)) {
$(window).scrollTop(2);
} else if (scroll == 0) {
$(window).scrollTop(sh - 1);
}
$(rightSide).css({
"transform": "translate3d(0, " + ((((sh) - scroll * 2) * -1)) + "px, 0)"
});
}
* {
box-sizing: border-box;
}
::-webkit-scrollbar {
display: none;
}
html,
body {
margin: 0;
padding: 0;
height: 100%;
width: 100%;
background-color: white;
}
body {
overflow-y: scroll
}

/* Basic Styling */
img {
max-width: 90%;
object-fit: fill;
margin-top: 1rem;
align-self: center;
border: 1px solid black;
}
h2 {
font-size: 14px;
font-weight: normal;
margin-bottom: 4px;
font-family: 'Inter', sans-serif;
text-align: center;
}
p {
color: black;
font-size: 11px;
font-family: 'Inter', sans-serif;
text-align: center;
}

/* center line for debugging */
.center {
position: fixed;
width: 100vw;
top: 50%;
left: 0%;
z-index: 100000;
transform: translateY(-50%);
border-bottom: 2px dashed gray;
}

/* Content will be in these eventually */
.view {
overflow: hidden;
position: relative;
width: 80vw;
margin: 0 auto;
}
.bar-left,
.bar-right {
/*border-right: 1px solid black;*/
box-sizing: border-box;
height: 100vh;
position: fixed;
top: 0;
left: 0;
width: 5vw;
z-index: 10000;
}
.bar-right {
border: none;
/*border-left: 1px solid black;*/
left: auto;
right: 0;
}

/* Split Loop */
.split-loop {
position: relative;
width: 100%;
height: 100%;
}
.split-loop>div {
max-width: 50%;
float: left;
height: auto;
transform-style: preserve-3d;
display: flex;
flex-flow: column;
}
.split-loop__right {
will-change: transform;
perspective: 1000;
backface-visibility: hidden;
}
.project {
border: 1px solid black;
min-height: auto;
background-color: lightskyblue;
display: flex;
flex-flow: column nowrap;
}
@media(max-width: 576px) {
.split-loop>div {
max-width: 100%;
}
.split-loop__right {
display: none;
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!-- span class="center"></span -->
<header class="bar-left"></header>
<div class="bar-right"></div>
<div id=view class="view">
<div class="grid split-loop">
<div class="split-loop__left">
<div class="grid__item project">
<img src="https://www.fillmurray.com/600/400" alt="" class="project__media" />
<h2 class="project__title">Project Title 1</h2>
<p class="project__desc">Short Description Lorem ipsum dolor sit amet consectetur adipisicing elit. Consequuntur, id?Short Description Lorem ipsum dolor sit amet consectetur adipisicing elit. Consequuntur, id?</p>
</div>
<div class="grid__item project">
<img src="https://www.placecage.com/c/460/300" alt="" class="project__media" />
<h2 class="project__title">Project Title 2</h2>
<p class="project__desc">Short Description Lorem ipsum dolor sit amet.</p>
</div>
<div class="grid__item project">
<img src="https://www.placecage.com/g/155/300" alt="" class="project__media" />
<h2 class="project__title">Project Title 3</h2>
<p class="project__desc">Short Description Lorem ipsum dolor sit amet consectetur, adipisicing elit. Aspernatur nostrum in obcaecati itaque explicabo voluptatibus corporis cumque praesentium eaque beatae!</p>
</div>
<div class="grid__item project">
<img src="https://www.placecage.com/140/100" alt="" class="project__media" />
<h2 class="project__title">Project Title 4</h2>
<p class="project__desc">Short Description Lorem, ipsum dolor sit amet consectetur adipisicing elit. Dolores nobis eius, minus optio ab earum. Lorem ipsum dolor sit amet consectetur adipisicing elit. Architecto, at. Fuga nisi nulla laborum explicabo possimus repellendus
amet quidem eos.</p>
</div>
<div class="grid__item project">
<img src="https://www.stevensegallery.com/460/300" alt="" class="project__media" />
<h2 class="project__title">Project Title 5</h2>
<p class="project__desc">Short Description Lorem ipsum dolor sit amet consectetur adipisicing elit. Nihil?</p>
</div>
<div class="grid__item project">
<img src="https://www.fillmurray.com/g/600/400" alt="" class="project__media" />
<h2 class="project__title">Project Title 6</h2>
<p class="project__desc">Short Description Lorem ipsum dolor, sit amet consectetur adipisicing elit. Quia iste distinctio doloremque facere!</p>
</div>
</div>
<div class="split-loop__right">
</div>
</div>
</div>

第二车道需要更巧妙的布局。


老答案:我们可以使用转换来代替滚动条。代码中有解释:

//variables to track left and right container scrolls
var leftX = 0, rightX = 0;
//how quickly shifts will happen
//depends on how many images are in a column
//range 1.0 - 5.0
var shiftingThreshold = 1.7;
var isAnimating = false;
var parent, leftSide, rightSide;

$(document).ready(function () {
parent = $(".split-loop");
leftSide = $(parent).find('.split-loop__left');
rightSide = $(parent).find('.split-loop__right');
centerScrollPosition();
window.onresize = function (event) {
centerScrollPosition();
};
document.querySelector('.split-loop__left').addEventListener('transitionend', () => {
isAnimating = false;
//positive value means clockwise
//negative means counter clockwise
//remove if you don't want to run loop
//handleScroll(-125);
});
//listen to scroll events
//incase you want movement to happen on user scroll
$('#view').on('wheel', function (event) {
handleScroll(event.originalEvent.deltaY);
});
//initiate continuous loop
setTimeout(function () {
//handleScroll(-125);
}, 3000);
});
function centerScrollPosition() {
//center the content
var vh = $('#view').height();
var slh = $('.split-loop__left').height();
var half_way = (slh - vh) / 2;
$('#view').scrollTop(half_way);
}
function handleScroll(deltaY) {
//handle next scroll event only after last transition ends.
if (isAnimating) {
return;
}
isAnimating = true;
var isUpShifted = true;
var isJumped = true;
leftX -= deltaY;
rightX += deltaY;
if (deltaY !== 0) {
var childHeight = $('.split-loop__left').children().first().height();
if ((leftX + childHeight / shiftingThreshold) <= 0) { //clockwise shift
isUpShifted = true;
var firstLeft = $(leftSide).children().first();
var lastRight = $(rightSide).children().last();
//shift left-first to right
firstLeft.prependTo(rightSide);
//shift right-last to left
lastRight.appendTo(leftSide);
leftX += childHeight + deltaY;
rightX -= childHeight + deltaY;
} else if ((leftX - childHeight / shiftingThreshold) > 0) { //anti clockwise shift
isUpShifted = false;
var lastLeft = $(leftSide).children().last();
var firstRight = $(rightSide).children().first();
//shift right-first to left
firstRight.prependTo(leftSide);
//shift left-last to right
lastLeft.appendTo(rightSide);
leftX -= childHeight - deltaY;
rightX += childHeight - deltaY;
} else {
isJumped = false;
}
//if we've moved projects to other container then 
//adjust position before smooth scrolling effect
if (isJumped) {
$('.split-loop__left').css('transform', 'translateY(' + leftX + 'px)');
$('.split-loop__right').css('transform', 'translateY(' + rightX + 'px)');
$('.split-loop__left').css('transition-duration', '0s');
$('.split-loop__right').css('transition-duration', '0s');
if (isUpShifted) {
leftX -= deltaY;
rightX += deltaY;
} else {
leftX -= deltaY;
rightX += deltaY;
}
}
//do smooth scroll effect
setTimeout(function () {
$('.split-loop__left').css('transition-duration', '1.5s');
$('.split-loop__right').css('transition-duration', '1.5s');
$('.split-loop__left').css('transform', 'translateY(' + leftX + 'px)');
$('.split-loop__right').css('transform', 'translateY(' + rightX + 'px)');
}, 5);
}
}
* {
box-sizing: border-box;
}
html,
body {
margin: 0;
padding: 0;
height: 100%;
width: 100%;
background-color: wheat;
}

/* Basic Styling */
img {
max-width: 80%;
aspect-ratio: 6/4;
object-fit: fill;
margin-top: 10%;
align-self: center;
border: 1px solid black;
}
h2 {
font-size: 14px;
font-weight: normal;
margin-bottom: 4px;
font-family: 'Inter', sans-serif;
text-align: center;
}
p {
color: black;
font-size: 11px;
font-family: 'Inter', sans-serif;
text-align: center;
}
/* center line for debugging */
.center {
position: fixed;
width: 100vw;
top: 50%;
left: 0%;
z-index: 100000;
transform: translateY(-50%);
border-bottom: 2px dashed gray;
}

/* Content will be in these eventually */
.view {
overflow: hidden;
position: relative;
width: 80vw;
height: 100vh;
margin: 0 auto;
}
.bar-left,
.bar-right {
/*border-right: 1px solid black;*/
box-sizing: border-box;
height: 100vh;
position: fixed;
top: 0;
left: 0;
width: 5vw;
z-index: 10000;
}
.bar-right {
border: none;
/*border-left: 1px solid black;*/
left: auto;
right: 0;
}
/* Split Loop */
.split-loop {
position: relative;
width: 100%;
height: 100%;
}
.split-loop>div {
max-width: 50%;
float: left;
transition-timing-function: linear;
height: auto;
will-change: transform;
}
.project {
border: 1px solid black;
min-height: 70vh;
background-color: lightskyblue;
display: flex;
flex-flow: column nowrap;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!-- span class="center"></span -->
<header class="bar-left"></header>
<div class="bar-right"></div>
<div id=view class="view">
<div class="grid split-loop">
<div class="split-loop__left">
<div class="grid__item project">
<img src="https://www.fillmurray.com/600/400" alt="" class="project__media" />
<h2 class="project__title">Project Title 1</h2>
<p class="project__desc">Short Description Lorem ipsum dolor sit amet consectetur adipisicing elit.
Consequuntur, id?</p>
</div>
<div class="grid__item project">
<img src="https://www.fillmurray.com/g/600/400" alt="" class="project__media" />
<h2 class="project__title">Project Title 2</h2>
<p class="project__desc">Short Description Lorem ipsum dolor sit amet.</p>
</div>
<div class="grid__item project">
<img src="https://www.fillmurray.com/600/400" alt="" class="project__media" />
<h2 class="project__title">Project Title 3</h2>
<p class="project__desc">Short Description Lorem ipsum dolor sit amet consectetur, adipisicing elit.
Aspernatur nostrum in obcaecati itaque explicabo voluptatibus corporis cumque praesentium eaque beatae!</p>
</div>
</div>
<div class="split-loop__right">
<div class="grid__item project">
<img src="https://www.fillmurray.com/g/600/400" alt="" class="project__media" />
<h2 class="project__title">Project Title 4</h2>
<p class="project__desc">Short Description Lorem, ipsum dolor sit amet consectetur adipisicing elit. Dolores
nobis eius, minus optio ab earum.</p>
</div>
<div class="grid__item project">
<img src="https://www.fillmurray.com/600/400" alt="" class="project__media" />
<h2 class="project__title">Project Title 5</h2>
<p class="project__desc">Short Description Lorem ipsum dolor sit amet consectetur adipisicing elit. Nihil?</p>
</div>
<div class="grid__item project">
<img src="https://www.fillmurray.com/g/600/400" alt="" class="project__media" />
<h2 class="project__title">Project Title 6</h2>
<p class="project__desc">Short Description Lorem ipsum dolor, sit amet consectetur adipisicing elit. Quia iste
distinctio doloremque facere!</p>
</div>
</div>
</div>
</div>

每列三个项目对于在小视口中平滑移动来说是非常少的。你需要玩shiftingThreshold

这个例子有点草率,没有使用jQuery,但它使用两个相互依赖的卷轴(左块和右块(。我希望这能以某种方式帮助你解决问题。

const rootElement = document.querySelector(".split-loop");
const leftLoop = document.querySelector(".split-loop__left");
const rightLoop = document.querySelector(".split-loop__right");
const scrollHeight = leftLoop.scrollHeight;
const offsetBoundary = 200; //the offset from the borders at which the element reordering event is triggered
const lastScrollPos = new WeakMap();
const linkedLoops = new Map([
[leftLoop, rightLoop],
[rightLoop, leftLoop],
]);
let scrollLockElement = null;
let scrollLockTimeout = null;
// the function sets handlers to scrolling for infinite scrolling
function infiniteScrollHandler(loop) {
const virtualLoop = Array.from(loop.children);
virtualLoop.forEach(
(el) => (el.style.top = scrollHeight / 2 + el.offsetHeight + "px")
);
loop.addEventListener("scroll", () => {
if (virtualLoop.length < 2) return; // not enough items to scroll
const topBound = loop.scrollTop;
const bottomBound = loop.scrollTop + loop.offsetHeight;
const firstEl = virtualLoop[0];
const lastEl = virtualLoop[virtualLoop.length - 1];
if (firstEl.offsetTop >= topBound - offsetBoundary) {
lastEl.style.top = firstEl.offsetTop - lastEl.offsetHeight + "px";
virtualLoop.unshift(lastEl);
virtualLoop.pop();
} else if (
lastEl.offsetTop + lastEl.offsetHeight <
bottomBound + offsetBoundary
) {
firstEl.style.top = lastEl.offsetTop + lastEl.offsetHeight + "px";
virtualLoop.push(firstEl);
virtualLoop.shift();
}
});
}
// the function sets handlers to scrolling for reverse interaction with the linked loop
function reverseLinkLoopHandler(loop) {
loop.addEventListener("scroll", () => {
const delta = lastScrollPos.get(loop) - loop.scrollTop;
lastScrollPos.set(loop, loop.scrollTop);
// this is blocked to prevent deadlock when events of two blocks are called each other.
{
if (scrollLockElement !== null && scrollLockElement !== loop)
return;
scrollLockElement = loop;
clearTimeout(scrollLockTimeout);
scrollLockTimeout = setTimeout(
() => (scrollLockElement = null),
300
);
}
linkedLoops
.get(loop)
.scrollTo(0, linkedLoops.get(loop).scrollTop + delta);
});
}
// set scroll handlers on all loops
linkedLoops.forEach((loop) => {
infiniteScrollHandler(loop);
loop.scrollTo(0, scrollHeight / 2);
lastScrollPos.set(loop, scrollHeight / 2);
reverseLinkLoopHandler(loop);
});
/* Hide Scroll Bars */
::-webkit-scrollbar {
display: none;
}
html,
body {
margin: 0;
padding: 0;
-ms-overflow-style: none;
/* IE and Edge */
scrollbar-width: none;
/* Firefox */
}

/* Basic Styling */
img {
border: 1px solid black;
margin-bottom: 24px;
width: 100%;
max-width: 100%;
}
h2 {
font-size: 14px;
font-weight: normal;
margin-bottom: 4px;
font-family: "Inter", sans-serif;
}
p {
color: black;
font-size: 11px;
font-family: "Inter", sans-serif;
}

/* Content will be in these eventually */
.bar-left,
.bar-right {
border-right: 1px solid black;
box-sizing: border-box;
height: 100vh;
position: fixed;
top: 0;
left: 0;
width: 48px;
z-index: 10000;
}
.bar-right {
border: none;
border-left: 1px solid black;
left: auto;
right: 0;
}

/* Split Loop */
.split-loop {
position: relative;
margin: 0 48px;
}
.split-loop__left {
width: 50%;
overflow: auto;
position: relative;
max-height: 100vh;
}
.split-loop__right:before,
.split-loop__left:before {
display: block;
content: "";
z-index: -1;
height: 9999999px;
}
.split-loop__right {
border-left: 1px solid black;
box-sizing: border-box;
position: fixed;
right: 48px;
bottom: 0;
z-index: 5;
width: calc(50% - 48px);
overflow: auto;
max-height: 100vh;
}
.project {
box-sizing: border-box;
border-bottom: 1px solid black;
height: 600px;
padding: 48px;
position: absolute;
}
.project__media {
/* height: 100px; */
}
<header class="bar-left"></header>
<div class="bar-right"></div>
<div class="view">
<div class="grid split-loop" style="max-height: 100vh">
<div class="split-loop__left">
<div class="grid__item project">
<img src="https://www.fillmurray.com/600/400" alt="" class="project__media" />
<h2 class="project__title">Project Title</h2>
<p class="project__desc">Short Description</p>
</div>
<div class="grid__item project">
<img src="https://www.fillmurray.com/g/600/400" alt="" class="project__media" />
<h2 class="project__title">Project Title</h2>
<p class="project__desc">Short Description</p>
</div>
<div class="grid__item project">
<img src="https://www.fillmurray.com/600/400" alt="" class="project__media" />
<h2 class="project__title">Project Title</h2>
<p class="project__desc">Short Description</p>
</div>
</div>
<div class="split-loop__right">
<div class="grid__item project">
<img src="https://www.fillmurray.com/g/600/400" alt="" class="project__media" />
<h2 class="project__title">Project Title</h2>
<p class="project__desc">Short Description</p>
</div>
<div class="grid__item project">
<img src="https://www.fillmurray.com/600/400" alt="" class="project__media" />
<h2 class="project__title">Project Title</h2>
<p class="project__desc">Short Description</p>
</div>
<div class="grid__item project">
<img src="https://www.fillmurray.com/g/600/400" alt="" class="project__media" />
<h2 class="project__title">Project Title</h2>
<p class="project__desc">Short Description</p>
</div>
</div>
</div>
</div>

最新更新