The link you provided showcases a beautiful page design, prompting me to take the time to create something that closely resembles it in comparison to other responses.
- I implemented a functioning transition similar to that on franshalsmuseum.nl.
- I ensured that the page is responsive to resizing:
- All panes and images adjust relative to each other,
- Scroll steps are in relation to page height,
- Images utilize
<div>
with background-image
instead of the <img>
tag. They are slightly cropped based on window size changes to accommodate varying aspect ratios.
- I made changing the number of image sets simple. While it could be enhanced by creating HTML elements in JavaScript, this isn't necessary for the original page.
Functionality Overview
HTML
Images are enclosed in special wrapper elements (.img-wrapper
) to handle appropriate sizing and positioning (notably position: relative
). Each image element is assigned a URL (as background image) and an image set number for use in JavaScript:
<div class="img visible" data-imageset="1"
style="background-image: url('http://placeimg.com/640/480/people');">
</div>
The class visible displays image set 1 initially.
CSS
Key definitions include these (and similar ones for #bottom-image
). The image container having overflow: hidden
allows us to hide the image by moving it out of viewable area. Setting the coordinates back triggers a smooth transition effect causing the image to slide back into place.
/* hiding images in #top-image */
#left-pane #top-image .img {
top: 100%;
}
#left-pane #top-image .img.visible {
top: 0;
}
JS
The JavaScript code is minimal with just one interaction line with the DOM. It utilizes some clever tricks which may not be immediately evident, hence the inclusion of links to relevant documentation:
document
.querySelectorAll
('#left-pane .img')
.forEach
((img)
=>
{
img
.classList
.toggle
('visible'
, img
.dataset
.imageset
<=
currentSet
);
}
This script locates all images and toggles the class visible
based on the image's data-imageset
attribute.
Complete Code Snippet with Demo
Refer to the snippet below. For optimal viewing, click the "Full page" option after running the snippet.
let currentSet = 1;
function updateSelectedImgSet() {
const currentScroll = document.scrollingElement.scrollTop;
const scrollMax = document.scrollingElement.scrollHeight - document.scrollingElement.clientHeight;
const setsCount = 3;
const scrollPerSet = scrollMax / setsCount;
const scrolledSet = Math.floor(currentScroll / scrollPerSet) + 1;
if (scrolledSet == currentSet) {
return;
}
currentSet = scrolledSet;
document.querySelectorAll('#left-pane .img').forEach((img) => {
img.classList.toggle('visible', img.dataset.imageset <= currentSet);
});
}
window.onscroll = updateSelectedImgSet;
window.onresize = updateSelectedImgSet;
/* Left pane, fixed */
#left-pane {
position: fixed;
height: 100%;
width: 40vw;
}
#left-pane .img-wrapper {
position: relative;
height: 50%;
width: 100%;
overflow: hidden;
}
#left-pane .img-wrapper .img {
position: absolute;
width: 100%;
height: 100%;
/* Sizing and cropping of image */
background-position: center;
background-size: cover;
/* Transition - the slow sliding of images */
transition: 0.5s all ease-in-out;
}
/* hiding images in #top-image */
#left-pane #top-image .img {
top: 100%;
}
#left-pane #top-image .img.visible {
top: 0;
}
/* hiding images in #bottom-image */
#left-pane #bottom-image .img {
bottom: 100%;
}
#left-pane #bottom-image .img.visible {
bottom: 0;
}
/* Right pane, scrolling with the page */
#right-pane {
margin-left: 40vw;
}
.scrollable-content {
font-size: 40vw;
writing-mode: vertical-rl;
white-space: nowrap;
}
<div id="left-pane">
<div id="top-image" class="img-wrapper">
<div class="img visible" data-imageset="1"
style="background-image: url('http://placeimg.com/640/480/people');">
</div>
<div class="img" data-imageset="2"
style="background-image: url('http://placeimg.com/640/480/animals');">
</div>
<div class="img" data-imageset="3"
style="background-image: url('http://placeimg.com/640/480/any');">
</div>
</div>
<div id="bottom-image" class="img-wrapper">
<div class="img visible" data-imageset="1"
style="background-image: url('http://placeimg.com/640/480/nature');">
</div>
<div class="img" data-imageset="2"
style="background-image: url('http://placeimg.com/640/480/tech');">
</div>
<div class="img" data-imageset="3"
style="background-image: url('http://placeimg.com/640/480/arch');">
</div>
</div>
</div>
<div id="right-pane">
<div class="scrollable-content">Scrollable content!</div>
</div>