I'm trying to make a parallax effect similar to the hover-over effects on the images on this site:
and here is the code I have so far:
document.querySelectorAll('.image-container').forEach(item => {
const img = item.querySelector('img');
item.addEventListener('mousemove', (e) => {
const rect = item.getBoundingClientRect();
const mouseY = e.clientY - rect.top; // Mouse Y position relative to the item
const halfHeight = rect.height / 2; // Midpoint of the element
const imgHeight = img.height - rect.height
const mousePercentage = mouseY/imgHeight*100
img.style.transform = `translateY(-${mousePercentage}px)`; // Move up
img.style.transition = "transform 0s ease-out"
});
item.addEventListener('mouseleave', () => {
img.style.transform = 'translateY(0)'; // Reset position when mouse leaves
img.style.transition = " transform 2s ease-out"
});
item.addEventListener('mouseenter', () =>{
img.style.transition = "transform 2s ease-out"
})
});
#display-grid{
display: grid;
width: 80%;
gap: 1rem;
grid-template-columns: repeat(auto-fit, minmax(24%, 1fr));
}
.cell{
border: 1px solid #EEEEEE;
border-radius: 1rem;
width: 100%;
overflow-y: hidden;
position: relative;
overflow: hidden;
border-radius: 12px;
aspect-ratio: 1 / 1.2;
}
.cell .image-container{
width: 100%;
height: 90%;
position: relative;
aspect-ratio: 1 / 1;
border-radius: 1rem;
overflow-y: hidden;
}
.cell img {
width: 100%;
height: auto;
object-fit: cover;
object-position: top;
border-radius: 1rem;
}
<div id="display-grid">
<div class="cell">
<div class="image-container">
<img id="website-preview" src=".jpg?scale-down-to=1024">
</div>
<p>Image Title</p>
</div>
<div class="cell">
<div class="image-container">
<img id="website-preview" src=".jpg?scale-down-to=1024">
</div>
<p>InfoSwap</p>
</div>
</div>
I'm trying to make a parallax effect similar to the hover-over effects on the images on this site: https://www.framer/gallery/categories/portfolio
and here is the code I have so far:
document.querySelectorAll('.image-container').forEach(item => {
const img = item.querySelector('img');
item.addEventListener('mousemove', (e) => {
const rect = item.getBoundingClientRect();
const mouseY = e.clientY - rect.top; // Mouse Y position relative to the item
const halfHeight = rect.height / 2; // Midpoint of the element
const imgHeight = img.height - rect.height
const mousePercentage = mouseY/imgHeight*100
img.style.transform = `translateY(-${mousePercentage}px)`; // Move up
img.style.transition = "transform 0s ease-out"
});
item.addEventListener('mouseleave', () => {
img.style.transform = 'translateY(0)'; // Reset position when mouse leaves
img.style.transition = " transform 2s ease-out"
});
item.addEventListener('mouseenter', () =>{
img.style.transition = "transform 2s ease-out"
})
});
#display-grid{
display: grid;
width: 80%;
gap: 1rem;
grid-template-columns: repeat(auto-fit, minmax(24%, 1fr));
}
.cell{
border: 1px solid #EEEEEE;
border-radius: 1rem;
width: 100%;
overflow-y: hidden;
position: relative;
overflow: hidden;
border-radius: 12px;
aspect-ratio: 1 / 1.2;
}
.cell .image-container{
width: 100%;
height: 90%;
position: relative;
aspect-ratio: 1 / 1;
border-radius: 1rem;
overflow-y: hidden;
}
.cell img {
width: 100%;
height: auto;
object-fit: cover;
object-position: top;
border-radius: 1rem;
}
<div id="display-grid">
<div class="cell">
<div class="image-container">
<img id="website-preview" src="https://framerusercontent/images/B7ykrtzOQa5hEXGFIhcq8gyaE.jpg?scale-down-to=1024">
</div>
<p>Image Title</p>
</div>
<div class="cell">
<div class="image-container">
<img id="website-preview" src="https://framerusercontent/images/B7ykrtzOQa5hEXGFIhcq8gyaE.jpg?scale-down-to=1024">
</div>
<p>InfoSwap</p>
</div>
</div>
I have made it as far as having the image scroll within the frame up and down a variable % depending on where the mouse is in the image-container, but I find when the mouse enters the image-container, the image jumps to the coordinates. If I add a transition time to my stylesheet or to the "mousemove" Event Listener, I find the image waits for the mouse to stop moving before slowly moving to where the image needs to be.
What can I do so that the image moves smoothly and consistently on entry, moving, and leaving the container?
Share Improve this question edited Mar 14 at 9:55 Sofiyullahi Olamilekan Jamiu 4074 silver badges11 bronze badges asked Mar 13 at 2:19 SkiddswarmikSkiddswarmik 2701 gold badge2 silver badges14 bronze badges 1- 2 Why do you call this shift effect “parallax”? Even though it has something in common (a very small similarity) and if this is a kind of jargon, this is not parallax. Also, what is the purpose of this shift on hover? What's the point? You can always peek CSS of that size, but... why?! – Sergey A Kryukov Commented Mar 13 at 3:02
1 Answer
Reset to default 2You're close to achieving the same effect seen on the provided site. You just need to change the "mouse move" state part, inside the JavaScript, from this:
img.style.transition = "transform 0s ease-out"
to this:
img.style.transition = "transform 2s ease-out"
Like so:
document.querySelectorAll('.image-container').forEach(item => {
const img = item.querySelector('img');
item.addEventListener('mousemove', (e) => {
const rect = item.getBoundingClientRect();
const mouseY = e.clientY - rect.top; // Mouse Y position relative to the item
const halfHeight = rect.height / 2; // Midpoint of the element
const imgHeight = img.height - rect.height
const mousePercentage = mouseY/imgHeight*100
img.style.transform = `translateY(-${mousePercentage}px)`; // Move up
img.style.transition = "transform 2s ease-out" // this is the changed part
});
item.addEventListener('mouseleave', () => {
img.style.transform = 'translateY(0)'; // Reset position when mouse leaves
img.style.transition = " transform 2s ease-out"
});
item.addEventListener('mouseenter', () =>{
img.style.transition = "transform 2s ease-out"
})
});
#display-grid {
display: grid;
width: 80%;
gap: 1rem;
grid-template-columns: repeat(auto-fit, minmax(24%, 1fr));
}
.cell {
border: 1px solid #EEEEEE;
border-radius: 1rem;
width: 100%;
overflow-y: hidden;
position: relative;
overflow: hidden;
border-radius: 12px;
aspect-ratio: 1 / 1.2;
}
.cell .image-container {
width: 100%;
height: 90%;
position: relative;
aspect-ratio: 1 / 1;
border-radius: 1rem;
overflow-y: hidden;
}
.cell img {
width: 100%;
height: auto;
object-fit: cover;
object-position: top;
border-radius: 1rem;
}
<div id="display-grid">
<div class="cell">
<div class="image-container">
<img id="website-preview" src="https://framerusercontent/images/B7ykrtzOQa5hEXGFIhcq8gyaE.jpg?scale-down-to=1024">
</div>
<p>Image Title</p>
</div>
<div class="cell">
<div class="image-container">
<img id="website-preview" src="https://framerusercontent/images/B7ykrtzOQa5hEXGFIhcq8gyaE.jpg?scale-down-to=1024">
</div>
<p>InfoSwap</p>
</div>
</div>
Known Issue:
Sometimes, when the browser's DevTools is open, the performance throttling kicks in to limit how frequently the mousemove
events are fired, especially if the browser detects excessive rendering work.