How to Fix a Website That Won’t Scroll
Find out why a website will not scroll, then fix browser settings, overlays, CSS overflow, nested panels, and mobile layout problems.
Start by opening the same URL in another browser. If it scrolls there, the problem is local to your original browser: an extension, cached site data, blocked JavaScript, privacy setting, zoom, or modified preference. If it fails in every browser, inspect the site’s CSS, JavaScript, overlays, and scroll containers.
This guide covers both sides of the problem: quick fixes for visitors and a complete debugging path for developers who own the site.
1. Identify whether the browser or website is at fault
- Copy the page URL.
- Open it in a private or incognito window.
- Open the same URL in a second browser.
- Try both the mouse wheel and the scrollbar. On mobile, try a touch swipe and an external keyboard if available.
- Record whether the whole page, an inner panel, or a modal is supposed to scroll.
| What you observe | Most likely scope | Next action |
|---|---|---|
| Works in a private window | Extension or stored site data | Disable extensions and clear data for this site |
| Works in another browser | Original browser settings or compatibility | Check JavaScript, privacy settings, zoom, and extensions |
| Fails in every browser | Website CSS, JavaScript, or overlay | Inspect overflow, dimensions, and pointer interception |
| Only one panel should scroll | Nested scroll container | Give that panel a usable height and overflow-y:auto |
| Desktop works but mobile fails | Viewport, touch, or mobile layout | Reproduce at several viewport sizes and browsers |
2. Quick fixes for visitors
Reload, then use a private window
Reload the page first. A private window is a fast isolation test because it normally starts without your regular extensions and most existing site data. If scrolling works there, return to the normal window and continue with the steps below.
Clear cookies and site data for the affected site
Delete data for the specific domain instead of clearing your entire browser history. This can sign you out and remove saved preferences, but it is reversible if you can sign in again. Reload after deleting the data.
Disable extensions one at a time
Start with ad blockers, privacy tools, script blockers, reader modes, custom style tools, and appearance extensions. Test after each change so you know which extension caused the conflict. Re-enable unrelated extensions when you finish.
Check JavaScript and page preferences
- Make sure JavaScript is allowed for the site.
- Reset unusual zoom levels to 100%.
- Check that a minimum-font-size or custom page-style setting is not changing the layout.
- Temporarily relax a privacy setting that blocks required scripts, then test again.
Test another browser and device
Mozilla recommends testing a website in another browser to determine whether the problem is specific to Firefox. The same comparison works for Chrome, Safari, Edge, and mobile browsers: if the failure follows the browser, investigate local settings; if it follows the URL, investigate the site.
3. Diagnose the page with developer tools
When you own the site, use the browser inspector to find the element that should move. In the Elements panel, select html, body, the application shell, modal wrappers, and the visible content panel. In the Computed styles panel, inspect:
overflow,overflow-x, andoverflow-yheight,max-height,block-size, andinline-sizeposition: fixedandposition: sticky- large overlays, pseudo-elements, and elements with a high
z-index
MDN documents how overflow interacts with constrained dimensions such as height and width. A fixed-height wrapper combined with overflow:hidden or overflow:clip can hide content or move scrolling to an unexpected ancestor.
Compare scroll height with client height
Select the suspected scrolling element, then run this in the DevTools console:
const el = $0;
({
tag: el.tagName,
className: el.className,
scrollHeight: el.scrollHeight,
clientHeight: el.clientHeight,
scrollWidth: el.scrollWidth,
clientWidth: el.clientWidth,
overflowY: getComputedStyle(el).overflowY
});
If scrollHeight is equal to clientHeight, that element has no vertical overflow. Inspect its children and ancestors. If scrollHeight is larger but the wheel does nothing, look for an overlay intercepting input and confirm that this is the element receiving the scroll.
Find every element that can scroll
[...document.querySelectorAll('*')]
.filter(el => el.scrollHeight > el.clientHeight)
.map(el => ({
el,
scrollHeight: el.scrollHeight,
clientHeight: el.clientHeight,
overflowY: getComputedStyle(el).overflowY
}));
Use the returned elements in the Elements panel. A page may have a scrolling app shell while body itself stays fixed.
4. Fix common CSS causes
Remove accidental clipping from the page shell
This pattern often prevents the document from growing:
html, body {
height: 100%;
overflow: hidden;
}
.app {
height: 100vh;
overflow: hidden;
}
If the whole document should scroll, allow the document to overflow and avoid locking the shell to the viewport:
html, body {
min-height: 100%;
overflow-x: hidden;
overflow-y: auto;
}
.app {
min-height: 100vh;
}
Use overflow-x:hidden carefully: it can affect the page’s overflow model. Verify the result in current Chrome, Firefox, and Safari.
Make an intentional nested panel scroll
A nested panel needs a constrained height and a vertical overflow rule. Every flex ancestor between the viewport and the panel must also be allowed to shrink.
.app {
min-height: 100vh;
display: flex;
flex-direction: column;
}
.content {
min-height: 0;
flex: 1 1 auto;
display: flex;
}
.results {
min-height: 0;
overflow-y: auto;
overscroll-behavior: contain;
}
Without min-height:0, a flex child can refuse to shrink and prevent its overflow area from behaving as expected.
Check overlays, modals, and pointer interception
A transparent or invisible element can cover the page and consume wheel or touch events. In DevTools, temporarily disable suspicious fixed-position elements, cookie dialogs, chat launchers, and full-screen backdrops. If scrolling returns, fix the overlay’s size, stacking order, or pointer behavior.
.backdrop[aria-hidden="true"] {
display: none;
}
.dismissed-widget {
pointer-events: none;
}
Do not apply pointer-events:none to an element that must remain interactive. Remove the overlay from the layout when it is closed whenever possible.
Inspect fixed and sticky elements
position:fixed elements are attached to the viewport and can cover content. Sticky elements depend on their nearest scrolling ancestor and can behave differently when an ancestor has overflow set. Temporarily disable sticky headers and fixed toolbars to see whether they are hiding the scrollbar or content.
Check horizontal overflow
A wide child can create an unexpected horizontal scrolling region, especially on mobile. Inspect long URLs, images, code blocks, tables, and elements using width:100vw. Prefer:
img, video, canvas, iframe {
max-width: 100%;
}
pre, code {
overflow-wrap: anywhere;
}
.table-wrap {
overflow-x: auto;
}
5. JavaScript and application-state failures
Single-page applications often lock the document while a drawer, dialog, or route transition is active. Search your code for assignments to document.body.style.overflow, classes such as no-scroll, and wheel or touch handlers that call preventDefault().
function setScrollLock(locked) {
document.documentElement.classList.toggle('scroll-locked', locked);
}
// Call setScrollLock(false) when the modal, drawer, or loading state closes.
.scroll-locked {
overflow: hidden;
}
Make sure every open action has a matching close path, including Escape, browser back navigation, route changes, failed network requests, and component unmounts. In the console, check for runtime errors that stop the code responsible for removing a scroll lock.
6. Mobile-specific checks
- Reproduce at more than one viewport width and height.
- Test Safari and Chrome on the affected mobile operating system.
- Check whether the body or an inner panel is supposed to scroll.
- Test a touch swipe, scrollbar drag, and keyboard navigation where available.
- Inspect fixed footers, address-bar viewport changes, dialogs, and horizontal overflow.
Record the browser name and version, operating system, URL, viewport, expected scrolling region, and input method. A failure limited to one browser suggests settings or compatibility. A failure that follows the URL suggests site CSS, JavaScript, or an overlay.
7. Troubleshooting checklist
| Symptom | Cause to check | Fix |
|---|---|---|
| Scrollbar is missing everywhere | html, body, or shell uses overflow:hidden |
Remove the lock or give the intended panel a height and overflow-y:auto |
| Scrollbar exists but wheel does nothing | Overlay intercepts pointer input | Disable the overlay and correct its stacking or pointer behavior |
| Panel content is cut off | Fixed height or overflow:clip |
Relax the constraint or make that panel the scrolling element |
| Only touch scrolling fails | Touch handler calls preventDefault() or wrong nested container |
Review touch listeners and test the actual scroll owner |
| Only one browser fails | Extension, cached data, blocked script, or browser-specific CSS | Use private mode, clear site data, disable extensions, and compare browsers |
| Works until a modal opens | Scroll lock is not removed | Clean up the lock on every close and unmount path |
| Works on desktop, fails on mobile | Viewport or fixed-position layout issue | Test mobile browsers and inspect fixed elements and overflow at small widths |
8. Performance, reliability, and accessibility
- Keep one clear primary scrolling region where possible. Multiple nested regions are harder to discover with a mouse, touch, and keyboard.
- Do not hide overflow merely to suppress a horizontal scrollbar; fix the overflowing child.
- Preserve keyboard access. Users must be able to reach a scrollable panel with Tab and move through it with arrow keys or Page Down.
- Give dialogs a focus trap and a reliable close path, then restore the previous scroll position when appropriate.
- Test with zoom, large text, reduced motion, touch, and keyboard input.
- When debugging intermittent failures, capture console errors and note whether a late-loading widget changes
bodyclasses or styles.
9. Or skip the browser setup
If your goal is to capture a page while debugging a scrolling issue, ScreenshotNeo provides a single GET request for a PNG, JPEG, WebP, or PDF. Its capture flow can accept cookie and consent banners before removing more than 60 known consent platforms, newsletter popups, and chat widgets; each step can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits cost nothing, and the response reports the result with X-Page-Verdict and X-Billed headers.
See the ScreenshotNeo API documentation for all options, including full-page capture, CSS selectors, device presets, custom headers and cookies, waits, request blocking, caching, signed links, asynchronous jobs, bulk capture, and PDF settings.
cURL
curl -G "https://api.screenshotneo.com/v1/shot" \
-d access_key=YOUR_API_KEY \
--data-urlencode url=https://example.com \
-o shot.webp
Python
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://example.com"},
timeout=90,
)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)
Node.js
const q = new URLSearchParams({
access_key: 'YOUR_API_KEY',
url: 'https://example.com'
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const body = Buffer.from(await res.arrayBuffer());
require('fs').writeFileSync('shot.webp', body);
ScreenshotNeo also includes an MCP server with take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients. The Free plan includes 1,000 shots per month with no card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.
10. FAQ
Why does scrolling work in incognito but not normally?
An extension or stored site setting is changing the page. Disable extensions one by one, then clear data for the affected domain.
How do I know which element owns scrolling?
Use the console snippet in this guide and compare scrollHeight with clientHeight. The element whose content is taller than its visible box is a candidate.
Should I use overflow:scroll or overflow:auto?
Use auto when you want a scrollbar only when content overflows. Use scroll when a persistent scrollbar is part of the design.
Why does a fixed header make the page look unscrollable?
A fixed header can cover the top of the content or an invisible backdrop can intercept input. Temporarily disable it and inspect its size, stacking order, and pointer behavior.
Can a browser zoom setting cause this?
Yes. Zoom and minimum-font settings can change dimensions enough to expose clipping or create an unexpected nested scroll area. Reset zoom and test again.


