Ben Nadel
On User Experience (UX) Design, JavaScript, ColdFusion, Node.js, Life, and Love.
Ben Nadel at CFUNITED 2010 (Landsdown, VA) with: Adam Tuttle and Laura Arguello
Ben Nadel at CFUNITED 2010 (Landsdown, VA) with: Adam Tuttle@TuttleTree ) and Laura Arguello

Using Position Absolute Inside A Scrolling Overflow Container

By Ben Nadel on
Tags: HTML / CSS

CAUTION: This is primarily a "note to self".

The other week, I tried to use absolute positioning inside a container that had "overflow: auto" enabled. And, somewhat to my surprise, the absolutely-positioned elements were rendered relative to the overflow "viewport," not to the "natural bounding box" of the content. This kind of threw me for a loop; and, it took me several days to come up with a solution. In retrospect, the solution is obvious. But, I had some weird mental block that was holding me back. All I had to do was wrap the content in non-overflow container and use said container as the anchor for positioning.


 
 
 

 
 
 
 
 

Run this demo in my JavaScript Demos project on GitHub.

To see what I mean, I've created a small demo in which I use the two approaches side-by-side. In the first approach, I'm using the overflow container as the position anchor. Then, in the second approach, I'm wrapping the content in an extra container in order to provide a non-overflow position anchor:

  • <!doctype html>
  • <html>
  • <head>
  • <meta charset="utf-8" />
  •  
  • <title>
  • Using Position Absolute Inside A Scrolling Overflow Container
  • </title>
  •  
  • <style type="text/css">
  •  
  • div.viewport {
  • border: 5px solid #CCCCCC ;
  • box-sizing: border-box ;
  • height: 300px ;
  • overflow: auto ;
  • width: 500px ;
  • }
  •  
  • span.box {
  • background-color: #FF3366 ;
  • color: #FFFFFF ;
  • padding: 7px 15px 7px 15px ;
  • position: absolute ;
  • }
  • span.tl { left: 0px ; top: 0px ; }
  • span.tr { right: 0px ; top: 0px ; }
  • span.bl { bottom: 0px ; left: 0px ; }
  • span.br { bottom: 0px ; right: 0px ; }
  •  
  • </style>
  • </head>
  • <body>
  •  
  • <h1>
  • Using Position Absolute Inside A Scrolling Overflow Container
  • </h1>
  •  
  • <h2>
  • With A Positioned Overflow Container
  • </h2>
  •  
  • <style type="text/css">
  •  
  • div.viewport-a {
  • padding: 5px 15px 5px 15px ;
  • /*
  • Here, the overflow container is, itself, acting as the anchor for the
  • positioned elements contained within. This caused the absolutely
  • positioned elements to anchor to the actual viewport of the container.
  • */
  • position: relative ;
  • }
  •  
  • </style>
  •  
  • <div class="viewport viewport-a">
  •  
  • <span class="box tl">Top Left</span>
  • <span class="box tr">Top Right</span>
  • <span class="box bl">Bottom Left</span>
  • <span class="box br">Bottom Right</span>
  •  
  • <p>Yay, content!</p><p>Yay, content!</p><p>Yay, content!</p><p>Yay, content!</p>
  • <p>Yay, content!</p><p>Yay, content!</p><p>Yay, content!</p><p>Yay, content!</p>
  • <p>Yay, content!</p><p>Yay, content!</p><p>Yay, content!</p><p>Yay, content!</p>
  • <p>Yay, content!</p><p>Yay, content!</p><p>Yay, content!</p><p>Yay, content!</p>
  •  
  • </div>
  •  
  • <!-- ---------------------------------------------------------------------------- -->
  • <!-- ---------------------------------------------------------------------------- -->
  •  
  • <h2>
  • With A Positioned Content Wrapper
  • </h2>
  •  
  • <style type="text/css">
  •  
  • div.viewport-b {
  • padding: 0px 0px 0px 0px ;
  • }
  •  
  • /*
  • Here, we're moving the position-anchoring off of the overflow container and
  • onto a content wrapper (contained within the overflow area). This allows the
  • absolutely positioned elements to anchor to the bounding box of the content,
  • not the viewport.
  • */
  • div.viewport-wrapper {
  • padding: 5px 15px 5px 15px ;
  • position: relative ;
  • }
  •  
  • </style>
  •  
  • <div class="viewport viewport-b">
  • <!--
  • By wrapping the content in a non-overflow container, we create an anchoring
  • box that is sized to the content, not to the viewport.
  • -->
  • <div class="viewport-wrapper">
  •  
  • <span class="box tl">Top Left</span>
  • <span class="box tr">Top Right</span>
  • <span class="box bl">Bottom Left</span>
  • <span class="box br">Bottom Right</span>
  •  
  • <p>Yay, content!</p><p>Yay, content!</p><p>Yay, content!</p><p>Yay, content!</p>
  • <p>Yay, content!</p><p>Yay, content!</p><p>Yay, content!</p><p>Yay, content!</p>
  • <p>Yay, content!</p><p>Yay, content!</p><p>Yay, content!</p><p>Yay, content!</p>
  • <p>Yay, content!</p><p>Yay, content!</p><p>Yay, content!</p><p>Yay, content!</p>
  •  
  • </div>
  • </div>
  •  
  • </body>
  • </html>

As you can see, the main difference between the two approach lies in where the "position: relative" style is applied. In the first approach, the relative position is applied to the "overflow" container; and, in the second approach, it's being applied to the content wrapper. Now, when we run this code, we get the following output:


 
 
 

 
 Using absolute position inside an overflow container. 
 
 
 

As you can see, in the first approach, the four corner boxes are positioned relative to the overflow viewport. And, in the second approach, the four corner boxes are positioned relative to the inner content wrapper, which creates a more "intuitive" bounding box for the content.

ASIDE: If you try the demo, you'll see that in the first approach the absolutely-positioned corner boxes scroll with the content. If you want the boxes to remain fixed in the corners, things get more complicated; especially in a context that may or may not present a scrollbar. When possible, you should avoid a user experience (UX) in which fixed elements overlap with scrollable content. Aside from nav-bars, it's a difficult experience to get right.

Looking back at this now, it seemed silly that this approach didn't occur to me immediately. But, at least I know now that I'll never forget it again.




Reader Comments

Post A Comment

You — Get Out Of My Dreams, Get Into My Comments
Live in the Now
Oops!
Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.