32

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.

Wesley Murch
  • 95,417
  • 36
  • 177
  • 220
  • Works for me in Chrome, wich browser are you using? – scumah Dec 14 '11 at 09:04
  • Using FF8 the problem is the worst, but other browsers seem to have issues too with the `
    ` setup using the various `display` settings that emulate tables (second example in demo), see edit.
    – Wesley Murch Dec 14 '11 at 09:13
  • 2
    Check [this SO question](http://stackoverflow.com/questions/5148041/does-firefox-support-position-relative-on-table-elements). Basically, adding `display:block;` to the cell or row would do the trick, but it messes the whole table styles up. You could try adding an element inside the cell and giving it relative position. More markup, less headache :P – scumah Dec 14 '11 at 09:24
  • http://stackoverflow.com/questions/7629326/position-relative-in-firefox/7629567#7629567 – thirtydot Dec 14 '11 at 09:44
  • @thirtydot: The wrapper trick doesn't seem to work either in any browser: http://jsfiddle.net/QU2zT/18/ – Wesley Murch Dec 14 '11 at 09:46
  • Your `div`s aren't wrapping the `button`s, which are the things that have `position: absolute` :) – thirtydot Dec 14 '11 at 09:48
  • @thirtydot: Oops, yeah time for me to get some sleep. Looks like it works, I'll have to decide a solution in the morning. Thanks. – Wesley Murch Dec 14 '11 at 09:52
  • @Madmartigan Well, if you can change your markup, simply add a class on the table cells with a button in them, and use vertical-align and text-align on them, as I wrote in the example below. – deviousdodo Dec 14 '11 at 09:55
  • Thanks scumah, that solved my problem – Stephan Muller Dec 21 '11 at 09:29

4 Answers4

44

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
}
Jesse
  • 3,093
  • 6
  • 22
  • 35
Bharat Parmar
  • 1,684
  • 1
  • 16
  • 21
  • yes true its a hack so it may behave different on different browser – Bharat Parmar Oct 20 '18 at 07:28
  • Here is the bug report for chromium for anyone who wants to keep track of the progress: https://bugs.chromium.org/p/chromium/issues/detail?id=417223 Although I'm a little confused considering the conversation in the csswg thread linked above if it's still considered a bug. – Jon F. May 22 '19 at 20:55
  • thanks a lot... – Amir Jan 27 '21 at 09:19
  • Update: `position: relative` works on Firefox (>88), the `transform` "hack" in Chrome and soon will be no [longer necessary](https://github.com/w3c/csswg-drafts/issues/1899#issuecomment-827141293), but unfortunately neither of them work in Safari. – renatodeleao May 09 '21 at 09:12
19

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.

deviousdodo
  • 9,023
  • 2
  • 27
  • 33
  • 1
    +1 for link to the spec; that's interesting - the undefined behavior. In the [demo](http://jsfiddle.net/QU2zT/) I actually have `table, tr, td {position:relative;}` and not even the `table` will contain it (have to add padding to body to notice). Can you make a working demo or have another solution? – Wesley Murch Dec 14 '11 at 09:35
  • It's still a mystery about the `
    ` elements with `display:table-*` showing this problem though isn't it? Or does this part of the spec actually include that?
    – Wesley Murch Dec 14 '11 at 09:42
  • @Madmartigan I've updated my answer with (somewhat of) a solution. As I said I haven't looked at the `div` implementation, but if you use `display: table-*`, all the rules apply as with normal tables (but there may be some quirks - that's why I don't like going this path). – deviousdodo Dec 14 '11 at 09:50
  • The solution you posted still relies on markup and element placement which won't fly for me unfortunately (it means lots of work editing template files...): http://jsfiddle.net/QU2zT/24/ The div thing was just an experiment, but the results were unexpected so I included it. I guess I'll have to make some concessions, thanks again. – Wesley Murch Dec 14 '11 at 09:54
  • Yeah, but you should have mentioned this in your question :) My answer doesn't change any markup (as you requested) but I didn't know you have any other content in the cell... Regarding element placement, this could have been solved with Javascript. – deviousdodo Dec 14 '11 at 09:57
  • I did mention it: "Note: My actual markup is more complex...". Usually with absolute positioning, the surrounding content doesn't matter. – Wesley Murch Dec 14 '11 at 10:01
  • By the way, if it's difficult to change the markup, you can write a bit of javascript that will add a wrapper div around the cells which have a button and you can use the positioning as thirtydot suggested. – deviousdodo Dec 14 '11 at 10:01
11

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:

<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.

Community
  • 1
  • 1
Wesley Murch
  • 95,417
  • 36
  • 177
  • 220
3

http://jsfiddle.net/QU2zT/23/

table, tr, td{
    width: 100%;
}
tr {
 background:#cde;
 float: left;
 clear: both;
}
Joonas
  • 7,027
  • 9
  • 36
  • 60
  • Thanks for the idea, it seemed to help FF, but as scumah mentioned in the comments - it messes up the way the rows display. See the difference in [block](http://jsfiddle.net/QU2zT/6/) VS [table-row](http://jsfiddle.net/QU2zT/12/) – Wesley Murch Dec 14 '11 at 09:32
  • Still the same side effects, even after adding `width:100%;`. This is actually what I tried at first, but it really broke the layout not having the table cells take up the entire row width. +1 because this technically seems to work, but I don't think I could really use this method. – Wesley Murch Dec 14 '11 at 09:39
  • Wow that's odd, it seems to work. I'll have to check up on this in the morning and see what kind of trouble `td {width:100%}` is causing, I'm out of gas for the night (it's 5am here). Thanks again. – Wesley Murch Dec 14 '11 at 09:59
  • Yep, this is breaking the layout pretty bad. Thanks for the help, I think I'll have to go with the wrapper div solution since it can't be done with CSS. – Wesley Murch Dec 14 '11 at 21:26
  • @Madmartigan I wouldnt say that it cant be done, not quite yet. Like it is now it seems to work, at least how I expect it to work. How is it breaking the layout? – Joonas Dec 14 '11 at 21:58
  • See image: http://i.stack.imgur.com/agSQL.png It's like trading one problem for another, not worth it IMO. Setting these styles on table elements has all kinds of side effects that would have to be patched. (BTW the absolute positioned buttons aren't in the image, my mistake - they are little X's for deleting rows but no rows were eligible when I took the screen shot) – Wesley Murch Dec 14 '11 at 22:07
  • @Madmartigan Oh, well if I had known that it has structure like that I would've known that it won't work to begin with and yea, I don't see point in messing with this code any longer. Howevver.. I would suggest maybe trying js.. This could maybe be usable if you are already using jquery ui.. (cause it uses that for the positioning) http://jsfiddle.net/QU2zT/29/ It can be done without jquery ui but it's more work :D (it's not perfect anyhow..) – Joonas Dec 14 '11 at 22:34
  • Thanks, I'll check it out (I am using jquery UI). I just hate having to use js for stuff like this, know what I mean? I didn't know about this "bug" until yesterday. Thanks again, "case closed" as far as I'm concerned. – Wesley Murch Dec 14 '11 at 22:40
  • @Madmartigan I accidentally left `position`, `top` and `right` into the button element which are unnecessary. Yea, I know exactly what you mean.. – Joonas Dec 14 '11 at 22:41