Pull to refresh

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

Reading time 4 min
Views 38K
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. Добавлено демо.
Tags:
Hubs:
+5
Comments 11
Comments Comments 11

Articles