构建用于交互式讲故事的滚动条的最简约方法?
Most minimalist way to build a scroller for interactive storytelling?
我正在尝试构建一个静态但响应迅速的讲故事 HTML 网站。我的目标是实现这样的目标:
左边是文字,右边是固定位置的*.jpg图片。当用户滚动左侧的文本时,右侧的图像保持固定位置,但在左侧滚动到某个点后,会更改为另一个 *.jpg 图像并进行短暂的过渡。
在这种情况下响应意味着我完全满意粘性滚动在较小的屏幕上处于非活动状态并且文本和图像块只是返回到它们的正常断点行为。
我研究了各种讲故事和滚动 JavaScript 库(Scrollstory、Waypoints 和 InView)以简单、轻量级和轻松地实现这一目标。对于我正在尝试做的事情,所有这些(到目前为止)似乎都完全过度设计了。
勉强可用的教程和代码片段让我有点像这样的感觉:
我找不到真正的参考资料来告诉我如何从小步骤开始构建滚动条。与图书馆无关。
各个库(具有可访问代码)的参考文件通常已过时,并且专注于使用外部数据可视化框架,并且无论出于何种原因都需要加载多达四个其他外部脚本,并且仍然不提供响应功能。
我已尝试在此处重建此展示示例:https://russellgoldenberg.github.io/scrollama/sticky-side/ because it is at least half of what I want to achieve, but I couldn't get it to work and I don't understand the excessive use of JavaScript there either: https://jsfiddle.net/gdkupcb6/2/
<article>
<div class='step' data-step='1'>
<p>STEP 1</p>
</div>
<div class='step' data-step='2'>
<p>STEP 2</p>
</div>
<div class='step' data-step='3'>
<p>STEP 3</p>
</div>
<div class='step' data-step='4'>
<p>STEP 4</p>
</div>
代码在 HTML 方面看起来很简单,对我来说几乎所有的库都有意义,但是当涉及到 JavsScript 部分时我完全迷失了。为什么这里需要 D3?为什么滚动上的简单更改需要这么多 JS 功能?
我认为有一种极简主义的方法可以在不涉及多个不同的外部脚本和库的情况下实现这种相当简单的粘性滚动,这是完全错误的吗?
有人能给我指出一个好的方向来逐步构建一个滚动条,使我能够理解其中的代码的每一部分,而不是在似乎没有真正意义的复杂外部库和教程的参与下有始无终?
首先,为了让您的代码正常工作,您需要用 main 标记将其包装起来。
// using d3 for convenience
var main = d3.select('main')
var scrolly = main.select('#scrolly');
var figure = scrolly.select('figure');
var article = scrolly.select('article');
var step = article.selectAll('.step');
// initialize the scrollama
var scroller = scrollama();
// generic window resize listener event
function handleResize() {
// 1. update height of step elements
var stepH = Math.floor(window.innerHeight * 0.75);
step.style('height', stepH + 'px');
var figureHeight = window.innerHeight / 2
var figureMarginTop = (window.innerHeight - figureHeight) / 2
figure
.style('height', figureHeight + 'px')
.style('top', figureMarginTop + 'px');
// 3. tell scrollama to update new element dimensions
scroller.resize();
}
// scrollama event handlers
function handleStepEnter(response) {
// response = { element, direction, index }
// add color to current step only
step.classed('is-active', function(d, i) {
return i === response.index;
})
// update graphic based on step
figure.select('p').text(response.index + 1);
}
function setupStickyfill() {
d3.selectAll('.sticky').each(function() {
Stickyfill.add(this);
});
}
function init() {
setupStickyfill();
// 1. force a resize on load to ensure proper dimensions are sent to scrollama
handleResize();
// 2. setup the scroller passing options
// this will also initialize trigger observations
// 3. bind scrollama event handlers (this can be chained like below)
scroller.setup({
step: '#scrolly article .step',
offset: 0.33,
debug: true,
})
.onStepEnter(handleStepEnter)
// setup resize event
window.addEventListener('resize', handleResize);
}
// kick things off
init();
#scrolly {
position: relative;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
background-color: #f3f3f3;
padding: 1rem;
}
#scrolly > * {
-webkit-box-flex: 1;
-ms-flex: 1;
flex: 1;
}
article {
position: relative;
padding: 0 1rem;
max-width: 20rem;
}
figure {
position: -webkit-sticky;
position: sticky;
width: 100%;
margin: 0;
-webkit-transform: translate3d(0, 0, 0);
-moz-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
background-color: #8a8a8a;
}
figure p {
text-align: center;
padding: 1rem;
position: absolute;
top: 50%;
left: 50%;
-moz-transform: translate(-50%, -50%);
-webkit-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
font-size: 8rem;
font-weight: 900;
color: #fff;
}
.step {
margin: 0 auto 2rem auto;
background-color: #3b3b3b;
color: #fff;
}
.step:last-child {
margin-bottom: 0;
}
.step.is-active {
background-color: goldenrod;
color: #3b3b3b;
}
.step p {
text-align: center;
padding: 1rem;
font-size: 1.5rem;
}
<main>
<section id='intro'>
<h1 class='intro__hed'>Sticky Side Example</h1>
<p class='intro__dek'>
Start scrolling to see how it works.
</p>
</section>
<section id='scrolly'>
<article>
<div class='step' data-step='1'>
<p>STEP 1</p>
</div>
<div class='step' data-step='2'>
<p>STEP 2</p>
</div>
<div class='step' data-step='3'>
<p>STEP 3</p>
</div>
<div class='step' data-step='4'>
<p>STEP 4</p>
</div>
</article>
<figure>
<p>0</p>
</figure>
</section>
</main>
<script src="https://unpkg.com/intersection-observer@0.5.1/intersection-observer.js"></script>
<script src="https://unpkg.com/scrollama"></script>
<script src='https://unpkg.com/d3@5.9.1/dist/d3.min.js'></script>
其次,除了使用 javascript 之外,我没有看到任何其他替代解决方案。特别是如果已经有像 scrollama 这样的库可以为您完成工作。
一般情况下,JS代码会让页面更加动态。例如:只有 CSS + HTML 不能根据 div.
的位置改变图像背景
我会在评论中回复您以获取更多信息。我会尽力帮助^^
为此您可以使用 JavaScript - 您添加一个 window.addEventListener("wheel") 或 "scroll" 并在您的 "picture".offsetTop 到达时收听向右滚动位置并将此元素的位置转到 "fixed"。此外,您可以选择添加 "slow motion in" 效果,或者只是尝试图像如何随页面滚动。
你的 jsFiddle 对我不起作用,但我喜欢这个想法所以我在 codepen 上插入了 30 行代码 ---DEMO--- 出于与这个想法类似的目的,它有点笨拙会很乐意接受任何建议来自其他人,但它有效。
当文本块开始和结束时,它会随着页面滚动图像,看起来图像会发生变化(我使用表情符号而不是图像,但想法是一样的)。
它应该会自动缩放到您的屏幕尺寸,同时仍然可以工作,但它未经测试,所以 ..:D
var container = document.getElementById("container");
var stickyImage = document.getElementById("stickyImage");
var tempY;
window.addEventListener("scroll", (e) => {
//watch how image moves with scrolleing
if(window.pageYOffset >= container.offsetTop && window.pageYOffset <= container.offsetTop+container.offsetHeight - window.innerHeight ){
console.log("slinding");
stickyImage.style.position = "fixed";
stickyImage.style.top = "0vh";
stickyImage.style.marginTop = "";
tempY = window.pageYOffset;
}else if(window.pageYOffset <= container.offsetTop){
console.log("top sxcreen");
stickyImage.style.position = "absolute";
stickyImage.style.top = "";
stickyImage.style.marginTop = "";
}else{
console.log("stop");
stickyImage.style.position = "absolute";
stickyImage.style.marginTop = tempY + "px";
}
//change images while scroll
if(window.pageYOffset < document.getElementById("change1").offsetTop){
stickyImage.textContent = "";
}
if(window.pageYOffset > document.getElementById("change1").offsetTop){
stickyImage.textContent = "";
}
if(window.pageYOffset > document.getElementById("change2").offsetTop){
stickyImage.textContent = "";
}
})
我正在尝试构建一个静态但响应迅速的讲故事 HTML 网站。我的目标是实现这样的目标:
左边是文字,右边是固定位置的*.jpg图片。当用户滚动左侧的文本时,右侧的图像保持固定位置,但在左侧滚动到某个点后,会更改为另一个 *.jpg 图像并进行短暂的过渡。
在这种情况下响应意味着我完全满意粘性滚动在较小的屏幕上处于非活动状态并且文本和图像块只是返回到它们的正常断点行为。
我研究了各种讲故事和滚动 JavaScript 库(Scrollstory、Waypoints 和 InView)以简单、轻量级和轻松地实现这一目标。对于我正在尝试做的事情,所有这些(到目前为止)似乎都完全过度设计了。
勉强可用的教程和代码片段让我有点像这样的感觉:
我找不到真正的参考资料来告诉我如何从小步骤开始构建滚动条。与图书馆无关。
各个库(具有可访问代码)的参考文件通常已过时,并且专注于使用外部数据可视化框架,并且无论出于何种原因都需要加载多达四个其他外部脚本,并且仍然不提供响应功能。
我已尝试在此处重建此展示示例:https://russellgoldenberg.github.io/scrollama/sticky-side/ because it is at least half of what I want to achieve, but I couldn't get it to work and I don't understand the excessive use of JavaScript there either: https://jsfiddle.net/gdkupcb6/2/
<article>
<div class='step' data-step='1'>
<p>STEP 1</p>
</div>
<div class='step' data-step='2'>
<p>STEP 2</p>
</div>
<div class='step' data-step='3'>
<p>STEP 3</p>
</div>
<div class='step' data-step='4'>
<p>STEP 4</p>
</div>
代码在 HTML 方面看起来很简单,对我来说几乎所有的库都有意义,但是当涉及到 JavsScript 部分时我完全迷失了。为什么这里需要 D3?为什么滚动上的简单更改需要这么多 JS 功能?
我认为有一种极简主义的方法可以在不涉及多个不同的外部脚本和库的情况下实现这种相当简单的粘性滚动,这是完全错误的吗?
有人能给我指出一个好的方向来逐步构建一个滚动条,使我能够理解其中的代码的每一部分,而不是在似乎没有真正意义的复杂外部库和教程的参与下有始无终?
首先,为了让您的代码正常工作,您需要用 main 标记将其包装起来。
// using d3 for convenience
var main = d3.select('main')
var scrolly = main.select('#scrolly');
var figure = scrolly.select('figure');
var article = scrolly.select('article');
var step = article.selectAll('.step');
// initialize the scrollama
var scroller = scrollama();
// generic window resize listener event
function handleResize() {
// 1. update height of step elements
var stepH = Math.floor(window.innerHeight * 0.75);
step.style('height', stepH + 'px');
var figureHeight = window.innerHeight / 2
var figureMarginTop = (window.innerHeight - figureHeight) / 2
figure
.style('height', figureHeight + 'px')
.style('top', figureMarginTop + 'px');
// 3. tell scrollama to update new element dimensions
scroller.resize();
}
// scrollama event handlers
function handleStepEnter(response) {
// response = { element, direction, index }
// add color to current step only
step.classed('is-active', function(d, i) {
return i === response.index;
})
// update graphic based on step
figure.select('p').text(response.index + 1);
}
function setupStickyfill() {
d3.selectAll('.sticky').each(function() {
Stickyfill.add(this);
});
}
function init() {
setupStickyfill();
// 1. force a resize on load to ensure proper dimensions are sent to scrollama
handleResize();
// 2. setup the scroller passing options
// this will also initialize trigger observations
// 3. bind scrollama event handlers (this can be chained like below)
scroller.setup({
step: '#scrolly article .step',
offset: 0.33,
debug: true,
})
.onStepEnter(handleStepEnter)
// setup resize event
window.addEventListener('resize', handleResize);
}
// kick things off
init();
#scrolly {
position: relative;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
background-color: #f3f3f3;
padding: 1rem;
}
#scrolly > * {
-webkit-box-flex: 1;
-ms-flex: 1;
flex: 1;
}
article {
position: relative;
padding: 0 1rem;
max-width: 20rem;
}
figure {
position: -webkit-sticky;
position: sticky;
width: 100%;
margin: 0;
-webkit-transform: translate3d(0, 0, 0);
-moz-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
background-color: #8a8a8a;
}
figure p {
text-align: center;
padding: 1rem;
position: absolute;
top: 50%;
left: 50%;
-moz-transform: translate(-50%, -50%);
-webkit-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
font-size: 8rem;
font-weight: 900;
color: #fff;
}
.step {
margin: 0 auto 2rem auto;
background-color: #3b3b3b;
color: #fff;
}
.step:last-child {
margin-bottom: 0;
}
.step.is-active {
background-color: goldenrod;
color: #3b3b3b;
}
.step p {
text-align: center;
padding: 1rem;
font-size: 1.5rem;
}
<main>
<section id='intro'>
<h1 class='intro__hed'>Sticky Side Example</h1>
<p class='intro__dek'>
Start scrolling to see how it works.
</p>
</section>
<section id='scrolly'>
<article>
<div class='step' data-step='1'>
<p>STEP 1</p>
</div>
<div class='step' data-step='2'>
<p>STEP 2</p>
</div>
<div class='step' data-step='3'>
<p>STEP 3</p>
</div>
<div class='step' data-step='4'>
<p>STEP 4</p>
</div>
</article>
<figure>
<p>0</p>
</figure>
</section>
</main>
<script src="https://unpkg.com/intersection-observer@0.5.1/intersection-observer.js"></script>
<script src="https://unpkg.com/scrollama"></script>
<script src='https://unpkg.com/d3@5.9.1/dist/d3.min.js'></script>
其次,除了使用 javascript 之外,我没有看到任何其他替代解决方案。特别是如果已经有像 scrollama 这样的库可以为您完成工作。
一般情况下,JS代码会让页面更加动态。例如:只有 CSS + HTML 不能根据 div.
的位置改变图像背景我会在评论中回复您以获取更多信息。我会尽力帮助^^
为此您可以使用 JavaScript - 您添加一个 window.addEventListener("wheel") 或 "scroll" 并在您的 "picture".offsetTop 到达时收听向右滚动位置并将此元素的位置转到 "fixed"。此外,您可以选择添加 "slow motion in" 效果,或者只是尝试图像如何随页面滚动。
你的 jsFiddle 对我不起作用,但我喜欢这个想法所以我在 codepen 上插入了 30 行代码 ---DEMO--- 出于与这个想法类似的目的,它有点笨拙会很乐意接受任何建议来自其他人,但它有效。 当文本块开始和结束时,它会随着页面滚动图像,看起来图像会发生变化(我使用表情符号而不是图像,但想法是一样的)。
它应该会自动缩放到您的屏幕尺寸,同时仍然可以工作,但它未经测试,所以 ..:D
var container = document.getElementById("container");
var stickyImage = document.getElementById("stickyImage");
var tempY;
window.addEventListener("scroll", (e) => {
//watch how image moves with scrolleing
if(window.pageYOffset >= container.offsetTop && window.pageYOffset <= container.offsetTop+container.offsetHeight - window.innerHeight ){
console.log("slinding");
stickyImage.style.position = "fixed";
stickyImage.style.top = "0vh";
stickyImage.style.marginTop = "";
tempY = window.pageYOffset;
}else if(window.pageYOffset <= container.offsetTop){
console.log("top sxcreen");
stickyImage.style.position = "absolute";
stickyImage.style.top = "";
stickyImage.style.marginTop = "";
}else{
console.log("stop");
stickyImage.style.position = "absolute";
stickyImage.style.marginTop = tempY + "px";
}
//change images while scroll
if(window.pageYOffset < document.getElementById("change1").offsetTop){
stickyImage.textContent = "";
}
if(window.pageYOffset > document.getElementById("change1").offsetTop){
stickyImage.textContent = "";
}
if(window.pageYOffset > document.getElementById("change2").offsetTop){
stickyImage.textContent = "";
}
})