154

Does overflow:hidden applied to <body> work on iPhone Safari? It seems not. I can't create a wrapper on the whole website to achieve that...

Do you know the solution?

Example: I have a long page, and simply I want to hide the content that goes underneath the "fold", and it should work on iPhone/iPad.

Ian Kemp
  • 28,293
  • 19
  • 112
  • 138
Francesco
  • 24,839
  • 29
  • 105
  • 152

18 Answers18

138

I had a similar issue and found that applying overflow: hidden; to both html and body solved my problem.

html,
body {
    overflow: hidden;
} 

For iOS 9, you may need to use this instead: (Thanks chaenu!)

html,
body {
    overflow: hidden;
    position: relative;
    height: 100%;
}
Alex Haas
  • 2,127
  • 2
  • 17
  • 13
  • 17
    This doesn't work on iOS Safari. position: relative is also necessary. – Kevin Borders Mar 28 '14 at 20:22
  • 5
    Yes add both relative and overflow to html + body – wutang Jul 05 '14 at 00:42
  • 4
    this does not work on iOS 9, even using position relative on body and html – CJT3 Dec 13 '15 at 01:59
  • @CharlesJohnThompsonIII - verifiable and is there a workaround? – tremor Dec 30 '15 at 20:35
  • I could solve my issue today on iOS 9 with adding height: 100%; -> http://stackoverflow.com/a/34659821/1384441 – chaenu Jan 07 '16 at 16:08
  • I've updated my answer above for iOS 9. Thanks guys. – Alex Haas Jan 08 '16 at 18:44
  • 1
    A word of warning, overflow hidden on the tag will break jQuery's scroll event – Brett Gregson Apr 13 '16 at 14:43
  • 2016: height: 100% is making vertical scrolling not smooth; is better to remove it. – suz Jul 13 '16 at 19:57
  • 2
    This doesn't work for me on iOS 9, Safari. Body still scrollable, also after adding `position: relative`. – Edo Apr 19 '17 at 08:20
  • 1
    @Edo I finally got it by doing position: fixed + overflow hidden on body instead of relative. Hope this helps. – Matt Jun 18 '17 at 06:56
  • 1
    @Matt IIRC we also ran `position: fixed` for some time, but the downside is that that resets the scroll position. – Edo Jun 26 '17 at 10:47
  • 1
    `height: 100%` on both `html` and `body` fixed it for me on iOS 11.4. – kmgdev Jun 07 '18 at 19:14
  • 1
    Any updates to this answer? The answer doesn't work for me, even with `position: relative`. – Arnav Borborah Sep 17 '19 at 21:15
  • @AlexHaas Neither position:relative nor height:100% works in IOS.. I wanted to stop body scroll when dragging an element in mobile . overflow:hidden works perfectly in Android phones. Is there any work around to solve this – monisha Mar 24 '20 at 10:43
  • 9
    safari is the new ie11 – funky-nd Nov 02 '21 at 07:40
  • 3
    It's crazy, isn't it? 10 years ago, `-webkit-` was so good, so far ahead of the pack that everbody wanted to be `-webkit-`. Now, in 2022, Apple has dropped the ball _so_ badly on supporting the web that there literally has not been one month this year when I haven't come across _yet another issue_ where all other browsers work and Safari breaks. With the financial resources that Apple has, they should be utterly ashamed of the poor state of their web product. – Rounin Aug 15 '22 at 10:08
98
body {
  position:relative; // that's it
  overflow:hidden;
}
Vian Esterhuizen
  • 3,788
  • 4
  • 27
  • 37
laFunk
  • 1,005
  • 7
  • 3
  • 4
    THANK. YOU. I had a big issue when elements being transitioned from outside the viewport, to inside. There would occur a strange bug where the content got extended. This was the solution for me! – Eric Jul 27 '14 at 13:30
  • 57
    In my case adding "position: relative" didn't help but adding "position: fixed" worked. – LeastOne Mar 11 '15 at 15:21
  • 1
    Yip this worked. I'm building a site where they want the mobile nav to go over the content - but when it's open the content behind the nav in the background still scroll. The other answers with position, overflow & ***height*** also worked but with height the page jumps to the top when I open the nav. I guess it's unique to my situation but just thought I'd mention it in case anyone else with overlaid nav have the same problem. – moonunit7 Sep 24 '16 at 06:38
  • Where does the wrapper go? How is this a complete answer? – Kugel Dec 22 '17 at 03:12
  • Position: fixed; work me me, not Position: relative; – Pons Purushothaman Apr 02 '19 at 11:28
  • 11
    Adding fixed position _does_ address the issue, but it makes the page jump to the top, which is bad for UX if you're implementing this in the background while you present a menu or modal. To make a good UX, you should, before locking position, store the scroll position of the page, and then re-apply it after unlocked. – mike Apr 24 '19 at 14:05
  • In my case I had to add "width:100%" to get it working – Iruku Kagika Nov 26 '19 at 08:52
43

After many days trying, I found this solution that worked for me:

touch-action: none;
-ms-touch-action: none;

MDN touch-action docs

nishanthshanmugham
  • 2,967
  • 1
  • 25
  • 29
Eduardo Leite
  • 444
  • 5
  • 2
  • 3
    Thanks so much for this, I was going crazy with a modal component I was building that blocks scrolling in all browsers except for safari – pakman198 Mar 09 '21 at 23:23
  • You rock sir! Thank you! – savram Jun 15 '21 at 03:22
  • 2
    That didn't work for me on iOS 15.3.1, you used these rules on `body` right? – vaskort Mar 21 '22 at 22:08
  • 1
    Update on my question: This seems to have worked when I added this in advance and not by using a class that toggles these rules on and off on the `body` element. – vaskort Mar 21 '22 at 22:39
  • Thank you! This is exactly what I needed. Works like a charm – Marc Mar 25 '22 at 14:27
  • Note that while `touch-action` is set to `none`, touchscreen actions such as panning, pinch-to-zoom, etc. will likely be turned off. [MDN touch-action docs](https://developer.mozilla.org/en-US/docs/Web/CSS/touch-action) – nishanthshanmugham Jan 30 '23 at 01:10
  • 1
    I didn't test using a class to toggle these rules on and off through JavaScript. But using `el.style.touchAction = "none"` (and back to `""`) works on iOS 16. – nishanthshanmugham Jan 30 '23 at 04:21
34

Some solutions listed here had some strange glitches when stretching the elastic scrolling. To fix that I used:

body.lock-position {
  height: 100%;
  overflow: hidden;
  width: 100%;
  position: fixed;
}

Source: http://www.teamtownend.com/2013/07/ios-prevent-scrolling-on-body/

Davey
  • 2,355
  • 1
  • 17
  • 18
  • 5
    This is nice (works better in my case than `position: relative`) however, the scroll position is lost after restoring default styling (e.g. closing menu). – jmarceli Mar 16 '17 at 20:06
  • 3
    For scroll position you can use js (jquery in this example) do something like this: `// on menu open // save window pos $('body').attr( 'data-pos', $(window).scrollTop() ) ; // ... // on menu close // scroll to saved window pos $( window ).scrollTop( $('body').attr( 'data-pos' ) );` – Davey May 17 '17 at 10:58
  • That really did the tick for me! – D.Steinel Oct 13 '17 at 19:03
10

Had this issue today on iOS 8 & 9 and it seems that we now need to add height: 100%;

So add

html,
body {
  position: relative;
  height: 100%;
  overflow: hidden;
}
chaenu
  • 1,915
  • 16
  • 32
5

Its working in Safari browser.

html,
body {
  overflow: hidden;
  position: fixed
}
Sridhar
  • 401
  • 7
  • 10
5

For me this:

height: 100%; 
overflow: hidden; 
width: 100%; 
position: fixed;

Wasn't enough, i't didn't work on iOS on Safari. I also had to add:

top: 0;
left: 0;
right: 0;
bottom: 0;

To make it work good. Works fine now :)

Loosie94
  • 574
  • 8
  • 17
4

Combining the answers and comments here and this similar question here worked for me.

So posting as a whole answer.

Here's how you need to put a wrapper div around your site content, just inside the <body> tag.

 <!DOCTYPE HTML>
 <html>
 <head>
     <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
     <!-- other meta and head stuff here -->
 <head>
 <body>
     <div class="wrapper">
         <!-- Your site content here -->
     </div>
 </body>
 </html>

Create the wrapper class as below.

.wrapper{
    position:relative; //that's it
    overflow:hidden;
}

I also got the idea from this answer here.

And this answer here also has got some food for thought. Something that probably will work equally good in both desktops and devices.

Community
  • 1
  • 1
Devraj Gadhavi
  • 3,541
  • 3
  • 38
  • 67
2

I've worked with <body>and <div class="wrapper">

When popup opens ...

<body> gets a height of 100% and an overflow:hidden

<div class="wrapper"> gets position:relative;overflow:hidden;height:100%;

I use JS/jQuery to get the actual scrollposition of the page and store the value as data-attribut to body

Then i scroll to the scrollposition in the .wrapper DIV (not in window)

Here is my solution:

JS/jQuery:

// when popup opens

$('body').attr( 'data-pos', $(window).scrollTop()); // get actual scrollpos
$('body').addClass('locked'); // add class to body
$('.wrapper').scrollTop( $('body').attr( 'data-pos' ) ); // let wrapper scroll to scrollpos

// when popup close

$("body").removeClass('locked');
$( window ).scrollTop( $('body').attr( 'data-pos' ));

CSS:

body.locked {position:relative;overflow:hidden;height:100%;}
body.locked .wrapper {position:relative;overflow:hidden;height:100%;}

It works well on both sides ... desktop & mobile (iOS).

Tipps and improvements are welcome :)

Cheers!

Toge
  • 333
  • 1
  • 3
  • 7
1
html {
  position:relative;
  top:0px;
  left:0px;
  overflow:auto;
  height:auto
}

add this as default to your css

.class-on-html{
  position:fixed;
  top:0px;
  left:0px;
  overflow:hidden;
  height:100%;
}

toggleClass this class to to cut page

when you turn off this class first line will call scrolling bar back

Jozef Dúc
  • 965
  • 2
  • 18
  • 29
Longwinter
  • 11
  • 1
0

Why not wrap the content you don't want shown in an element with a class and set that class to display:none in a stylesheet meant only for the iphone and other handheld devices?

<!--[if !IE]>-->
<link media="only screen and (max-device-width: 480px)" href="small-device.css" type= "text/css" rel="stylesheet">
<!--<![endif]-->
William George
  • 6,735
  • 3
  • 31
  • 39
S16
  • 2,963
  • 9
  • 40
  • 64
0

Here is what I did: I check the body y position , then make the body fixed and adjust the top to the negative of that position. On reverse, I make the body static and set the scroll to the value I recorded before.

var body_x_position = 0;

function disable_bk_scrl(){

    var elb = document.querySelector('body');

    body_x_position = elb.scrollTop;
    // get scroll position in px

    var body_x_position_m = body_x_position*(-1);
    console.log(body_x_position);

    document.body.style.position = "fixed";

    $('body').css({ top: body_x_position_m });

}

function enable_bk_scrl(){  

    document.body.style.position = "static";

    document.body.scrollTo(0, body_x_position);

    console.log(body_x_position);
}
Austen Holland
  • 1,828
  • 1
  • 15
  • 24
0

Yes, this is related to new updates in safari that are breaking your layout now if you use overflow: hidden to take care of clearing divs.

Lee McAlilly
  • 9,084
  • 12
  • 60
  • 94
  • 11
    Can you go into more detail with this, or cite a source? This answer might be correct, but it's not very helpful. – pjmorse Oct 16 '14 at 17:20
0

A CSS keyword value that resets a property's value to the default specified by the browser in its UA stylesheet, as if the webpage had not included any CSS. For example, display:revert on a <div> would result in display:block.

overflow: revert;

I think this will work properly

0

If you need scroll modal

Modal open

$('body').attr('data-position', $(window).scrollTop());
$('body').css({'overflow' : 'hidden', 'position' : 'fixed'});

Modal close

$('body').css({'overflow' : 'unset', 'position' : 'unset'});
$(window).scrollTop( $('body').attr( 'data-position' ));
Ivan_Aka
  • 23
  • 4
0

My version) Work in iOS

 if (isModalWindowClose) {
        document.querySelector('body').style.overflow = '';
        document.querySelector('html').style.overflow = '';
        
        const scrollY = document.body.style.top;
        
        document.querySelector('html').style.height = '';
        document.body.style.position = '';
        document.body.style.left = '';
        document.body.style.top = '';

        window.scrollTo(0, parseInt(scrollY || '0') * -1);

        document.querySelector('html').style['scroll-behavior'] = '';
    } else {
        document.body.style.top = `-${window.scrollY}px`;
        document.querySelector('html').style.height = `${window.innerHeight - 1}px`;
        
        document.body.style.position = 'fixed';
        document.body.style.left = '0';
        
        document.querySelector('body').style.overflow = 'hidden';
        document.querySelector('html').style.overflow = 'hidden';
        
        document.querySelector('html').style['scroll-behavior'] = 'unset';
    }
0

It does apply, but it only applies to certain elements within the DOM. for example, it won't work on a table, td, or some other elements, but it will work on a <DIV> tag.
eg:

<body>
<meta name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1.0; user-scalable=0;"/>

Only tested in iOS 4.3.

A minor edit: you may be better off using overflow:scroll so two finger-scrolling does work.

adam
  • 1,067
  • 11
  • 24
-5

Simply change body height < 300px (height of mobile viewport on landspace is around 300px to 500px)

JS

$( '.offcanvas-toggle' ).on( 'click', function() {
    $( 'body' ).toggleClass( 'offcanvas-expanded' );
});

CSS

.offcanvas-expended { /* this is class added to body on click */
    height: 200px;
}
.offcanvas {
    height: 100%;
}
Vishal
  • 2,030
  • 22
  • 27
  • Not a very elegant solution, and will cause issues on iOS devices that are larger than the specific pixels you end up choosing. A different solution should be used. – Badrush Jul 11 '18 at 20:59