Rick Strahl's Weblog  

Wind, waves, code and everything in between...
.NET • C# • Markdown • WPF • All Things Web
Contact   •   Articles   •   Products   •   Support   •   Advertise
Sponsored by:
Markdown Monster - The Markdown Editor for Windows

Absolute Positioning inside of a Relative Element with CSS


:P
On this page:

I have to admit that I'm not all that conversant with more advanced CSS layout concepts. When I'm working with page or component composition on a page I often struggle with how to get layout to work just right using CSS. Getting better with CSS usage and using minimal markup code in HTML is on the top of my todo list and I've been trying to apply some of this in some of the work that I'm doing at the moment.

One thing that I want to do frequently is to get items to pop at a specific position inside of another container. For example, I'm updating my internal photoalbum application to be more AJAX enabled and one of the things I allow is for interactive editing, sorting and deleting of images. For the delete operation I wanted to get the delete 'button' to pop up on a hover operation when the user hovers over the particular thumbnail component in admin mode.

The following screen shot demonstrates the delete button popping up on a hover operation and showing transparently over the main thumbnail content.

HoverDelete 

So essentially what's needed is to use absolute positioning, but within the context a given control. It seems that positioning should easily address this scenario, but if you're like me and and don't use absolute positioning much it's not really all that obvious how to get absolute positioning to constrain to a given container element.

So, there are a number of positioning modes available:

static
The default mode which is basic flow layout. Elements just flow using standard HTML layout flow.

relative
The element is laid out in the flow of the document, but can be offset by using top, left, right, top, bottom. These offsets can result in the content of the element overlaying (or underlaying) others.

absolute
An absolute position based on the next non-static element up the control hierarchy. If no relative elements are defined on the document the position will be document relative - ie. global absolute.

fixed
Like absolute except that the position is always relative to the viewport (browser window) and so the position of the element is fixed and doesn't scroll.

So in my example above, I have an unordered list of items that are of class photolistitem (that's the outer box for each thumbnail item). The items are floated left to give a table like flow and most importantly allow for nice interactive drag and drop sorting to work with jQuery Sortables (as part of jQuery UI).

The hovering server generated markup looks like this:

<ul id='ulThumbnailList'>
    <li id='f8492325' class='photolistitem'>
    <div>
    <a href="javascript:ShowImagePopup('f8492325');">
        <img src='tb_babybeach3.jpg' class='thumbnailimage' id='f8492325Img' title='babybeach3.jpg' />
    </a>
    </div>
    <div id='f8492325Notes'>
    Nowhere to go but up
    </div>
    <div class='deletethumbnail'>X</div>
    </li>
 
    <li id='c5b5fede' class='photolistitem'>
    <div>
    <a href="javascript:ShowImagePopup('c5b5fede');">
        <img src='tb_baerencoding.jpg' class='thumbnailimage' id='c5b5fedeImg' title='baerencoding.jpg' />
    </a>
    </div>
    <div id='c5b5fedeNotes'>
    Even bears have work to do in this technological age
    </div>
    <div class='deletethumbnail'>X</div>
    </li>
</ul>

The two relevant CSS elements attached to a <li> and <div> tag respectively:

.photolistitem
{
    display: block;
    float: left;    
    list-style-type: none;
    height: 220px;    
    width: 170px;    
    padding: 10px;
    border: solid 1px khaki;
    margin: 12px;
    background: steelblue;
    text-align: center;
}
.deletethumbnail
{                
    width:25px;            
    display: none;
    font-weight: bold;
    font-size: 12px;
    padding: 2px;
    cursor: pointer;    
    background: black;
    color: Red;
    opacity: 0.60;
    filter: alpha(opacity="60");
}

To position the element it would at first seem that absolute positioning is the right thing to use for the delete element. So adding absolute to .deletethumbnail was the first thing I tried.

position: absolute;
top: 1px;
right: 3px;    

This of course doesn't work as absolute in this context ends up being 'document absolute' and so the delete button would pop up in one place in the right top of the document for every thumbnail rather than inside of the container.

The key to get this to work is to ensure that the parant container is set to position: relative. In this case the the .photolistitem class is meant to be position: relative and the child - .deletethumbnail set to position: absolute. If you look at the spec for position:absolute it says that the absolute positioning is applied relative to the next element up the hierarchy that is not set to fixed.

The final style that works then becomes:

.photolistitem
{
    position: relative;
    display: block;
    float: left;    
    list-style-type: none;
    height: 220px;    
    width: 170px;    
    padding: 10px;
    border: solid 1px khaki;
    margin: 12px;
    background: steelblue;
    text-align: center;
}

.deletethumbnail
{                
    position: absolute;
    top: 1px;
    right: 3px;    
 
    background: black;
    color: Red;
    font-weight: bold;
    font-size: 12px;
    padding: 2px;
    opacity: 0.60;
    filter: alpha(opacity="60");
    display: none;
    margin-top: 3px;
    width:25px;            
    cursor: pointer;    
}
.deletethumbnail:hover
{
    opacity: 0.90;
    filter: alpha(opacity="90");    
}

And this works well - I now have a positioned pop up in a fixed position inside of another element.

I sure wish though that there were a couple of more explicit position tags available. absolute as it is now constrained by the relative to the container option and another that's always document relative. Even better would be a tag that allows automatically to take on the containers absolute/relative positioning without having to explicitly set position: relative on the container. Certainly that'd make it much easier to express the intent without accidentally affecting some other lower level container that might need absolute positioning that is document relative.

One thing that can be a problem with this approach is if you want to get elements to be document absolute. If you have any position: relative element in the element hierarchy the absolute position will only apply against THAT relative element rather than the document. To get a true absolute document position you actually have to remove the element from the its container and re-attach it to the document. This is why libraries like Prototype have functions like makeAbsolute() that ensure that an element is document absolute and ready to be moved around for things like drag and drop.

<shrug> It is what it is I guess, and at least the above approach works in most cases, but it's far from obvious... as are so many things when it comes to CSS layout <g>...

Posted in CSS  HTML  

The Voices of Reason


 

Milan Negovan
March 28, 2008

# re: Absolute Positioning inside of a Relative Element with CSS

The relatively or absolutely positioned element becomes the "containing block". I have a writeup here: http://aspnetresources.com/blog/ms_ajax_domelement_remarks.aspx

Rick Strahl
March 28, 2008

# re: Absolute Positioning inside of a Relative Element with CSS

Great link Milan. Reinforces the point that it'd be useful to a document absolute keyword though so that an element can truly be pushed to document absolute positioning regardless of it's element hierarchy.

Doug Dodge
March 28, 2008

# re: Absolute Positioning inside of a Relative Element with CSS

Hey Rick,

Have you ever looked at the www.projectseven.com website? These folks have a very good grasp of css-related issues.

Maybe something there you could use.

Best,

DD

Rick Strahl
March 28, 2008

# re: Absolute Positioning inside of a Relative Element with CSS

@Doug - yeah I've used this and Zen Garden a bit. The problem I have is finding good content when you need it and are stuck. CSS lets you do a great many things, but many features are not easy to reference in the way you can look up an API call on MSDN or a vendor site typically <g>...

Josh Stodola
March 28, 2008

# re: Absolute Positioning inside of a Relative Element with CSS

I agree, and have thought the same thing for years. It's completely unsemantic to move an element outside of the normal markup hierarchy just for the sake of document-level absolute positioning. Hopefully CSS3 will have a solution for this, which I think is scheduled to release sometime next century.

johny why
March 30, 2008

# re: Absolute Positioning inside of a Relative Element with CSS

bravo, Rick! just what i needed to position controls within a ascx WebUserControl.

thanks!

Doug Dodge
March 30, 2008

# re: Absolute Positioning inside of a Relative Element with CSS

Rick, Righto. I forgot to mention that the ptoject seven folks have a pretty active list server and are usually quite responseive.

Best,

DD

harvey mushman
March 31, 2008

# re: Absolute Positioning inside of a Relative Element with CSS

I would like to hear more about drag and drop of the thumbnails of your photo collection!! In specific, can you read the sorted last after they are re-arranged?

--<s>

Rick Strahl
March 31, 2008

# re: Absolute Positioning inside of a Relative Element with CSS

@Jim - yeah I can read the sorted images back. I use jQuery which makes this a breeze. Essentially I make real time changes on the client to the sort order and captions, then submit them to the server. When I submit I collect all the list elements and pick up each ID and caption text then use an AJAX call to send that data to the server. The items picked up will be in the correct order so on the server all I have to do is assign a new sort order as I iterate over the items and then write them out to disk.

The magic of jQuery (or other tool) selectors make this a breeze.

none
September 04, 2008

# re: Absolute Positioning inside of a Relative Element with CSS

This was very useful, thank you!

Bryan
September 10, 2009

# re: Absolute Positioning inside of a Relative Element with CSS

These combinations of display and position are like alchemy. Thanks a million for this article, it helped me achieve exactly what I wanted, which I was beginning to think was impossible. One more tidbit for the toolbox.

West Wind  © Rick Strahl, West Wind Technologies, 2005 - 2024