Need to keep a page element centered? Here's the code

Discussion in 'HTML & Website Design' started by Mike H., Sep 21, 2007.

  1. #1
    The code uses the attached sample image.

    The image will always be centered, regardless of window size, or vertical scrolling.

    The image will not return to the center, until the user stops vertically scrolling. Then, it will "smooth" scroll, back to the center.

    Tested in IE6 and FF2.

    The BODY height was for testing only, the code works with ANY body height. Some people run their mouth without TESTING code, because they can't write code, all they know how to do is criticize someone else's.


    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
       "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <title>Any Title</title>
    <script type="text/javascript">
    	
    	var useWidth = "185";  // this is the width of the image;
    	var useHeight = "139";  // this is its height;
    	var useFloat = "";
    	var slideTimer = "";	
    	var initTop = 0;	
    	var nScrollTop = 0;		
    	var prevVal = 0;
    	var currVal = 0;
    	var throttlePx = 0;	
    	var resizeTick = 0;
    	var IE = true;
    	if (navigator.appName != "Microsoft Internet Explorer"){IE = false}	
    
    	function realign(){
    
    		if (!IE)
    			{
    			 init();
    			}
    		if (IE && resizeTick == 2)
    			{		
    			 self.location.reload();	
    			}
    		resizeTick++;
    	}
    
    	function throttle(){	
    		
    		clearTimeout(slideTimer);
    		throttlePx += Math.floor((Number(nScrollTop) - Number(throttlePx)) * .5);			
    		useFloat.style.top = initTop + throttlePx + "px";	
    		if (Math.abs(throttlePx - nScrollTop) > 1)
    			{
    			 setTimeout("throttle()", 30);
    			}
    		else	{
    			 useFloat.style.top = Number(initTop) + Number(nScrollTop) + "px";
    			 slideTimer = setTimeout("stayHome()", 500);
    			}
    	}
    
    	function stayHome(){		
    		
    		if (document.documentElement && document.documentElement.scrollTop)
    			{
    			 nScrollTop = document.documentElement.scrollTop;	
    			 document.getElementById('nScroll').value = nScrollTop;		
    			}
    		else	{
    			 nScrollTop = document.body.scrollTop;	
    			 document.getElementById('nScroll').value = nScrollTop;			
    			}		
    		prevVal = document.getElementById('nScroll').value;
    		if (prevVal == currVal)
    			{				 
    			 clearTimeout(slideTimer);
    			 if (nScrollTop == 0)
    				{
    				 useFloat.style.top = initTop + "px";	
    				}	
    			 else	{	 
    			 	 if (Number(nScrollTop) + Number(initTop) != useFloat.offsetTop)
    					{					 
    					 throttle();					 
    					}
    				}
    			}
    		currVal = document.getElementById('nScroll').value;	
    		prevVal = currVal;		
    		slideTimer = setTimeout("stayHome()", 500);		
    	}
    
    	function init(){
    	
    		useFloat = document.getElementById('isFloat');
    		if(!document.body.scrollTop)
    			{
    			 useFloat.style.top = (document.documentElement.clientHeight - useHeight) / 2 + "px";
    			 useFloat.style.left = (document.documentElement.clientWidth - 15 - useWidth) / 2  + "px";  
    			}
    		else 	{
    			 useFloat.style.top = (document.body.clientHeight - useHeight) / 2  + "px";	
    			 useFloat.style.left = (document.body.clientWidth - 15 - useWidth) / 2 + "px";		 
    			}
    		initTop = useFloat.offsetTop;		
    		stayHome();		
    	}
    
    	onload = init;
    	onresize = realign;
    
    </script>
    </head>
    <body style="height:3967px">
    
    	<div id='isFloat' style="position:absolute; width:auto; border:1px solid black; background-color:#90ee90">
    		<div style="padding:3px"><input type="hidden" id="nScroll"><img src="./Rock_Hall.jpg" alt=""></div>
    	</div>
    
    </body>
    </html>
    
    Code (markup):
     

    Attached Files:

    Mike H., Sep 21, 2007 IP
  2. soulscratch

    soulscratch Well-Known Member

    Messages:
    964
    Likes Received:
    45
    Best Answers:
    0
    Trophy Points:
    155
    #2
    Useless with Javascript disabled. What if the height exceeds your 3xxx pixel height set on the body?
     
    soulscratch, Sep 21, 2007 IP
  3. deathshadow

    deathshadow Acclaimed Member

    Messages:
    9,732
    Likes Received:
    1,999
    Best Answers:
    253
    Trophy Points:
    515
    #3
    I can do you one better - look ma, no .js and a hell of a lot smoother.

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" 
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml" lang="en"><head>
    
    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
    
    <title>Untitled</title>
    
    <style type="text/css">
    * {
    	margin:0;
    	padding:0;
    }
    
    body,
    html {
    	height:100%;
    	overflow:hidden;
    }
    
    p {
    	margin:1em 0;
    }
    
    #fixed {
    	position:absolute;
    	left:50%;
    	top:50%;
    	width:30em;
    	height:16em;
    	line-height:16em;
    	margin:-8em 0 0 -15em;
    	text-align:center;
    	background:#CCC;
    	filter:alpha(opacity=80);
    	-moz-opacity:0.8;
    	opacity:0.8;
    }
    
    #container {
    	height:100%;
    	padding:0 0.5em;
    	overflow:auto;
    }
    
    </style>
    
    </head><body>
    
    <div id="fixed">
    	Your image or other 'fixed' stuff goes here.
    </div>
    
    <div id="container">
    	<p>
    		Some test para's to pad the height out for testing that the fixed image 
    		stays on top. Of course if you want it underneath, just set a z-index on
    		#container, and put anything you want on top at a higher z-index, and 
    		anything that would be below the content at a lower z-index. Of course 
    		this page uses the 'emulate position:fixed with absolute' method, so
    		you could affix your 'fixed' content anywhere you like.
    	</p><p>
    		It does have the drawback that to center something you need to know it's
    		width and height. A tiny bit of .js to adjust the dimensions and margin
    		'tricks' would simplify things a bit.
    	</p><p>
    		Some test text. Some test text. Some test text. Some test text.
    	</p><p>
    		Some test text. Some test text. Some test text. Some test text.
    	</p><p>
    		Some test text. Some test text. Some test text. Some test text.
    	</p><p>
    		Some test text. Some test text. Some test text. Some test text.
    	</p><p>
    		Some test text. Some test text. Some test text. Some test text.
    	</p><p>
    		Some test text. Some test text. Some test text. Some test text.
    	</p><p>
    		Some test text. Some test text. Some test text. Some test text.
    	</p><p>
    		Some test text. Some test text. Some test text. Some test text.
    	</p><p>
    		Some test text. Some test text. Some test text. Some test text.
    	</p><p>
    		Some test text. Some test text. Some test text. Some test text.
    	</p><p>
    		Some test text. Some test text. Some test text. Some test text.
    	</p><p>
    		Some test text. Some test text. Some test text. Some test text.
    	</p><p>
    		Some test text. Some test text. Some test text. Some test text.
    	</p><p>
    		Some test text. Some test text. Some test text. Some test text.
    	</p><p>
    		Some test text. Some test text. Some test text. Some test text.
    	</p><p>
    		Some test text. Some test text. Some test text. Some test text.
    	</p><p>
    		Some test text. Some test text. Some test text. Some test text.
    	</p>
    </div>
    
    </body></html>
    Code (markup):
    Which I've got a copy live here:
    http://battletech.hopto.org/html_tutorials/fixed_element.html

    It relies on the 'position fixed emulation' trick of setting body and html to overflow:hidden and height:100%. This lets us absolute position elements and have them act as position:fixed. Then we create a container set to overflow:auto for the content we want to scroll. Simple, effective, and works in all CSS capable browsers I've thrown the code at (unlike position:fixed).

    I also gave the floating div opacity to better illustrate it. Javascript would actually have an advantage in that you should be able to actually grab hold of the element and determine it's actual height dynamically at runtime (which you didn't, you're feeding the numbers by hand) - but if you know how big the element is this technique is a lot simpler/faster.

    Tested and working in IE 5.5, 6&7, FF, Opera and Safari. Validates XHTML 1.0 Strict. CSS will validate if you remove the three opacity declarations.

    and yes, it works regardless of body height OR screen size... and best of all no javascript. If worried about graceful degredation when CSS is off, you could put the fixed element after the #container as appropriate... and you can put it UNDER the content as well by just using z-index.

    300 bytes of CSS that updates instantly, or 2.2k of javascript that relies on a timer and can't keep up with the user scrolling. Gee, let me think...

    Enjoy.
     
    deathshadow, Sep 21, 2007 IP