I am trying to create a page where there are multiple sections and as you scroll the header that you are on is always shown at the top o开发者_如何转开发f the page (in a fixed element). I want to achieve the same effect as on the iPhone where as you scroll it "pushes" the old header out of the way and replaces it.
I have seen it done with lists, but I want to do it with multiple HTML5 sections.
For example:
<section>
<h1>Header 1</h1>
<p>Text for section</p>
</section>
<section>
<h1>Header 2</h1>
<p>Text for section</p>
</section>
Does anyone have any idea?
Thanks
I've wanted to do this for a long time and Seeing @AlienWebguy's work inspired me to finally take it on. His JSFiddle was impressive, but needed a lot of work. I think this solution is pretty much ready to use in my production app.
http://jsfiddle.net/RichardBronosky/VMnnr/
HTML:
<body>
<div class="tableview">
<div id="header1" class="header">
<h2>Header 1</h2>
</div>
<div id="header1_content">
<p>
header1_content1
</p>
<p>
header1_content2
</p>
<p>
header1_content3
</p>
</div>
<div id="header2" class="header">
<h2>Header 2</h2>
</div>
<div id="header2_content">
<p>
header2_content1
</p>
<p>
header2_content2
</p>
<p>
header2_content3
</p>
</div>
<div id="header3" class="header">
<h2>Header 3</h2>
</div>
<div id="header3_content">
<p>
header3_content1
</p>
<p>
header3_content2
</p>
<p>
header3_content3
</p>
</div>
</div>
</body>
CSS:
body {
font-family:Helvetica,Arial,san-serif;
}
div.tableview {
background-color:#CCC;
}
.tableview p:nth-child(odd) {
background-color:#FFF;
}
.tableview p:nth-child(even) {
background-color:#F0F0F0;
}
.tableview p {
padding:8px;
margin:1px 0px 1px 0px;
}
body, .tableview p:last-of-type, .tableview p:first-of-type, .tableview .header h2 {
margin:0px;
}
.tableview .header {
background-color:#333;
color:#FFF;
width:100%;
position:relative;
}
.tableview .header h2 {
padding:8px 4px 8px 4px;
}
.tableview .fixed {
position:fixed;
top:0;
left:0;
}
JAVASCRIPT: (relies on jQuery)
// From: http://jsfiddle.net/AlienWebguy/mvtP7/1/ via: http://stackoverflow.com/questions/6720847
$(function(){
var lastScrollTop = 0;
// When the first header is given a fixed position, the inline content that follows with shift up.
el = $('.header').first();
// To over come this: clone it, make it invisible, remove id tags from it and its children, attach it before the original
el.before(el.clone(false).css({'visibility':'hidden'}).removeAttr("id").find("*").removeAttr("id").end()).addClass('fixed');
$(window).scroll(function(event){
var currentScrollTop = $(this).scrollTop();
$('.header').each(function(){
if($(this).hasClass('fixed')){
if (currentScrollTop > lastScrollTop){
console.log('scrolling down');
var _next_header = $(this).nextUntil('.header').next('.header');
if($(_next_header).length > 0){
if($('body').scrollTop() > $(_next_header).offset().top){
console.log("Bottom of header hit top of next header")
$(this).removeClass('fixed');
$(_next_header).addClass('fixed');
}
}
} else {
console.log('scrolling up');
var _prev_header = $(this).prevUntil('.header').prev('.header');
if($(_prev_header ).length > 0){
if($('body').scrollTop() < $('.fixed').next().offset().top-$('.fixed').height()){
console.log("Top of header hit bottom of previous content box")
$(this).removeClass('fixed');
$(_prev_header).addClass('fixed');
}
}
}
}
});
lastScrollTop = currentScrollTop;
});
});
Here you go, pretty similar:
http://jsfiddle.net/AlienWebguy/mvtP7/1/
HTML:
<div id="header1" class="header fixed">
<h2>Header1</h2>
</div>
<div id="header1_content">
<p>Lorem ipsum dolor sit amet...</p>
</div>
<div id="header2" class="header relative">
<h2>Header2</h2>
</div>
<div id="header2_content">
<p>Lorem ipsum dolor sit amet...</p>
</div>
<div id="header3" class="header relative">
<h2>Header3</h2>
</div>
<div id="header3_content">
<p>Lorem ipsum dolor sit amet...</p>
</div>
CSS:
p {
background-color:#F0F0F0;
}
.header {
background-color:#CCC;
width:100%;
top:0;
left:0;
}
.header h2 {
margin:20px;
}
.fixed {
position:fixed;
}
.relative {
position:static;
}
#header1_content {
margin-top:80px;
}
JQuery:
$(function(){
var lastScrollTop = 0;
$(window).scroll(function(event){
var currentScrollTop = $(this).scrollTop();
if (currentScrollTop > lastScrollTop){
// Scrolling down
$('.header').each(function(){
if($(this).hasClass('fixed'))
{
var _next_header = $(this).nextUntil('.header').next('.header');
if($(_next_header).length > 0)
{
if(($(this).offset().top + $(this).height()) >= $(_next_header).offset().top)
{
// Bottom of header hit top of next header
$(this).removeClass('fixed').addClass('relative');
$(_next_header).removeClass('relative').addClass('fixed');
}
}
}
});
}
else
{
// Scrolling up
$('.header').each(function(){
if($(this).hasClass('fixed'))
{
var _prev_header = $(this).prevUntil('.header').prev('.header');
if($(_prev_header ).length > 0)
{
if($(this).offset().top <= ($('#' + $(_prev_header).attr('id') + '_content').offset().top + $(this).height()))
{
// Top of header hit bottom of previous content box
$(this).removeClass('fixed').addClass('relative');
$(_prev_header).removeClass('relative').addClass('fixed');
}
}
}
});
}
lastScrollTop = currentScrollTop;
});
});
So essentially what we're doing is creating some basic collision detection. When we scroll down, we detect if the bottom of the current header collides with the top of the next header. If it does, we swap it out. When we scroll up, we detect if the top of the current header collides with the bottom of the previous content container and make the swap.
Taking this to the next level to more accurately emulate the iPhone menu, you'd probably want to re-position the headers within the DOM on the fly when they collide, which would give that illusion of one "pushing the other out of the way", then once the previous one is off the screen, you'd apply the fixed positioning to the new header. This demo should get you on the right track at least :)
Hope this helps!
I haven't seen the iphone version you talk about but from how you describe it I have an idea of what it is like.
The problem as I see it is that the headers have two contexts. Firstly they are in the page and secondly they are in a fixed element at the top of the page. Also you haven't said but I presume that if you were to scroll the otherway the headers would have to change in the opposite direction.
One approach would be to give the fixed element a fixed height and hidden overflow. Then have an innerdiv that contains a copy of all the pages headers. Give the inner div relative positioning. In javascript add an event to all the headers that are in the page that fires when they reach the top of the window to trigger the animation. Use jQuery to animate the position of the fixed element's innerdiv so that it reveals the next header.
精彩评论