Mobile Safari bugs so far

Sunday, Apr 1, 2012 2:23 pm
William Barnes

I just bought my first iOS device (the new iPad) and I’ve been busy squashing bugs in my latest project. And by bugs in my project I mean, of course, bugs in Safari. Here are some of the more annoying ones and how I fixed them.

Changing CSS visibility breaks things

Several of the problems I had seem to have been caused by various problems with Safari’s handling of visibility. For example, a number of elements in the app use the following CSS transition to fade in and out:

  1. .hideable {
  2. opacity: 0;
  3. visibility: hidden;
  4. transition: visibility 0.5s linear 0.5s, opacity 0.5s ease;
  5. -moz-transition: visibility 0.5s linear 0.5s, opacity 0.5s ease;
  6. -webkit-transition: visibility 0.5s linear 0.5s, opacity 0.5s ease;
  7. -o-transition: visibility 0.5s linear 0.5s, opacity 0.5s ease;
  8. }
  9.  
  10. .visible {
  11. opacity: 1;
  12. visibility: visible;
  13. transition-delay:0s;
  14. -moz-transition-delay:0s;
  15. -webkit-transition-delay:0s;
  16. -o-transition-delay:0s;
  17. }

I use visibility for two reasons: (1) elements can be sized according to their contents before being shown, (2) visibility can be transitioned. The second reason is important, because otherwise it would require additional Javascript to delay the hiding of the element until after the opacity transition runs. This works in Desktop Safari, Chrome, Firefox, the Android Browser, and Mobile Chrome. In Mobile Safari, however, the element does not get shown until you click on another link.

[Edit: Apparently I was wrong about the Android Browser. I suspect this may be a problem in an older Webkit, since it definitely works in Mobile Chrome.]

I originally solved this by disabling the visibility transition in iOS, but I ran into another problem. Merely toggling visibility breaks Mobile Safari’s new native “overflow: auto/scroll” functionality. I’ll talk about this problem in more detail later. For now, the solution is to disable the transition and use display instead of visibility in Mobile Safari:

  1. body.iOS .hideable {
  2. display: none;
  3. opacity: 1;
  4. -webkit-transition: none;
  5. visibility: visible;
  6. }
  7.  
  8. body.iOS .visible {
  9. display: block;
  10. }

Overflow scroll breaks on visibility toggle

iOS5 finally introduced scrolling within an element. Previously, this had to be achieved with Javascript (e.g. iScroll). Frankly, I was pretty happy with my Javascript solution, but some variation of the position fixed bug mentioned below was breaking it. The touchable portion of the inner DIV scrolled with the document, rather than remaining fixed.; if the document was scrolled partway down, the fixed element no longer scrolled.

iOS’s solution is fairly simple, just add the following to your CSS: “-webkit-overflow-scrolling: touch;” I imagine it’s done this way because they’re afraid of breaking apps that relied on overflow-scroll just not working. It works pretty well, though it does not use the custom scrollbars. It also does not work if the scrolling DIV is contained in an element that was previously visibility-hidden. This time, it has nothing to do with transitions. The only fix I can find is to use display instead of visibility.

 Javascript scrolling breaks touch events on position-fixed objects

This was a weird one. I put buttons on the right edge of the screen to allow a user to page up and down the document. They were position-fixed (supported in iOS 5!) and they worked. Once. You couldn’t click them a second time. If you clicked one, all the other position-fixed buttons stopped working. If you then scrolled normally, everything started working again. Interestingly, if I just scrolled down 100px, the button would stop working, but if I then touched a spot 100px above the button, it would register. It’s as if Safari has a map of elements for the purpose of registering touch events that stays fixed to the page (ie: position absolute), while the visible representation of the elements stays fixed to the screen. Thus, when the page scrolls, the map goes with it. For whatever reason, Javascript doesn’t trigger a recalculation of where the elements are.

I disabled the buttons in iOS. Apple is aware of this, so a fix may be coming.