Last active
August 29, 2015 14:15
-
-
Save abicky/7c351a6ed1170d9a8c5f to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=320,user-scalable=no"> | |
<style> | |
body { | |
margin: 0; | |
padding: 0; | |
height: 3000px; | |
} | |
#parent { | |
margin-top: 600px; | |
border: solid black 1px; | |
width: 320px; | |
} | |
#header { | |
color: white; | |
background: red; | |
} | |
#footer { | |
color: white; | |
background: blue; | |
} | |
.box { | |
width: 320px; | |
height: 100px; | |
border: solid black 1px; | |
} | |
</style> | |
</head> | |
<body> | |
下にスクロールしてください | |
<div id="parent"> | |
<div id="header" class="box">Header</div> | |
<div class="box">1</div> | |
<div class="box">2</div> | |
<div class="box">3</div> | |
<div class="box">4</div> | |
<div class="box">5</div> | |
<div class="box" style="display: none;">6</div> | |
<div class="box" style="display: none;">7</div> | |
<div class="box" style="display: none;">8</div> | |
<div class="box" style="display: none;">9</div> | |
<div class="box" style="display: none;">10</div> | |
<div id="footer" class="box">Footer</div> | |
</div> | |
<script src="https://rawgit.com/abicky/7c351a6ed1170d9a8c5f/raw/de61d7947118a28ca5abbc206b425157adad5240/sticky.js"></script> | |
<script> | |
document.addEventListener('DOMContentLoaded', function() { | |
// 動的に parent element の高さを変える(auto pager で要素が追加されるケースとか) | |
setTimeout(function() { | |
var boxes = document.getElementsByClassName('box'); | |
for (var i = boxes.length - 1; i >= 0; --i) { | |
boxes[i].style.display = 'block'; | |
} | |
}, 1000); | |
sticky(document.getElementById('header'), { top: 10 }); | |
sticky(document.getElementById('footer'), { bottom: 10 }); | |
}); | |
</script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Copyright 2015- Takeshi Arabiki | |
* License: MIT License (http://opensource.org/licenses/MIT) | |
*/ | |
var sticky = (function() { | |
var INTERVAL = 1000 / 60; // 60 FPS for setTimeout | |
var STICKY_POSITION = (function() { | |
var div = document.createElement('div'); | |
div.style.position = 'sticky'; | |
if (div.style.position === 'sticky') { | |
return 'sticky'; | |
} | |
div.style.position = '-webkit-sticky'; | |
if (div.style.position === '-webkit-sticky') { | |
return '-webkit-sticky'; | |
} | |
})(); | |
var requestAnimationFrame = window.requestAnimationFrame || | |
window.webkitRequestAnimationFrame || | |
setTimeout; | |
function isValid(options) { | |
if (options.top == null && options.bottom == null) { | |
return false; | |
} | |
if (options.top != null && options.bottom != null) { | |
return false; | |
} | |
return true; | |
} | |
function tickForTop(stickyElement, spacer, top) { | |
return function tick() { | |
var stickyElementHeight = stickyElement.offsetHeight; | |
var parentHeight = stickyElement.parentElement.offsetHeight; | |
spacer.style.height = stickyElementHeight + 'px'; | |
var parentOffsetTop = 0; | |
var parent = spacer.parentElement; | |
while (parent) { | |
parentOffsetTop += parent.offsetTop; | |
parent = parent.offsetParent; | |
} | |
var offsetTop = parentOffsetTop + spacer.offsetTop; | |
var scrollTop = document.body.scrollTop; | |
if (scrollTop > parentOffsetTop + parentHeight - stickyElementHeight - top) { | |
stickyElement.style.top = ''; | |
stickyElement.style.bottom = 0; | |
stickyElement.style.position = 'absolute'; | |
} else if (scrollTop > parentOffsetTop - top) { | |
stickyElement.style.top = top + 'px'; | |
stickyElement.style.bottom = ''; | |
stickyElement.style.position = 'fixed'; | |
} else { | |
stickyElement.style.top = 0; | |
stickyElement.style.bottom = ''; | |
stickyElement.style.position = 'absolute'; | |
} | |
requestAnimationFrame(tick, INTERVAL); | |
}; | |
} | |
function tickForBottom(stickyElement, spacer, bottom) { | |
return function tick() { | |
var stickyElementHeight = stickyElement.offsetHeight; | |
spacer.style.height = stickyElementHeight + 'px'; | |
var parentOffsetTop = 0; | |
var parent = spacer.parentElement; | |
while (parent) { | |
parentOffsetTop += parent.offsetTop; | |
parent = parent.offsetParent; | |
} | |
var offsetTop = parentOffsetTop + spacer.offsetTop; | |
var windowOffsetBottom = document.body.scrollTop + window.innerHeight; | |
if (windowOffsetBottom < parentOffsetTop + stickyElementHeight + bottom) { | |
stickyElement.style.top = 0; | |
stickyElement.style.bottom = null; | |
stickyElement.style.position = 'absolute'; | |
} else if (windowOffsetBottom <= offsetTop + stickyElementHeight + bottom) { | |
stickyElement.style.top = null; | |
stickyElement.style.bottom = bottom + 'px'; | |
stickyElement.style.position = 'fixed'; | |
} else { | |
stickyElement.style.top = null; | |
stickyElement.style.bottom = 0; | |
stickyElement.style.position = 'absolute'; | |
} | |
requestAnimationFrame(tick, INTERVAL); | |
}; | |
} | |
return function sticky(stickyElement, options) { | |
if (!isValid(options)) { | |
throw new Error("'top' or 'bottom', but not both, must be specified"); | |
} | |
if (STICKY_POSITION) { | |
stickyElement.style.position = STICKY_POSITION; | |
if (options.top != null) { | |
stickyElement.style.top = options.top + 'px'; | |
} else { | |
stickyElement.style.bottom = options.bottom + 'px'; | |
} | |
return; | |
} | |
var spacer = document.createElement('div'); | |
stickyElement.parentElement.insertBefore(spacer, stickyElement); | |
if (getComputedStyle(stickyElement.parentElement).position === 'static') { | |
stickyElement.parentElement.style.position = 'relative'; | |
} | |
var tick; | |
if (options.top != null) { | |
tick = tickForTop(stickyElement, spacer, options.top); | |
} else { | |
tick = tickForBottom(stickyElement, spacer, options.bottom); | |
} | |
requestAnimationFrame(tick, INTERVAL); | |
}; | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment