Upon entering the website, the initial UI that greets you can be seen here: https://i.sstatic.net/Z3eIl.png
As you scroll down to the very beginning of section B
I anticipate that section B will stick in place and the state of currentPercentage
will gradually increase from 0% as you continue scrolling.
https://i.sstatic.net/LVfba.png
Once the currentPercentage
reaches 100%, the sticky effect on section B will cease, allowing you to scroll down to section C or to the bottom of the page.
https://i.sstatic.net/2BlE1.png
This functionality is reminiscent of the homepage of circle-ci.
You are invited to experiment with scrolling within this particular section.
https://i.sstatic.net/t6uV2.png
I believe there are a few key aspects that need to be addressed in order to find a solution:
- How to make section B stick when the scroll position reaches it
- How to trigger the percentage increase while reaching section B through scrolling
After attempting different approaches using CSS and JavaScript, a viable solution has yet to be found.
Extensive research has been conducted for several days to tackle this issue without success thus far.
There seems to be a lack of information available regarding handling such UX elements, which is why providing a quick solution would benefit fellow developers dealing with similar challenges in the frontend.
Any help in answering this question with an example would be greatly appreciated and serve as a valuable reference for other developers.
App.js
import "./styles.css";
import "bootstrap/dist/css/bootstrap.min.css";
import ProgressBar from "react-bootstrap/ProgressBar";
import { useState } from "react";
export default function App() {
const [currentProgress, setCurrentProgress] = useState(100);
return (
<div className="App">
<div className="sectionA">Section A</div>
<div className="sectionB">
Section B
<ProgressBar
now={currentProgress}
label={`${currentProgress}%`}
style={{ marginBottom: "16px" }}
/>
</div>
<div className="sectionC">Section C</div>
</div>
);
}
Codesandbox
https://codesandbox.io/s/mutable-fire-sz19b?file=/src/App.js:0-619
Update 1
The code has been updated to achieve the sticky behavior for container B, but further steps remain elusive.
App.js
import "./styles.css";
import "bootstrap/dist/css/bootstrap.min.css";
import ProgressBar from "react-bootstrap/ProgressBar";
import { useState } from "react";
export default function App() {
const [currentProgress, setCurrentProgress] = useState(3);
return (
<div className="App">
<div className="sectionA">Section A</div>
<div style={{ position: "sticky", top: 0 }}>
<div className="sectionB">
Section B
<ProgressBar
now={currentProgress}
label={`${currentProgress}%`}
style={{ marginBottom: "16px" }}
/>
</div>
<div className="sectionC">Section C</div>
</div>
<div style={{ minHeight: "400vh", maxHeight: "calc(200vh - 466px)" }} />
</div>
);
}
Codesandbox
https://codesandbox.io/s/elated-hawking-n3rvw?file=/src/App.js:0-778
Update 2
Integration of the library react-scroll-percentage
will allow scrolling to update the currentProgress
Nonetheless, the current implementation updates the currentProgress
once the entire container B is visible in the viewport, contrary to the intended behavior.
https://i.sstatic.net/9L6g1.png
The desired outcome is for the scrolling to initiate the sticky feeling when Section B reaches the top of the viewport and subsequently start updating the currentProgress
from 0%.
App.js
import "./styles.css";
import "bootstrap/dist/css/bootstrap.min.css";
import React, { useState, useEffect } from "react";
import { useScrollPercentage } from "react-scroll-percentage";
import ProgressBar from "react-bootstrap/ProgressBar";
export default function App() {
const [currentProgress, setCurrentProgress] = useState(0);
const [ref, percentage] = useScrollPercentage({
threshold: 1.0
});
useEffect(() => {
setCurrentProgress(percentage * 100);
}, [percentage]);
return (
<div className="App">
<div className="sectionA">Section A</div>
<div style={{ position: "sticky", top: 0 }}>
<div className="sectionB" ref={ref}>
Section B
<ProgressBar
now={currentProgress}
label={`(${currentProgress})%`}
style={{ marginBottom: "16px" }}
/>
</div>
<div className="sectionC">Section C</div>
</div>
<div style={{ minHeight: "400vh", maxHeight: "calc(200vh - 466px)" }} />
</div>
);
}
Codesandbox
https://codesandbox.io/s/elated-hawking-n3rvw?file=/src/App.js:0-1029