Here is the desired outcome I'm looking to achieve by scrolling using react-scroll-parallax.
On Mobile browser
I want to create a website with the parallax affect shown above. The key elements being a website build in react containing three pages.
While scrolling from Page 1 to Page 2 I want the mobile device mock to start halfway on the screen (as to avoid the other content of page 1), then move to being basically centered.
While scrolling from Page 2 to Page 3, the website and components stick and once again act like a normal website scroll.
Additionally, during the scroll from Page 1 to Page 2, I want the content inside the device mock to scroll as well.
For starters I was able to get nearly the affect I wanted by using a div with it's z-index and absolute position set, and parallax on translateY of -50, 125
.
<div className={"absolute z-10 w-full"}>
<Parallax translateY={[-50, 125]}></Parallax>
</div>
The problem became however when I wanted to place content inside the div. Having another div within the parallax that also had z-index set seemed to mess with the parallax affect.
One issue I found that was tricky was trying to place the content inside the device mock. I want a parallax both on the device mock itself, and the content within it.
I'm not entirely sure how I should crop the content inside the device mock. The device mock svg frame and device mock mask can be found here if you want to give it a try Device mock svg and mask
I tried imgs with various z-indexes, masking the div with an svg mask, using image backgrounds. Nothing is quite getting the preferred outcome.
I want to make sure this works well on both mobile and browser. With that said I was trying to use margins to scale the device mock but I had a hard time with trying to then correctly get the mask to work for the content within the mock.
I'm not sure if using dedicated width and height sizes would be the ideal way to go, but very open to suggestions! It seems hard to scale the device frame and the mask properly.
I want the content inside the device mock to be html so that I can change it more than just an image. That being said the most important feature I want is for both the device and the content inside to have a parallax scroll affect.
I know this is a bit much for a quick simple stack overflow issue, but I've been trying a lot to get this to work and just can't seem to nail down the little details correctly. I sincerely appreciate all help and suggestions and if there is anything else I can provide please let me know!
The trickier part of the request was blowing up the <svg>
, adding new <path />
and <clipPath />
for the color swap inside the phone mock.
Eventually I got it working here. The part linking the clipPath transition to the scroll progress looks like this:
const [y, setY] = React.useState(1739);
const onProgressChange = React.useCallback(
(a) =>
setY(Math.max(Math.min(1739, 1739 - ((a - 0.24) / 0.0018) * 17), 36)),
[setY]
);
const { ref } = useParallax({
translateY: [0, 185],
onProgressChange
});
The 1739
and 36
are max and min values for the translation and they are strictly related to the svg's viewBox. The other values allow tweaking the start, end and speed of animation, with regards to overall scroll progress.
This, together with some CSS, took care of binding the right animations to the correct scroll progress.
Feel free to tweak it some more, especially if you add more markup.
The other thing I wanted was a function activated shortly after scrolling, which would snap the scroll to certain positions. Namely, to the .page
elements.
I used gsap's ScrollTrigger plugin for the task, for multiple reasons:
There are other libs/plugins out there for the task, you don't have to use gsap
(although I do think it's awesome). If you end up including it in your project, make sure you comply with their licensing (which is not MIT).
By the way, my first choice for the parallax effect per-se would also be gsap
, as their timelines provide a lot of flexibility and options.
Their most advanced stuff is reserved for subscribers, but even if you limit yourself to the free plugins, you're still getting more than from alternative libs/plugins, IMHO.
See it working.