position: fixed doesn't work on iPad and iPhone
Asked Answered
D

15

145

I have been struggling with fixed positioning in iPad for a while. I know iScroll and it does not always seem to work (even in their demo). I also know that Sencha has a fix for that, but I couldn't Ctrl + F the source code for that fix.

I am hoping that someone may have the solution. The problem is that fixed positioned elements do not get updated when the user pans down/up on an iOS powered mobile Safari.

Danielladanielle answered 3/2, 2011 at 17:42 Comment(3)
Looks like jQuery Mobile 1.1 solved this problem: jquerymobile.com/blog/2012/04/13/announcing-jquery-mobile-1-1-0Danielladanielle
possible duplicate of Fixed positioning in Mobile SafariCull
Possible duplicate of several SO questions. See gist.github.com/avesus/… for details.Inflectional
D
6

I ended up using the new jQuery Mobile v1.1: http://jquerymobile.com/blog/2012/04/13/announcing-jquery-mobile-1-1-0/

We now have a solid re-write that provides true fixed toolbars on the a lot of popular platforms and safely falls back to static toolbar positioning in other browsers.

The coolest part about this approach is that, unlike JS-based solutions that impose the unnatural scrolling physics across all platforms, our scrolling feels 100% native because it is. This means that scrolling feels right everywhere and works with touch, mousewheel and keyboard user input. As a bonus, our CSS-based solution is super lightweight and doesn’t impact compatibility or accessibility.

Danielladanielle answered 27/5, 2012 at 8:57 Comment(2)
Also pretty elegant (but definitely a workaround) is this method for allowing fixed objects on iOS without using jQuery or JavaScript (only uses CSS). It's pretty universally applicable. If you wanted a "floating" position:fixed element to appear in front of your scrolling page, you'd just need to give it a higher z-index value so that it stays in front.Tactics
this definitely doesn't answer the question.Tube
T
67

A lot of mobile browsers deliberately do not support position:fixed; on the grounds that fixed elements could get in the way on a small screen.

The Quirksmode.org site has a very good blog post that explains the problem: http://www.quirksmode.org/blog/archives/2010/12/the_fifth_posit.html

Also see this page for a compatibility chart showing which mobile browsers support position:fixed;: http://www.quirksmode.org/m/css.html

(but note that the mobile browser world is moving very quickly, so tables like this may not stay up-to-date for long!)

Update: iOS 5 and Android 4 are both reported to have position:fixed support now.

I tested iOS 5 myself in an Apple store today and can confirm that it does work with position fixed. There are issues with zooming in and panning around a fixed element though.

I found this compatibility table far more up to date and useful than the quirksmode one: http://caniuse.com/#search=fixed

It has up to date info on Android, Opera (mini and mobile) & iOS.

Trigger answered 3/2, 2011 at 17:55 Comment(10)
position:device-fixed would be kind of redundant. position:fixed should just work to W3C specifications.Eldridgeeldritch
@TalviWatia - the device-fixed solution was not part of my answer. It may or may not have merit as a suggestion, but the reason for the link was the explanation of the issue rather than his suggested solution. In any case, things have moved on a lot since this answer was posted (as I said it would), and a lot of newer devices do support fixed. You still need to deal with older devices that don't, though.Trigger
So I am curious, what exactly is your solution to the problem at hand? The links you supplied while possibly helpful do not solve the problem at hand. Not to be jaded, but people tend to upvote answers that are not actually answers here on SO.Eldridgeeldritch
@TalviWatia: At the time I wrote the answer, there wasn't really a good solution to the question. The link I gave was the best discussion I knew of to explain why things were the way they were, which in the absence of a solution was as good as I could offer. Things have changed in the intervening period, so the discussion in the link is no longer relevant, and there are solutions now, but that's how it was at the time.Trigger
Actually position:fixed works for scale 1 but when the user zooms the ipad it won't works ok. position:device-fixed exist?? Is valid css attribute for safari ios?Tunicate
@Tunicate - position:device-fixed did not exist when this answer was posted; it's a more recent development intended to solve the problems described in this question. It therefore definitely will not work on older devices. Newer devices may or may not support it; you'd have to check specific devices and OS versions to confirm.Trigger
The compat table shows that all major mobile browsers, even older versions, now support position fixed. Perhaps the answer can be updated to reflect this?Sanalda
This is not a solution! Just indetify a problem and we all know there is a problem.Acrylonitrile
@Acrylonitrile - always look at the date an answer was posted before reacting to it. This was answered in 2011. Browsers have moved on a long way since then; the answer was correct, accurate and helpful when it was posted but it is no longer relevant. It is simply out of date.Trigger
Spudley. How will i go back in the time to know at 2011 it was working? Now is not working and visitors must know that so they do not try something NOW is not working. Not offense. Maybe we need an update here.Acrylonitrile
S
38

Fixed positioning doesn't work on iOS like it does on computers.

Imagine you have a sheet of paper (the webpage) under a magnifying glass(the viewport), if you move the magnifying glass and your eye, you see a different part of the page. This is how iOS works.

Now there is a sheet of clear plastic with a word on it, this sheet of plastic stays stationary no matter what (the position:fixed elements). So when you move the magnifying glass the fixed element appears to move.

Alternatively, instead of moving the magnifying glass, you move the paper (the webpage), keeping the sheet of plastic and magnifying glass still. In this case the word on the sheet of plastic will appear to stay fixed, and the rest of the content will appear to move (because it actually is) This is a traditional desktop browser.

So in iOS the viewport moves, in a traditional browser the webpage moves. In both cases the fixed elements stay still in reality; although on iOS the fixed elements appear to move.


The way to get around this, is to follow the last few paragraphs in this article

(basically disable scrolling altogether, have the content in a separate scrollable div (see the blue box at the top of the linked article), and the fixed element positioned absolutely)


"position:fixed" now works as you'd expect in iOS5.

Scare answered 3/2, 2011 at 18:5 Comment(1)
There are some odd things that happen with position:fixed when you zoom in on IOS. See #52086498Arsenault
I
34

position: fixed does work on android/iphone for vertical scrolling. But you need to make sure your meta tags are fully set. e.g

<meta name="viewport" content="width=device-width, height=device-height, initial-scale=1.0, user-scalable=0, minimum-scale=1.0, maximum-scale=1.0">

Also if you're planning on having the same page work on android pre 4.0, you need to set the top position also, or a small margin will be added for some reason.

Infrastructure answered 1/3, 2012 at 21:38 Comment(4)
This actually worked for me. Before, position:fixed on a hidden input element (see pure css off screen navigation) caused the browser to crash on iphone ios 8.3 but not on tablet. After it works fine.Horntail
Did not work on iPad iOS 10.3, horizontal in Square stand. Granted author says this approach is for "phones".Norwood
Disabling user to zoom with user-scalable=0, minimum-scale=1.0, maximum-scale=1.0 can make the page less accessible for many users. It would be useful to add a warning about it in your answerShipway
Thanks, worked for me on an iPad Pro 12.9Salpinx
M
28

I had this problem on Safari (iOS 10.3.3) - the browser was not redrawing until the touchend event fired. Fixed elements did not appear or were cut off.

The trick for me was adding transform: translate3d(0,0,0); to my fixed position element.

.fixed-position-on-mobile {
  position: fixed;
  transform: translate3d(0,0,0);
}

EDIT - I now know why the transform fixes the issue: hardware-acceleration. Adding the 3D transformation triggers the GPU acceleration making for a smooth transition. For more on hardware-acceleration checkout this article: http://blog.teamtreehouse.com/increase-your-sites-performance-with-hardware-accelerated-css.

Melvinmelvina answered 13/3, 2018 at 19:34 Comment(1)
This actually fixed my scrolling issue, it was bouncing on iOS devices when using fixed, added the transform and this was fixed.Caudex
C
25

now apple support that

overflow:hidden;
-webkit-overflow-scrolling:touch;
Cricoid answered 25/4, 2012 at 14:29 Comment(5)
This is exactly what I was after to solve my background-size: cover and fixed issue on the iPadAllegedly
This works on Mobile Safari in iOS 7. Note: It will not work for users that have not upgraded to this version yet.Pyromania
Then there must be some other variables at work. I've tested on iOS 6 and it was not working, then on iOS 7 and it was.Pyromania
@NeilMonroe hmm maybe. im sure i've done it on iOS 6 without prob but maybe i used an other variable. dont rememberCentroclinal
this was really helpful, but it seems, overflow has to be set to scrollDodecagon
I
17

Fixed Footer (here with jQuery):

if (navigator.platform == 'iPad' || navigator.platform == 'iPhone' || navigator.platform == 'iPod' || navigator.platform == 'Linux armv6l') {
  window.ontouchstart = function() {
    $("#fixedDiv").css("display", "none");
  }

  window.onscroll = function() { 
    // 45 is the height of the Footer
    var iPadPosition = window.innerHeight + window.pageYOffset-45;

    $("#fixedDiv").css("position", "absolute");
    $("#fixedDiv").css("top", iPadPosition);
    $("#fixedDiv").css("display", "block");
  }
}

In the CSS file should stand:

 #fixedDiv {
  position: fixed;
  bottom: 0;
  height: 45px;
  ...
}
Interpretation answered 31/7, 2012 at 14:13 Comment(0)
O
7

Avoid on the same box using transform:--- and position:fixed. Element will stay in position:static if there is any transform.

Openandshut answered 4/6, 2014 at 13:46 Comment(0)
D
6

I ended up using the new jQuery Mobile v1.1: http://jquerymobile.com/blog/2012/04/13/announcing-jquery-mobile-1-1-0/

We now have a solid re-write that provides true fixed toolbars on the a lot of popular platforms and safely falls back to static toolbar positioning in other browsers.

The coolest part about this approach is that, unlike JS-based solutions that impose the unnatural scrolling physics across all platforms, our scrolling feels 100% native because it is. This means that scrolling feels right everywhere and works with touch, mousewheel and keyboard user input. As a bonus, our CSS-based solution is super lightweight and doesn’t impact compatibility or accessibility.

Danielladanielle answered 27/5, 2012 at 8:57 Comment(2)
Also pretty elegant (but definitely a workaround) is this method for allowing fixed objects on iOS without using jQuery or JavaScript (only uses CSS). It's pretty universally applicable. If you wanted a "floating" position:fixed element to appear in front of your scrolling page, you'd just need to give it a higher z-index value so that it stays in front.Tactics
this definitely doesn't answer the question.Tube
A
2

using jquery i am able to come up with this. it doesnt scroll smooth, but it does the trick. you can scroll down, and the fixed div pops up on top.

THE CSS

<style type="text/css">
    .btn_cardDetailsPg {height:5px !important;margin-top:-20px;}
    html, body {overflow-x:hidden;overflow-y:auto;}
    #lockDiv {
  background-color: #fff;
  color: #000;
  float:left;
  -moz-box-shadow: 0px 4px 2px 2px #ccc;-webkit-box-shadow: 0px 4px 2px 2px #ccc;box-shadow:0px 4px 2px 2px #ccc;
  }
#lockDiv.stick {
  position: fixed;
  top: 0;
  z-index: 10000;
  margin-left:0px;
  }
</style>

THE HTML

<div id="lockSticky"></div>
<div id="lockDiv">fooo</div>

THE jQUERY

<script type="text/javascript">
    function sticky_relocate() {
        var window_top = $(window).scrollTop();
        var div_top = $('#lockSticky').offset().top;
        if (window_top > div_top)
            $('#lockDiv').addClass('stick')
        else
            $('#lockDiv').removeClass('stick');
    }
    $(function() {
        $(window).scroll(sticky_relocate);
        sticky_relocate();
    });
</script>

Finally we want to determine if the ipod touch in landscape or portrait mode to display accordingly

<script type="text/javascript">
    if (navigator.userAgent.match(/like Mac OS X/i)) {
        window.onscroll = function() {

        if (window.innerWidth > window.innerHeight) {
            //alert("landscape [ ]");
            document.getElementById('lockDiv').style.top =
            (window.pageYOffset + window.innerHeight - 268) + 'px';
        }

        if (window.innerHeight > window.innerWidth) {
            //alert("portrait ||");
            document.getElementById('lockDiv').style.top =
            (window.pageYOffset + window.innerHeight - 418) + 'px';
        }
        };
    }
</script>
Ackler answered 30/4, 2012 at 22:23 Comment(0)
T
2

The simple way to fix this problem just types transform property for your element. and it will be fixed.

.classname{
  position: fixed;
  transform: translate3d(0,0,0);
}

Also you can try his way as well this is also work fine.

.classname {
  position: -webkit-sticky;
}
Trochaic answered 6/8, 2019 at 16:12 Comment(0)
B
2

In my case, it was because the fixed element was being shown by using an animation. As stated in this link:

in Safari 9.1, having a position:fixed-element inside an animated element, may cause the position:fixed-element to not appear.

Branscum answered 13/7, 2020 at 5:24 Comment(0)
E
1

Even though the CSS attribute {position:fixed;} seems (mostly) working on newer iOS devices, it is possible to have the device quirk and fallback to {position:relative;} on occasion and without cause or reason. Usually clearing the cache will help, until something happens and the quirk happens again.

Specifically, from Apple itself Preparing Your Web Content for iPad:

Safari on iPad and Safari on iPhone do not have resizable windows. In Safari on iPhone and iPad, the window size is set to the size of the screen (minus Safari user interface controls), and cannot be changed by the user. To move around a webpage, the user changes the zoom level and position of the viewport as they double tap or pinch to zoom in or out, or by touching and dragging to pan the page. As a user changes the zoom level and position of the viewport they are doing so within a viewable content area of fixed size (that is, the window). This means that webpage elements that have their position "fixed" to the viewport can end up outside the viewable content area, offscreen.

What is ironic, Android devices do not seem to have this issue. Also it is entirely possible to use {position:absolute;} when in reference to the body tag and not have any issues.

I found the root cause of this quirk; that it is the scroll event not playing nice when used in conjunction with the HTML or BODY tag. Sometimes it does not like to fire the event, or you will have to wait until the scroll swing event is finished to receive the event. Specifically, the viewport is re-drawn at the end of this event and fixed elements can be re-positioned somewhere else in the viewport.

So this is what I do: (avoid using the viewport, and stick with the DOM!)

<html>
  <style>
    .fixed{
      position:fixed;
      /*you can set your other static attributes here too*/
      /*like height and width, margin, etc.*/
      }
    .scrollableDiv{
      position:relative;
      overflow-y:scroll;
      /*all children will scroll within this like the body normally would.*/
      } 
    .viewportSizedBody{
      position:relative;
      overflow:hidden;
      /*this will prevent the body page itself from scrolling.*/
      } 
  </style>
  <body class="viewportSizedBody">
    <div id="myFixedContainer" class="fixed">
       This part is fixed.
    </div>
    <div id="myScrollableBody" class="scrollableDiv">
       This part is scrollable.
    </div>
  </body>
  <script type="text/javascript" src="{your path to jquery}/jquery-1.7.2.min.js"></script>
  <script>
    var theViewportHeight=$(window).height();
    $('.viewportSizedBody').css('height',theViewportHeight);
    $('#myScrollableBody').css('height',theViewportHeight);
  </script>
</html>

In essence this will cause the BODY to be the size of the viewport and non-scrollable. The scrollable DIV nested inside will scroll as the BODY normally would (minus the swing effect, so the scrolling does stop on touchend.) The fixed DIV stays fixed without interference.

As a side note, a high z-index value on the fixed DIV is important to keep the scrollable DIV appear to be behind it. I normally add in window resize and scroll events also for cross-browser and alternate screen resolution compatibility.

If all else fails, the above code will also work with both the fixed and scrollable DIVs set to {position:absolute;}.

Eldridgeeldritch answered 21/6, 2012 at 0:11 Comment(0)
L
1

Had the same issue on Iphone X. To fixed it I just add height to the container

top: 0;
height: 200px;
position: fixed;

I just added top:0 because i need my div to stay at top

Lalita answered 6/8, 2020 at 1:20 Comment(0)
A
0

This might not be applicable to all scenarios, but I found that the position: sticky (same thing with position: fixed) only works on old iPhones when the scrolling container is not the body, but inside something else.

Example pseudo html:

body                         <- scrollbar
   relative div
       sticky div

The sticky div will be sticky on desktop browsers, but with certain devices, tested with: Chromium: dev tools: device emultation: iPhone 6/7/8, and with Android 4 Firefox, it will not.

What will work, however, is

body
    div overflow=auto       <- scrollbar
        relative div
            sticky div
Alpine answered 21/3, 2020 at 23:20 Comment(0)
O
0

This seems to work for Ionic5 on iPhone 6 Plus on iOS 12.4.2

.large_player {
  float: left;
  bottom: 0;
  width: 100%;
  position: fixed;
  background-color: white;
  border-top: black 1px solid;    
  height: 14rem;
  z-index: 100;
  transform: translate3d(0,0,0);
}

The transform tag makes it work, but it also seems a little clunky in how the scroll works, it is seems to redraw the 'on top' element after it's all moved and sort of resets and makes it jump a little.

Or, you could also use this tag option as well, position: -webkit-sticky;, but then you won't get, or may run in to trouble with WPA/browser or Android builds while having to do version checking and have multiple CSS tags.

.large_player {
  float: left;
  bottom: 0;
  width: 100%;
  position: -webkit-sticky;
  background-color: white;
  border-top: black 1px solid;    
  height: 14rem;
  z-index: 100; 
}

I don't know at what point it was fixed, but later iOS phones work without the transform tag. I don't know if it's the iOS version, or the phone.

As most iOS devices are usually on the most recent iOS version, it's pretty safe with go with a weird work around - such as using the transform tag, rather than building in a quirky detection routine for the sake of less than 1% of users.

Update:

After thinking about this answer further, this is just another way of doing this by platform for ionic5+:

.TS

import {Platform } from '@ionic/angular';

constructor(public platform: Platform) {  
  // This next bit is so that the CSS is shown correctly for each platform    

  platform.ready().then(() => {
    if (this.platform.is('android')) {
      console.log("running on Android device!");
      this.css_iOS = false;
    }
    if (this.platform.is('ios')) {
      console.log("running on iOS device!");
      this.css_iOS = true;
    }     
    if (this.platform.is('ipad')) {
      console.log("running on iOS device!");
      this.css_iOS = true;
    }
  });
}
css_iOS: boolean = false;

.HTML

<style *ngIf="css_iOS">
  .small_player {
    position: -webkit-sticky !important;
  }
  .large_player {
    position: -webkit-sticky !important;
  }
</style>
    
    
<style>
  .small_player {
    float: left;
    bottom: 0;
    width: 100%;
    position: fixed;
    background-color: white;
    border-top: black 1px solid;    
    height: 4rem;
    z-index: 100;
    /*transform: translate3d(0,0,0);*/
  }
    
  .large_player {
    float: left;
    bottom: 0;
    width: 100%;
    position: fixed;
    background-color: white;
    border-top: black 1px solid;    
    height: 14rem;
    z-index: 100;
    /*transform: translate3d(0,0,0);*/
  }
</style>
Octofoil answered 23/2, 2021 at 1:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.