Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Table row won't contain elements with position:absolute

Tags:

html

css

I have a table like this:

<table cellspacing="0">
    <tr>
        <td>Row 1</td>
        <td><button>Button 1</button></td>
    </tr>
    <tr>
        <td>Row 2</td>
        <td><button>Button 2</button></td>
    </tr>
    <tr>
        <td>Row 3</td>
        <td><button>Button 3</button></td>
    </tr>
</table>

I wanted to absolutely position each button at the top right of the table row, so I used this CSS, expecting the <tr> to contain the <button>:

tr {
    position:relative;
}
button {
   position:absolute;
   top:0;
   right:0;   
}

However, the buttons are all stacked on top of each other in the same place. It normally works fine using <div>s, except it will still behave this way when using display:table-row which I found out while testing, and came as a surprise to me.

Demo: http://jsfiddle.net/QU2zT/1/

Note: My actual markup is more complex, and the element I'm trying to position might appear anywhere in any table cell in it's row, which is why I believe I need position:absolute.

  1. Why does this happen?
  2. How can I work around this using CSS, without altering the markup?

EDIT: The results are different in Firefox than they are in Chrome and IE9 (haven't tested beyond that). FF is a complete failure, while the other browsers only fail to contain the "divs with table display" setup, seen in the demo.

like image 800
Wesley Murch Avatar asked Dec 14 '11 08:12

Wesley Murch


People also ask

Why does position absolute not working?

If you are placing an element with absolute position, you need the base element to have a position value other than the default value. In your case if you change the position value of the parent div to 'relative' you can fix the issue.

Does float work with position absolute?

Generally speaking, float is a relative positioning statement, since it specifies the position of the element relative to its parent container (floating to the right or left). This means it's incompatible with the position:absolute property, because position:absolute is an absolute positioning statement.

How do you position an element with an absolute position?

Absolute An element with position: absolute is removed from the normal document flow. It is positioned automatically to the starting point (top-left corner) of its parent element. If it doesn't have any parent elements, then the initial document <html> will be its parent.

What can I use instead of position absolute?

Fixed. The fixed value is similar to absolute as it can help you position an element anywhere relative to the document, however this value is unaffected by scrolling.


3 Answers

Use this hack as position: relative is ignored in <tr> (thanks to https://github.com/w3c/csswg-drafts/issues/1899)

tr {
  transform: scale(1);
}
td {
  position: absolute;
  top:0;
  right:0
}
like image 114
Bharat Parmar Avatar answered Oct 21 '22 10:10

Bharat Parmar


To quote from the spec:

The effect of 'position:relative' on table-row-group, table-header-group, table-footer-group, table-row, table-column-group, table-column, table-cell, and table-caption elements is undefined.

EDIT:

The only solution that I can see involves using :last-child (ie. no IE < 9) and good old vertical-align and text-align:

td:last-child {
    vertical-align: top;
    text-align: right;
    padding: 0;
    margin: 0;
}

Here's a working demo: http://jsfiddle.net/QU2zT/15/

I would also like to add that if you really don't want to change your markup and need to support IE you can use this solution combined with JavaScript.

PS: I haven't looked at (and won't comment on) the solution using divs as I see no point in writing that much markup to obtain a table, when there is already one. It will only be a maintenance nightmare.

like image 19
deviousdodo Avatar answered Oct 21 '22 09:10

deviousdodo


Apparently, the only pure CSS solution is to set display:block on the tr (including implicitly via use of float). However, this severely breaks table layouts and didn't work out very well for me.

I decided to bite the bullet and wrap the content of the cell in a div, as suggested in these answers:

  • https://stackoverflow.com/a/8312358/398242
  • https://stackoverflow.com/a/7629567/398242
<tr>
    <td>
        <div style="position:relative">
            <button style="position:absolute"></button>
        </div>
    </td>
</tr>

This still has a disadvantage: since our position:relative element must be inside a table cell, it only works in the last cell of the table row (when the goal is to have the absolute element positioned relative to the entire row, in the top right corner). This also doesn't seem to position the element correctly as seen here: http://jsfiddle.net/QU2zT/25/

This seems to be the best we can do, without abandoning table markup or breaking it's rendering.

like image 12
Wesley Murch Avatar answered Oct 21 '22 10:10

Wesley Murch