I need to position something with absolute positioning inside a td. To get around the fact that a td is undefined when setting it to relative, I use a div set to relative inside my td then inside that div I have an inner div set to absolute. This all works great when I have content filling up the td. When I set the content of the td to display none then the absolute positioning gets all screwed up.
Does anyone know why this would be.
HTML:
<table>
<tr>
<td>
<div class="relative">
<div class='absolute'>
<p>A</p>
</div>
</div>
<div class="slot"></div>
<div class="slot"></div>
</td>
<td>
<div class="relative">
<div class='absolute'>
<p>B</p>
</div>
</div>
<div class="slot hidden"></div>
<div class="slot"></div>
</td>
</tr>
</table>
And CSS:
td{
border:1px solid red;
width:100px;
height:60px;
vertical-align:bottom;
}
.slot{
width:100px;
height:29px;
background-color:#999;
border:1px dashed blue;
}
.relative{
position:relative;
}
.absolute{
position:absolute;
top:5px;
left:5px;
}
.hidden{
display:none;
}
And a live version: http://jsfiddle.net/HgEtQ/
In the fiddle above you can see the first table cell works correctly. The absolutely positioned div is in the correct space. The second one has hidden the top slot and now the absolute positioning is not in the top left corner anymore. If you take out both slots then it really screws up the absolute positioning. I need to positioning it absolute because some of the elements will be shifted depending on the element.
There are a couple things going on here.
You have this:
td {
/*...*/
vertical-align:bottom;
}
That will push the content of the cells to the bottom.
Also, an absolutely positioned element is removed from the normal flow so it won't contribute to its parent's height:
It is removed from the normal flow entirely (it has no impact on later siblings). An absolutely positioned box establishes a new containing block for normal flow children and absolutely (but not fixed) positioned descendants.
In particular, this means that your div.relative elements have a height of zero but they will still have an upper left corner so your absolute positioning offsets are anchored somewhere.
Then you have <div class="slot hidden"> and the hidden removes the <div> from the layout so you effectively have just this:
<div class="relative"></div> <!-- Height zero -->
<div class="slot"></div> <!-- Height 29px -->
That combined with the vertical-align: bottom means that your second div.absolute will be positioned 5px from the top of the div.slot and that is 25px from the bottom of the table cell.
The first cell works fine because the two visible div.slot elements push the div.relative right to the top of the cell, then the div.absolute is positioned 5px from the top of the div.relative and that is 5px from the top of the table cell.
Unfortunately, adding position: relative to a <td> is a bit dodgy as far as browsers go so you'll need some hackery to get your positioning right while keeping vertical-align: bottom. You could re-structure the <td>s like this:
<td>
<div class="relative">
<div class='absolute'>
<p>A</p>
</div>
</div>
<div class="nonsense">
<div class="slot"></div>
<div class="slot"></div>
</div>
</td>
And the CSS like this:
td{
border:1px solid red;
width:100px;
height:60px;
vertical-align: top;
}
.slot{
width:100px;
height:29px;
background-color:#999;
border:1px dashed blue;
}
.relative {
position:relative;
}
.nonsense {
height: 62px; /* td[height] + 2 for the borders */
display: table-cell;
vertical-align: bottom;
}
.absolute{
position:absolute;
top:5px;
left:5px;
}
.hidden{
display:none;
}
Live example: http://jsfiddle.net/ambiguous/aV4nT/
Or you could use visibility: hidden:
hidden
The generated box is invisible (fully transparent, nothing is drawn), but still affects layout. Furthermore, descendants of the element will be visible if they have 'visibility: visible'.
instead of display: none for your .hidden class:
.hidden {
visibility: hidden;
}
This will leave both div.slot elements taking up space and affecting the layout but only the second one will be seen.
Live example: http://jsfiddle.net/ambiguous/RcdNh/
Related
I have a CSS
.nav {
width: 200px;
line-height: 50px;
float: left;
}
.content {
margin: 0px 0px 0px 230px;
}
.container {
border: 1px solid red;
}
And here is the HTML
<body>
<div class="container">
<div class="nav">Some text
<br>more text
<br>even more text
</div>
<div class="content">
<h1>Home</h1>
<p>Text paragraph</p>
</div>
</div>
</body>
This gives me menu on the left and the content on the right. And a red box around the content on the right, but only the half menu on the left.
But I would like to have the red box also around the complete nav-div Can anyone help?
Thanks
Teddy
Add overflow:auto to your container div's CSS:
.container {
border: 1px solid red;
overflow:auto;
}
jsFiddle example
Floating the child div removes it from the flow of the document and the container essentially collapses as if it didn't exist. Adding the overflow restores the behavior you're after.
I think this is a quick fix if you float your container it should solve the problem your having. See here http://jsfiddle.net/1540sscj/
.container {
border: 1px solid red;
float:left;
width:100%;
}
Floating an element removes it from the normal flow of the page with one side effect being that its parent's dimensions won't expand to fit it.
So, what you need to do is clear the floated item. The best way to do this, without using additional markup or using the overflow property, which may cause other issues, depending on your layout, is to use the :after pseudo class on the parent element, like so:
.nav{
width:200px;
line-height:50px;
float:left;
}
.content{
margin:0px 0px 0px 230px;
}
.container{
border:1px solid red;
}
.container::after{
clear:both;
content:"";
display:block;
height:0;
width:0;
}
<body>
<div class="container">
<div class="nav">Xalsdk fjaskldfj alskdfj asädf<br>asdf<br>asdf</div>
<div class="content">
<h1>Home</h1>
<p>Bla bla.</p>
</div>
</div>
</body>
More information on clear
More information on pseudo elements
Best way imho would be to add a div like:
<div style="clear:both;"></div>
Under your floating elements: FIDDLE
This way you don't need to use oveflow:hidden on your container that may give you problems once you have more stuff in your project.
Also you shoudn't use a margin-left for your content as the previous element is already floating left. The best practise if you want to add some margin between nav and content would be to make your content float left as well and then use margin left (the exact size you want) with respect of the nav and not with the left of the window.
Finally, if you don't want to add the clear:both div to the html you could add somethign like
.content:after {
content:'';
display:block;
clear: both;
}
it's a bit less browser (old ones) compatible but cleaner
You have to add overflow:auto to .container in your css
Check my js fiddle
Also the css that modified.
.container {
border: 1px solid red;
overflow:auto;
}
Description of property overflow from MDN
The overflow property specifies whether to clip content, render
scrollbars or just display content when it overflows its block level
container.
I want to create a div that's wider than its parent, and i found many solutions.
Almost all of them say something that looks like this:
position:absolute;
left:0;
right:0;
(for example: How to expand child <div> with 100% of body width?)
This is indeed a solution, but there is only one little problem.
situation:
(jsfiddle)
<style>
.parent
{
width:70%;
padding: 1%;
}
.fullwidth
{
position:absolute;
left:0;
right:0;
}
</style>
<div class="parent">
<div>
<h1>
This is a normal div.
This text is visible
</h1>
</div>
<div class="fullwidth">
<h1>
This is a full width div.
</h1>
</div>
<div class="normal-div">
<h1>
This is a normal div
This text is hiding behind fullwidth div
</h1>
</div>
</div>
In this example, the second normal div is hiding behind the fullwidth div, because the fullwidth is absolute positioned.
So, how can you do this without having the divs hide behind the fullwidth div?
You need to make two changes to the "normal div":
Position relative (the default is static)
Set z-index below that of the absolute positioned div
And one change to the absolute div (set its z-index below the "normal" div).
http://jsfiddle.net/gx4p2red/3/
.fullwidth
{
position:absolute;
left:0;
right:0;
/*Testing only*/
background-color: green;
z-index: 0;
}
/*Testing only*/
.normal-div
{
background-color:red;
position: relative;
z-index: 1;
}
Html:
<br/><br/><br/><br/><br/>
<table>
<tr>
<td class="container">
<button class="del">delete</button>
</td>
</tr>
</table>
<br/><br/><br/><br/><br/>
<div class="container">
<button class="del">delete</button>
</div>
Css:
.container {
position: relative;
border: 1px solid red;
height: 50px;
width: 200px;
}
.del {
position: absolute;
top: 3px;
right: 3px;
}
Why the button inside a div will be placed on the top right corner of the div, but the one inside a td will be placed outside the table?
How to fix it?
See active demo: http://jsfiddle.net/Freewind/d6Tug/
I think it has something to do with the display style of a td, which is table-cell. If you set it to display:block, it will work correctly.
Just add display:block to your .container style.
As freewind pointed out, it would be better to use inline-block if it is supported in your browser for td since td's are usually displayed in a row.
Giving an element position:absolute; places it relative to its containing block. Since a table cell is not considered a block container (unlike a div), it places it relative to the document body itself. top:3px; brings it 3px from the top border of the document and right:3px; moves it 3px from the right border.
http://reference.sitepoint.com/css/position
I have a column of text, with wide margins on either side. Below it, I have a full-width section of data (in tabular format).
I can align these against each other quite readily. My problem is that there is a 'tab' that sits on top of the table section. It's narrow enough that it doesn't interfere with the center column of text, and the layout calls for it to slide up into the white space to the left of the text.
The easy solution would a position:absolute, with top:foopx to slide it up relative to the rest of the div. The only problem is, the tab's height is dynamic. I need to somehow to top:'height'px, but (obviously) CSS doesn't contain anything for dynamic values.
What I need to do is align the bottom edge of the 'tab' against the top edge of the containing div, and I cannot for the life of me figure out any CSS statement that does that. I'd rather avoid a javascript based approach (e. g. at runtime get the height of the tab, then set top equal to that height) because the entire bottom div is refreshed from time to time using an AJAX call, and adjusting the height in that process causes the page to 'jitter' on the update (not sure why it doesn't happen without the height update; the jitter is in a separate section of the code).
Requested code example:
<html>
<head>
<style>
#smallColumn
{
float:left;
width:100px;
height:100px;
background:#000;
margin:5px;
}
#fullColumn
{
float:left;
width:200px;
height:300px;
background:#000;
margin:5px;
}
#bottomDiv
{
position:relative;
}
#tab
{
position:absolute;
top:-40px;
}
</style>
</head>
<body>
<div id="smallColumn">a</div>
<div id="fullColumn">b</div>
<div style="clear:both"></div>
<div id="bottomDiv">
<div id="tab">Tab</div>
<hr />
DATA DATA DATA
</div>
</body>
</html>
Use top margins, the appropriate display properties and vertical-align:bottom. See the code below + comments for an explanation. You have to set a height and negative margin-top value which is larger than the actual height of the tab's content. Otherwise, the content may jump back to the top.
Relevant HTML/CSS:
<div id="cont">
<div id="tab">
<div id="tab-fix">
Tab
</div>
</div>
Rest of content
</div>
#cont {
margin-top: 30px; /*Reserve space*/
height: 100px;
background: lightgreen;
}
#tab {
display: table; /* Necessary for the application */
margin-top: -30px;/* Move tab to the top*/
}
#tab-fix {
height: 30px; /* Expecting the height to not exceed 30px*/
display: table-cell;
vertical-align: bottom; /* Aligns the content at the bottom*/
}
Fiddle: http://jsfiddle.net/stEW3/2/
Update2
So this is a tough problem to solve! The only thing I could think of was to put a wrapper around the tab. That wrapper needs to be relatively positioned and have a height equal to that of the tab. Then you can use absolute and negative top of 100%.
http://jsfiddle.net/mrtsherman/BC8Xr/2/
Update
With posted code I now understand. How about using absolute and specifying a bottom value of 0?
http://jsfiddle.net/mrtsherman/BC8Xr/
<div id="content">
<div id="smallColumn">a</div>
<div id="fullColumn">b</div>
<div style="clear:both"></div>
<div id="bottomDiv">
<div id="tab">Something</div>
<hr />
</div>
</div>
#content { border: 1px solid red; position: relative; }
#bottomDiv
{
position:absolute;
bottom: 0px;
}
#tab
{
/*
position:absolute;
top:-40px;
*/
}
Old
Without html structure and a somewhat vague description this is a bit hard to decipher. But this is what I think you mean:
http://jsfiddle.net/mrtsherman/VM99L/
Basically you want the tab above the tabular data to be drawn up into the div before it. You can use a negative top margin for this. Just set it to the same height as the height of your tab. If you have padding on the div then you will need to compensate for that also.
<div id="tabulardata">
<div id="tab">Tab X</div>
<table>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
<tr><td>data</td></tr>
</table>
</div>
#tabulardata { margin-top: -50px; }
#tab { height: 50px; width: 80px; background: gray; color: white; }
Boxes are some objects(button, label, textarea). Green's size is dynamic. Especially I have a problem with the blue box stick to bottom.
Place a holder around it and it will take the height from the 'green' one, and give them only absolute and bottom 0, it won't matter what width you give your elements.
Edit: hopefully this works for you, with floating the elements, the green one to the right, and the rest left.
<div id="divHolder">
<label id="red">Label</label>
<button id="blue">Button</button>
<div id="green">
a
</div>
<br class="clearFloat" />
</div>
#divHolder {
width:300px;
position:relative;
}
#green {
height:300px;
background-color: green;
float:right;
}
#red {
background-color:red;
float:left;
position:absolute;
}
#blue {
background-color: blue;
bottom: 0;
position:absolute;
}
.clearFloat {
clear:both;
}
check it out here:
http://jsfiddle.net/YA9yD/32/
Here's my solution →
The main problem here is that the left-hand column doesn't know how tall the right-hand column is.
You can put them in a parent together (which will wrap both columns), but the left-hand column will not know the height of the parent because a child element can only expand to the height of a parent element if the parent element's height is explicitly set.
Also, there are two distinct columns here, so I wanted to try and group them as close to the way they appear as possible. Putting the left column inside the right column (the green box) doesn't accurately represent how this is structured.
HTML:
<div id="container">
<div id="labelDiv">
<label>I'm a label.</label>
<p>Text area, whatevs.</p>
</div>
<button>Hello</button>
<div id="greenBox">
<p>Green box text.</p>
</div>
</div>
CSS:
#container {
width: 610px;
overflow: hidden;
position: relative;
}
#labelDiv {
width: 300px;
float: left;
}
button {
position: absolute;
bottom: 0;
left: 0;
}
#greenBox {
width: 310px;
float: left;
}
So everything on the left (other than the button) is floated left, and the green box is also floated left. Great so far, but the the button needs to know how tall the entire box is so that it can attach itself to the bottom. So, we set overflow to hidden on the outer container so that it wraps around the floated elements, and absolutely positioning the button to the bottom of this aligns it exactly with the bottom of the tallest inner element (the green box).
I'd also recommend setting some margin-bottom on #labelDiv so that it doesn't cover up the button.
See example of the following →
As long as the blue and red widths are specified, you could use relative and absolute position as follows:
<div id="green">
<label id="red">Label</label>
<button id="blue">Button</button>
</div>
#green {
position:relative;
}
#red {
width:100px;
position:absolute; left:-110px; top:0px;
}
#blue {
width:100px;
position:absolute; left:-110px; bottom:0px;
}