1

There have been a number of questions like this one around the internet for dealing with horizontal scrollbars. I've read a lot of them and people explain how to fix this, but I can't find an answer as to why it happens in the first place.

The spec says the following about the hidden overflow value:

This value indicates that the box’s content is clipped to its padding box and that the UA must not provide any scrolling user interface to view the content outside the clipping region, nor allow scrolling by direct intervention of the user, such as dragging on a touch screen or using the scrolling wheel on a mouse. However, the content must still be scrollable programatically, for example using the mechanisms defined in [CSSOM-VIEW], and the box is therefore still a scroll container.

I've made this very simple page that deliberately has overflowing content and overflow-x: hidden on the <body>:

<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body style="overflow-x: hidden">
    <div style="width: 150%">
        <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec maximus magna odio, vel eleifend nulla
            ullamcorper eget. Nulla vel mi facilisis, facilisis mi non, lacinia libero. Cras eros orci, tristique id
            orci et, finibus convallis libero. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per
            inceptos himenaeos. Quisque vehicula mauris at ex placerat fermentum sed eget erat. Nulla eleifend sodales
            dolor, ac luctus eros malesuada et. Sed ut lobortis eros. Vestibulum eget tortor nibh. Mauris vulputate
            sapien id faucibus molestie. Proin commodo efficitur purus, vitae auctor libero luctus eu. Donec nec ipsum
            libero. Duis tincidunt dapibus ex, vel facilisis sapien interdum id.</p>

        <p>Nunc faucibus, velit at aliquet condimentum, felis urna tristique sapien, sed volutpat nibh turpis nec dolor.
            Sed feugiat at justo eget auctor. Cras pellentesque dapibus orci non egestas. Nulla pulvinar rhoncus nulla
            vel tempus. Sed id ultrices nisi. Cras sit amet augue eget tellus convallis condimentum a non massa. Ut a
            justo in felis interdum tempus vitae vitae orci. Praesent efficitur mi dui, quis porttitor tellus
            pellentesque suscipit. In posuere volutpat scelerisque. Donec semper sapien at elit egestas, sit amet
            fringilla risus ultricies. Maecenas congue posuere velit, eu tristique metus cursus quis. In urna lorem,
            mollis non quam ac, consectetur laoreet ante.</p>

        <p>Pellentesque nec sem pellentesque, interdum dui id, pretium ipsum. Aenean at augue placerat, rutrum mauris
            quis, vehicula nibh. Vestibulum at augue mi. Sed laoreet enim et augue dapibus vestibulum. Curabitur
            pellentesque dignissim ante quis elementum. Phasellus pretium tortor molestie libero tincidunt eleifend vel
            sed mi. Interdum et malesuada fames ac ante ipsum primis in faucibus. Nunc eu finibus dui, non mattis
            sapien. Pellentesque at tortor lacus. Donec enim nulla, lacinia a risus id, congue sollicitudin dolor. Fusce
            non imperdiet magna. Nunc vehicula scelerisque aliquet. Mauris pellentesque quis enim vitae finibus.</p>

        <p>Nulla facilisi. Maecenas vitae ipsum quam. Cras eleifend facilisis dolor vel blandit. Praesent commodo ex
            arcu, id varius felis condimentum et. Nulla lobortis, augue ut ultricies tincidunt, dolor dui tristique
            libero, nec lacinia tellus nunc ut risus. Phasellus et egestas arcu. Vestibulum lobortis vel erat sit amet
            fringilla. Proin fringilla urna libero, eget cursus sem laoreet sed. Nunc vitae mauris et elit mollis
            volutpat eu eget velit. Mauris fringilla viverra ex, nec ornare arcu consequat id. Cras sed erat elit.
            Mauris euismod, sapien eu iaculis finibus, massa risus convallis eros, sit amet lacinia lacus velit
            elementum arcu. Etiam ut lacus convallis, euismod enim eu, bibendum libero.</p>

        <p>Maecenas auctor sapien auctor lobortis auctor. Praesent vel lacus dictum, rutrum dui vitae, vehicula arcu.
            Aenean sapien ante, dignissim ut lacinia quis, interdum faucibus lacus. Mauris facilisis dolor non orci
            interdum, eget suscipit orci cursus. Quisque a eros quam. Etiam tempor nisi vel iaculis luctus. Fusce sit
            amet pellentesque erat. In lorem mi, mattis ut maximus semper, efficitur eget eros. Suspendisse ac nulla
            tincidunt enim tincidunt convallis sit amet ac nisl. In eu magna libero. Aliquam erat volutpat. In egestas
            sit amet mauris a rhoncus. Aliquam aliquet mauris nec venenatis dignissim. Aenean faucibus tortor vitae
            lacus malesuada, id fringilla nunc tincidunt.</p>
    </div>
</body>

</html>

...and on desktop, the horizontal scrollbar is correctly hidden:

horizontal scrollbar on desktop

However, on a mobile device, you can scroll the content:

scrollbar on mobile

You even get a scrollbar in DevTools when viewing the page in "Mobile" mode:

scrollbar in mobile devtools


The question is why? I have the meta viewport tag in the page:

<meta name="viewport" content="width=device-width, initial-scale=1.0">

...which is a hint that the page is mobile-friendly. Therefore if I have overflow-x: hidden, I mean it. Why doesn't the browser respect that?

I know I can get around this by wrapping the entire page in a <div> element, for example, and setting overflow-x: hidden on that instead. But if I have a position: sticky element somewhere in the content, it would no longer work because it sticks to its scroll container, which is the wrapper element, and the actual scroll happens on the body. Or, if I also set overflow-y: auto on the wrapper, the sticky element will work as expected, but now all the JavaScript will break because it uses document.scrollingElement, and the actual scrolling element is this wrapper.

So getting around this can be tricky, and I don't understand why we need those hacks. To me, it appears that browsers fail to implement the spec correctly.

dodov
  • 5,206
  • 3
  • 34
  • 65

1 Answers1

0

<meta name="viewport" content="width=device-width, initial-scale=1.0">

When setting the ViewPort on a HTML document in the above manner, the initial-scale=1.0 sets the initial zoom level when the page is first loaded by the browser.

Given that when that level of zoom is applied to the page, whilst that particular div is not overflowing, the html and the body are because you set the width of the div to 150%.

That ViewPort scale is essentially changing a reference point rather than behaviour in regards to this specific case.

You also set the width=device-width property which assigns the page width to follow the screen-width of the device (which is going to vary depending on the device) which acts as another reference point to 'scale elements' (page layout).

The reason the overflow isn't working as intended is that it is applied to a div, correctly, so that the content is behaving as expected except for when the now re-sized html/body has expanded from the reference in size to the device-width and scale so that they then overflow the ViewPort.

To overcome this you can adapt your <meta> tag to this:

<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">

This fixes the issue because minimum-scale determines how far out you can zoom, this prevents the 'interference' from initial-scale regarding the expected outcome given that the scaling 'dimensions of the page' are now locked to the ViewPort as you see it physically with the appropriate scale of whatever the initial was set to.

  • This appears to prevent scrolling in DevTools, but on an actual device (testing iPhone X Safari with BrowserStack), it still doesn't work. – dodov May 07 '20 at 05:10