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.
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>...
Other Posts you might also like