14

I have done some testing and from what I can see there is a bug in mobile Safari on ios6.

When adding overflow:hidden on the body tag and moving an element out of the body using transform:translateX(100%); It creates an extra scrollable space for that element. On all desktop browsers it is "hidden".

Here is a demo: http://jsfiddle.net/mUB5d/1 . Open that in Mobile safari and you will see what is wrong.

Could anyone take a look at safari 6 on Mac OS to see if the bug is present there too? Does anybody know of any workaround besides creating another parent around my element?

Thanks for your feedback!

cmplieger
  • 7,155
  • 15
  • 55
  • 83
  • A note: The issue is present on iOS 5 as well. It is not in Chrome (desktop or mobile). – Cat Sep 15 '12 at 04:17
  • @Eric weird that it works in chrome as it uses the ios webview. It is true that webview uses a different JS/webkit engine so that could explain it... – cmplieger Sep 15 '12 at 04:23
  • Actually, my mistake--the error is also visible in Chrome on iOS. Sorry about that. – Cat Sep 15 '12 at 04:27
  • Other problem with iOS6 specifically! http://stackoverflow.com/questions/12510013/how-to-style-ios-safari-scrollbars-with-css-for-ios-6 – Armel Larcier Sep 20 '12 at 10:43
  • If you need to hide the element can you not use `position: relative; right:100%;` ? – Seb Ashton Nov 13 '12 at 14:28

4 Answers4

9

Nope. Safari 6 on Mac does not present with the bug. Scrollbars are not present.

I ran it on OSX Mountain Lion (10.8.2)

enter image description here

To further answer your question, the reason this is happening probably has more to do with Mobile Safari's zoom rendering than an overflow hidden bug. The element is in fact being hidden off screen (notice below where I have scrolled over to the right all the way, it still doesn't show me the full 100% width element - 90% of it is in fact being hidden.

It likely has something to do with iframes, and page zoom. Still looks like a bug though.

I'm assuming you're demonstrating in JSFiddle from a real life example. If you go back to your real life example (apart from iframe territory), try adding this meta tag to the head if you don't already have it, and see it this helps:

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

enter image description here

Joel Glovier
  • 7,469
  • 9
  • 51
  • 86
8

This is normal behaviour on iOS (and iOS only). You can work around it by declaring overflow: hidden on both html and body element. In addition, you should set the body to position: relative.

Overflow behaviour

There are several things at play here. To understand why the fix works, we first need to have a look at how the overflow of the viewport is set.

  • The overflow of the viewport is determined by the overflow setting of the html element.
  • But as long as you leave the overflow of the html element at its default (visible), the overflow setting of the body gets applied to the viewport, too. Ie, you can set either html or body to overflow: hidden when you target the viewport. The overflow behaviour of the body element itself is unaffected - so far.
  • Now, if you set the overflow of the htmlelement to anything other than visible, the transfer from body to viewport does no longer happen. In your particular case, if you set both overflows to hidden, the setting of the html element gets applied to the viewport, and the body element hides its overflow as well.

That's actually the case in every reasonably modern browser out there, and not specific to iOS.

iOS quirks

Now, iOS ignores overflow: hidden on the viewport. The browser reserves the right to show the content as a whole, no matter what you declare in the CSS. This is intentional and not a bug, and continues to be the case in iOS 7 and 8. There is nothing anyone can do about it, either - it can't be turned off.

But you can work around it by making the body element itself, not the viewport, hide its overflow. To make it happen, you must first set the overflow of the html element to anything other than visible, e.g. to auto or hidden (in iOS, there is no difference between the two). That way, the body overflow setting doesn't get transferred to the viewport and actually sticks to the body element when you set it to overflow: hidden.

With that in place, most content is hidden. But there still is an exception: elements which are positioned absolutely. Their ultimate offset parent is the viewport, not the body. If they are positioned somewhere off screen, to the right or to the bottom, you can still scroll to them. To guard against that, you can simply set the body element to position: relative, which makes it the offset parent of positioned content and prevents those elements from breaking out of the body box.

Answering in code

There is one final gotcha to watch out for: the body itself must not be larger than the viewport.

So the body needs to be set to 100% of the viewport width and height. (The credit for a CSS-only way to achieve it goes to this SO answer.) Margins on the html and body elements have to be 0, and the html must not have padding or a border, either.

Finally, in order to deal with body padding, and in case you ever want to set a border on the body, make the math work with box-sizing: border-box for the body.

So here goes.

html {
  overflow: hidden;

  height: 100%;
  margin: 0;
  padding: 0;
  border: none;
}

body {
  overflow: hidden;
  position: relative;

  box-sizing: border-box;
  margin: 0;
  height: 100%;
}

NB You can set body padding and border as you please.

Community
  • 1
  • 1
hashchange
  • 7,029
  • 1
  • 45
  • 41
  • This is a great explanation but doesn't seem to remove body scroll when testing for iOS 8 + Safari & Chrome @ iPad. – Rui Marques Mar 11 '15 at 16:50
  • Works for me ;) Have a look at http://jsbin.com/gomoqo/1/ and play with the settings for a bit. Perhaps you can set up a bin/fiddle where it does _not_ work, and post the URL? I'll have a look. – hashchange Mar 11 '15 at 18:49
  • One thing to look out for here is that the body actually fits inside the viewport. If it is wider or taller, the viewport will scroll, even though the body itself hides its overflow. Just a thought. – hashchange Mar 11 '15 at 18:53
  • Yes I think the body is taller than the viewport. To make it the same size you have to use javascript right? – Rui Marques Mar 12 '15 at 09:52
  • @RuiMarques I have updated the answer to address this. – hashchange Mar 13 '15 at 12:11
1

After struggling with this for a while I've found that both html and body tags need overflow hidden to actually hide the overflowing contents. On elements inside body overflow hidden works fine, so our choice is an extra css rule or a wrapper element.

RobW
  • 10,184
  • 4
  • 41
  • 40
0

for me it works

I have implemented in the left side menu

if($('.left-menu-panel').is(':visible')) {$("body").addClass('left-menu-open');$("html").css('overflow-y','hidden'); $('body').click(function() {$("body").removeClass("left-menu-open") ;$("html").css('overflow-y','visible'); });$('#off-canvas-left').click(function(event){event.stopPropagation();}); }