I'm working on a feature where I need to scroll to a specific element in my React app, but I want to prevent it from scrolling into the notch area on devices with a notch (iOS/Android). The idea is to make sure the scroll doesn't overlap with the "safe area" where the notch or system UI is located.
I have two versions of the scroll function: the initial version, which scrolls directly to the target, and a refactored version that attempts to adjust for the safe area using paddingTop from the app-bar element. However, my refactored solution is not working as expected. It still scrolls into the notch area on devices with one.
Here’s the code I have:
export const scrollToDiv = (htmlRef: RefObject<HTMLDivElement>, location: 'start' | 'nearest' | 'center' | 'end', behavior: 'auto' | 'smooth') => {
setTimeout(() => {
if (htmlRef?.current) {
htmlRef.current.scrollIntoView({
block: location,
behavior: behavior,
});
}
}, 200);
};
I'm working on a feature where I need to scroll to a specific element in my React app, but I want to prevent it from scrolling into the notch area on devices with a notch (iOS/Android). The idea is to make sure the scroll doesn't overlap with the "safe area" where the notch or system UI is located.
I have two versions of the scroll function: the initial version, which scrolls directly to the target, and a refactored version that attempts to adjust for the safe area using paddingTop from the app-bar element. However, my refactored solution is not working as expected. It still scrolls into the notch area on devices with one.
Here’s the code I have:
export const scrollToDiv = (htmlRef: RefObject<HTMLDivElement>, location: 'start' | 'nearest' | 'center' | 'end', behavior: 'auto' | 'smooth') => {
setTimeout(() => {
if (htmlRef?.current) {
htmlRef.current.scrollIntoView({
block: location,
behavior: behavior,
});
}
}, 200);
};
export const scrollToDiv = (htmlRef: RefObject<HTMLDivElement>, location: 'start' | 'nearest' | 'center' | 'end', behavior: 'auto' | 'smooth') => {
setTimeout(() => {
if (htmlRef?.current) {
const element = htmlRef.current;
const elementRect = element.getBoundingClientRect();
// Safely get the app-bar element
const appBar = document.getElementById('app-bar');
// If the app-bar exists, get its padding-top; otherwise, default to 0
const safeAreaTop = appBar ? parseInt(getComputedStyle(appBar).paddingTop) || 0 : 0;
// Adjust the scroll to ensure the element is visible and doesn't overlap the safe area
const adjustedTop = Math.max(elementRect.top - safeAreaTop, 0);
// Scroll to the adjusted position, ensuring the element is fully visible above the safe area
window.scroll({
top: adjustedTop + window.scrollY, // This ensures we're considering the current scroll position
behavior: behavior,
});
}
}, 200);
};
Share
Improve this question
asked Mar 22 at 23:36
RichardsonRichardson
2,3141 gold badge24 silver badges62 bronze badges
1 Answer
Reset to default 1The issue you’re facing occurs because the notch or safe area inset is not necessarily the same as the padding-top
of your app bar. Instead, modern browsers on iOS/Android expose these safe areas using CSS environment variables like env(safe-area-inset-top)
.
Use env(safe-area-inset-top)
in your CSS
Make sure your app bar or body element uses this safe area inset:
#app-bar {
padding-top: env(safe-area-inset-top, 0px);
}
The fallback
0px
ensures it works on devices without a notch. read more about this here
Adjust the scroll by reading the safe area inset from the computed style
In JavaScript, reading
env(safe-area-inset-top)
directly isn’t supported.
A reliable workaround is:
- Add the inset via CSS on a known element (like
#app-bar
or<body>
). - Parse the value from the computed style.
Here’s a corrected scroll function that accounts for both app-bar height and the safe area inset:
export const scrollToDiv = (
htmlRef: RefObject<HTMLDivElement>,
location: ScrollLogicalPosition = 'start',
behavior: ScrollBehavior = 'smooth'
) => {
setTimeout(() => {
if (htmlRef?.current) {
const element = htmlRef.current;
const elementRect = element.getBoundingClientRect();
const appBar = document.getElementById('app-bar');
// Get both appBar height and safe-area-inset-top (if available)
const appBarStyles = appBar ? getComputedStyle(appBar) : null;
const appBarHeight = appBar ? appBar.getBoundingClientRect().height : 0;
const safeAreaInsetTop = appBarStyles
? parseInt(appBarStyles.paddingTop.replace('px', '')) || 0
: 0;
// Calculate final offset
const offset = appBarHeight + safeAreaInsetTop;
// Scroll to the adjusted position
window.scrollTo({
top: window.scrollY + elementRect.top - offset,
behavior: behavior,
});
}
}, 200);
};
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744300957a4567498.html
评论列表(0条)