Мобильные браузеры и position:fixed

CSS-свойство position:fixed в Mobile Safari сносно работает начиная c iOS 5. В Android родной браузер частично понимает это свойство начиная с версии системы 2.1, адекватно — с 2.2, полная поддержка — с 3.0. Подробнее: таблица поддержки position:fixed.

HTML:
<div id="topbar">Fixed Title</div>
<div id="content">
	<h2>Start</h2>
	<p>Main content text </p>
	...
	<p>Main content text </p>
	<h2>End</h2>
</div>
<div id="bottombar">Fixed footer</div>

CSS:
#content{
	padding: 50px 0; /* отбиваем высоту баров, чтобы не перекрывать контент вверху и внизу страницы */
}
#topbar,
#bottombar {
	position: fixed;
	left: 0;
	width:100%;
	height: 50px; /* фиксируем высоту для простоты */
	line-height:50px;
	background:#eee;
	text-align: center;
}
#topbar {top: 0;}
#bottombar {bottom: 0;}


Теперь в современных смартах у нас topbar и bottombar «прибиты» соответственно к верху и к низу окна. Проблема позицонирования при первом скролле в iOS решается мини-Javacript'ом (исправлено):
window.scrollBy(0, 1);


Для «старичков» делаем имитацию по принципу progressive enhancemen.

Определяем поддержку position:fixed; по методу со stackoverflow и добавляем контекстный класс для не поддерживающих (исправлено):
// проверяем поддержку position: fixed;[start]
var isFixedSupported = (function(){
	var isSupported = null;
	if (document.createElement) {
		var el = document.createElement("div");
		if (el && el.style) {
			el.style.position = "fixed";
			el.style.top = "10px";
			var root = document.body;
			if (root && root.appendChild && root.removeChild) {
				root.appendChild(el);
				isSupported = el.offsetTop === 10;
				root.removeChild(el);
			}
		}
	}
	return isSupported;
})();

// добавляем контекст для "старичков"
window.onload = function(){
	if (!isFixedSupported){
		document.body.className += ' no-fixed-supported' : '';
	}
// первичный scroll
	window.scrollBy(0, 1);
}

Соответственно CSS:
.no-fixed-supported #topbar,
.no-fixed-supported #bottombar { position: absolute; }

Добавляем обработку событий touch и scroll:
// имитируем position: fixed;
var topbar = document.getElementById('topbar');
var bottombar = document.getElementById('bottombar');
var bottomBarHeight = bottombar.offsetHeight;

var windowHeight = window.innerHeight;

// обрабатываем события touch и scroll
window.ontouchstart = function(e) {
	if (event.target !== topbar){
		topbar.style = "";
	}
}
window.onscroll = function(){
	var scrollTop = window.scrollY;
	topbar.style.top = scrollTop + 'px';
	bottombar.style.bottom = (scrollTop + windowHeight - bottomBarHeight) + 'px';
};

Результат (исправлено)
<!DOCTYPE html>
<html>
<head>
	<title>TEST</title>
	<meta name="viewport" content="initial-scale=1.0,maximum-scale=1.0,user-scalable=no" />
	<style type="text/css">
		#content{
			padding: 50px 0; /* отбиваем высоту баров, чтобы не перекрывать контент вверху и внизу страницы */
		}
		#topbar,
		#bottombar {
			position: fixed;
			left: 0;
			width:100%;
			height: 50px; /* фиксируем высоту topbar'а для простоты */
			line-height:50px;
			background:#eee;
			text-align: center;
		}
		#topbar {top: 0;}
		#bottombar {bottom: 0;}
		.no-fixed-supported #topbar,
		.no-fixed-supported #bottombar { position: absolute; }
	</style>
</head>
<body>
	<div id="topbar">Fixed Title</div>
	<div id="content">
		<h2>Start</h2>
		<p>Main content text</p><p>Main content text</p><p>Main content text</p><p>Main content text</p><p>Main content text</p><p>Main content text</p><p>Main content text</p><p>Main content text</p><p>Main content text</p><p>Main content text</p><p>Main content text</p><p>Main content text</p><p>Main content text</p><p>Main content text</p><p>Main content text</p><p>Main content text</p><p>Main content text</p><p>Main content text</p><p>Main content text</p><p>Main content text</p><p>Main content text</p><p>Main content text</p>
		<h2>End</h2>
	</div>
	<div id="bottombar">Fixed footer</div>

	<script type="text/javascript">
// проверяем поддержку position: fixed;[start]
		var isFixedSupported = (function(){
			var isSupported = null;
			if (document.createElement) {
				var el = document.createElement("div");
				if (el && el.style) {
					el.style.position = "fixed";
					el.style.top = "10px";
					var root = document.body;
					if (root && root.appendChild && root.removeChild) {
						root.appendChild(el);
						isSupported = (el.offsetTop === 10);
						root.removeChild(el);
					}
				}
			}
			return isSupported;
		})();
		window.onload = function(){
			if (!isFixedSupported){
// добавляем контекст для "старичков"
				document.body.className += ' no-fixed-supported';
// имитируем position: fixed;
				var topbar = document.getElementById('topbar');
				var bottombar = document.getElementById('bottombar');
				var bottomBarHeight = bottombar.offsetHeight;
				var windowHeight = window.innerHeight;
// обрабатываем события touch и scroll
				window.ontouchmove = function(e) {
					if (event.target !== topbar){
						topbar.style = "";
					}
				}
				window.onscroll = function(){
					var scrollTop = window.scrollY;
					topbar.style.top = scrollTop + 'px';
					bottombar.style.bottom = (scrollTop + windowHeight - bottomBarHeight) + 'px';
				};
			}
// первичный scroll
			window.scrollBy(0, 1);
		}
	</script>
</body>
</html>
Демо

UPD: Источник вдохновения.
UPD2: внесены правки. Отключен auto zoom. Подфикшен код. Исправлено первичное смещение. Проверено на iOS 6.0.1, Android 2.3.7. Добавлено демо.

Similar posts

Ads
AdBlock has stolen the banner, but banners are not teeth — they will be back

More

Comments 11

    +4
    Нехорошо копипастить, тем более без указания источника. Как-то воровством попахивает.

    UPD: Виноват, не разобрался сразу — таки разные статьи
      0
      Да, таки пост относится к «совету», по принципу «музыка невеяла».
      +1
      Надо попробывать, а то приходилось делать так
      if(/(iPhone|iPod|iPad)/i.test(navigator.userAgent)) {
              if (/OS [1-4]_\d like Mac OS X/i.test(navigator.userAgent)) {
                  $('#header').css({"position" : "static"});
                  $('body').css({"padding" : 0});
              }
          }
      
        +3
        «попробОвать», очень вас прошу!
        0
        Сделал демку.

        У меня на Android 2.3.4 не работает…
          0
          Исправлено.
            0
            Ваше решение не заработает на iOS младше 5 версии. Наиболее просто можно добавить поддержку через iScroll 4, FT Scroller или Zynga Scroller
              0
              Заработает, но это ж не полная имитация скролла, а репозиционирование баров.
              Фрейфмворки — это, конечно, хорошо, но это не наш путь.
                0
                Не заработает) Специально проверил на iPod Touch iOS 4.2.1.
                0
                у кастомных скроллов свой гемор начинается, когда добавляются всякие инпуты внутрь
            0
            огромное спасибо!

            Only users with full accounts can post comments. Log in, please.