Changing from table layout to div layout - html

Okay, so I know it's frowned upon to use tables for layout, so I tried using DIVs etc, and got myself completely tangled in knots and without managing to achieve the layout I needed - and thus resorted back to a table.
The layout's actually relatively simple, but it seems there's a couple of features that make it a little tricky (for me at least) in CSS.
There are just 2 rows. The top row has two cells of equal width. These contain text, and should automatically resize to the correct height.
The other row contains an iframe. It should be the full width of the container, and take up the remaining container height.
I tried a few approaches, including using CSS like display:table-cell etc, but because my second row would require colspan="2" that simply does not work. Using floating divs doesn't seem to work very well either, because how do I get my second row - I don't want to have to resort to absolute positioning, because then I'd have to assume a fixed height for the top row.
Any CSS experts out there who can get me on the right track?
Here's an example demonstration what I currently do using a table (jsfiddle link below).
HTML...
<div id="cont">
<table>
<tr height="1%">
<td><p>How would you do this with DIVs / CSS?<br />
Some text. Lorem ipsum dolor sit amet,
consectetur adipiscing elit, sed do eiusmod
</p></td>
<td><p>Some more text.<br />
These two cells have indeterminate size.<br />
They should only take up the minimum height.
</p></td>
</tr>
<tr>
<td colspan="2">
<div id="iframe">
An iframe will go here.<br />
I'm just using a div for
illustrative purposes.
</div>
</td>
</tr>
</table>
</div>
CSS
#cont {
position: absolute;
left: 4px;
right: 4px;
top: 4px;
bottom: 4px;
}
table {
width: 100%;
height: 100%;
}
td {
vertical-align: top;
}
#iframe {
width: 100%;
height: 100%;
border: 1px solid green;
}
http://jsfiddle.net/z8qum850/

This is very easy to do with CSS. Something like the following would give what you asked about:
HTML
<div id="wrapper">
<div id="row1">
<div id="first-cell"></div>
<div id="second-cell"></div>
</div>
<div id="row2"></div>
</div>
CSS
div {
border:1px solid black;
}
#wrapper {
height:auto;
width:100%;
}
#row1 {
display:table;
width:100%;
}
#first-cell,#second-cell {
display:table-cell;
height:200px;
}
#row2 {
width:100%;
height:200px;
display:block;
}
Using display:table and table-cell, the child div elements will automatically fill the width, but you need to use a wrapper to keep them contained. So, if you were to remove the width declaration on the #wrapper element, you'd collapse everything because the child elements don't know how much space to fill. Here's a CodePen demo showing the result of the code.

Related

Table cell unnecessarily overflows wrapper in FF and IE

I tried to create a box with rotating content, simply using an outer box with a specified width and overflow: hidden, and inner boxes with display: inline-block; width: 100%. Everything worked as expected, until I added an image to each of the three "content boxes". Even though the images were narrow enough to fit well within the available space, the outer box' parent element now started overflowing its parent, in turn making the rotating box wider (since it had a relative width). The problem was the same in FF (28) and IE (11), but things were fine in Chrome.
In the end I boiled it down to this being a table layout issue, since adding table-layout: fixed on a table ancestor stopped the td parent of the rotating box to grow unneccessarily. (There are tables used for layout due to legacy reasons.)
What I wonder now is why this is happening, and if there is something wrong with my approach for the boxes. I've created a minimal example of the problem below (fiddle at http://jsfiddle.net/rvy2V/9/).
(In the example I use overflow: visible instead of hidden to make it easier to see what is going on. I also have whitespace between the inline blocks, which is bad for layout but good for clarity.)
HTML
<div id="wrapper">
wrapper
<table>
<tbody>
<tr>
<td id="cell">
table cell
<div class="niceBox slidePanes" id="outerBox">
<span class="slidePane">
.slidePane
<div class="body">
<div class="inner">inner box</div>
</div>
</span>
<span class="slidePane">
.slidePane
<div class="body">
<div class="inner">inner box</div>
</div>
</span>
<span class="slidePane">
.slidePane
<div class="body">
<div class="inner">inner box</div>
</div>
</span>
</div>
</td>
</tr>
</tbody>
</table>
</div>
CSS
.niceBox {
border: 1px solid #d7d7d7;
background-color: #f6f6f6;
}
.slidePanes {
overflow: visible;
white-space: nowrap;
}
.slidePanes .slidePane {
display: inline-block;
width: 100%;
white-space: normal;
vertical-align: top;
background-color: #bbf;
padding: 5px 0;
}
#wrapper {
width: 525px;
background-color: #888;
}
#cell {
background-color: #bbb;
}
#outerBox {
width: 50%;
}
div.inner {
width: 230px;
background-color: #f88;
}
Note in the fiddle how the table cell (medium gray) is wider than the wrapper (dark gray), but still not wide enough to contain all three content boxes (purple). Also note how, as a result, the rotating box (yellow border) is wider than the intended 50% of the wrapper. Also note how the inner boxes (red), which should be the widest thing in each content box, is not determining the width of each box.

DIV not taking parent height 3 columns

<div class='main_container' style='overflow:hidden; height:100%; height: auto !important; min-height:100%; width:100%;'>
<div class='float_left' style='width:100px; height:100%;'>
</div>
<div class='float_right' style='width:100px;'>
</div>
<div class='clear'></div>
<div class='content'>
//elastic content that sometimes makes the page longer or shorter
</div>
</div>
No matter how many tutorials or examples I looked at, nothing is helping me. I've tried many different combinations. As soon as I set main_container to a px height, the sidebars then, correctly, take up 100% of the height. But I can't set a px height for the main container.
EDIT:
example
The content box will not have a static height. So far what happens is that main_container adjusts it's height based on the content box, but the two sidebars don't adjust there height based on the main_containers height.
In addition to Adrift's answer, you are also overriding the height: 100% with the following height: auto !important - the latter overrides the height setting, even though it is not the source of the problem.
Here is a Gist that works on Chrome and most likely also on other modern browsers as well.
This solution uses CSS tables cells that allow the left/right sidebars to take on the height of the central .content panel.
The HTML:
<div class='main_container'>
<div class='left_bar'></div>
<div class='content'>
<p>Elastic content that sometimes makes the page longer or shorter</p>
<p>Lorem ipsum dolor sit amet, ...</p>
</div>
<div class='right_bar'></div>
</div>
The CSS:
.main_container {
display: table;
width: 100%;
}
.left_bar {
display: table-cell;
width: 100px;
background-color: lightgray;
}
.right_bar {
display: table-cell;
width: 100px;
background-color: lightgreen;
}
.content {
padding: 0 20px;
}
Demo Fiddle: http://jsfiddle.net/audetwebdesign/zahPD/
As suggested in other comments, you can specify height: 100% or height: inherit to .main_container as required in your application.
Reference for table-cell: https://developer.mozilla.org/en-US/docs/Web/CSS/display
Backwards Compatibility
Works with IE8 and above.
Div not supports height in percent using xhtml document. You use a trick like this:
.main_container{
position:fixed;
top:0;bottom:0;
right:0;left:0;
}
I've write an example here: http://jsfiddle.net/vF6fY/ take a look to it

Losing elements' positions with css

I need to do smth like this:
Left box should have static width and right one resizes to full browser width.
Height of the boxes also should be resizeable.
P.S.
Sorry guys, it took a while to make fiddle work.
So it is here
<div class="page-wrapper">
<div class="search-wrapper">
</div>
<div class="content-wrapper">
<div class="leftPage">
</div>
<div class="rightPage">
</div>
</div>
</div>
The problem is:
I have silver left page. I want it to have static width. Lets say 454px.
And I want right page (black one) to be dynamically resized to screen.
Variant with width 20%/80% is not good for me.
Is it possible with CSS only?
I got good answers with jquery/js but still interesting if it can be done with CSS only)
Sorry for troubles)
Javascript/jQuery
If you want left column to be static and the right column to be dynamic, you will need Javascript or a CSS preprocessor like SASS. That's the only real solution that is supported by older browsers.
// parent width - leftpage width = remainings
$('div.rightPage').width(
$('div.rightPage').parent().width() - $('div.leftPage').width()
);
Fluid layout
If you really want a pure-CSS solution, I suggest to use a fluid layout instead. This is cross-browser as well.
div.leftPage { width: 25%; }
div.rightPage { width: 75%; }
Simulated table
As alternative, you can still simulate a table layout using display: table. Tables do have that functionality. Check out the demo (resize the window to see it working)
This may not work in IE6 and IE7.
Native table
In the end, if you are OK with tables, you can use native tables, which are cross-browser ;)
CSS
table td.fixed { width: 200px; }
HTML
<table>
<tbody>
<tr>
<td class="fixed">
<p>Left content</p>
</td><td>
<p>Right content</p>
</td>
</tr>
</tbody>
</table>
Finally, in order to resize it vertically, you need to set resize: vertical.
div.leftpage, div.rightpage { resize: vertical; }
Using table is much easier.
HTML
<div class="page-wrapper">
<div class="search-wrapper">
</div>
<table class="content-wrapper">
<tr>
<td class="leftPage">LEFT</td>
<td class="rightPage">RIGHT</td>
</tr>
</table>
</div>
CSS
table
{
width:100%;
}
.leftPage
{
width: 454px;
}
Unless you really want to stick with DIVs?
Try using absolute position at a relative container and have your right div position at left the same amount of pixels as your left width. Like below:
div.content-wrapper {
height: 100%;
width: 100%;
position:relative;
}
div.leftPage {
background-color: black;
height: 100%;
width: 454px;
position:absolute;
}
div.rightPage {
background-color: red;
height: 100%;
width: 100%;
position:absolute;
left:454px;
}
Also its good to set the body height at 100% if you want your divs to expand across the page:
body, html {
width:100%;
height:100%;
}
And here's the demo: http://jsfiddle.net/XLLSA/1/
EDIT
I fixed the search div: http://jsfiddle.net/XLLSA/2/
Try this..
div.left {
width: 20%;
min-width: 200px;
}
div.right {
width: 80%;
}

CSS table-cell equal width

I have an indeterminate number of table-cell elements inside a table container.
<div style="display:table;">
<div style="display:table-cell;"></div>
<div style="display:table-cell;"></div>
</div>
Is there a pure CSS way to get the table-cells to be equal width even if they have differently sized content within them?
Having a max-width would entail knowing how many cells you have I think?
Here is a working fiddle with indeterminate number of cells: http://jsfiddle.net/r9yrM/1/
You can fix a width to each parent div (the table), otherwise it'll be 100% as usual.
The trick is to use table-layout: fixed; and some width on each cell to trigger it, here 2%. That will trigger the other table algorightm, the one where browsers try very hard to respect the dimensions indicated.
Please test with Chrome (and IE8- if needed). It's OK with a recent Safari but I can't remember the compatibility of this trick with them.
CSS (relevant instructions):
div {
display: table;
width: 250px;
table-layout: fixed;
}
div > div {
display: table-cell;
width: 2%; /* or 100% according to OP comment. See edit about Safari 6 below */
}
EDIT (2013): Beware of Safari 6 on OS X, it has table-layout: fixed; wrong (or maybe just different, very different from other browsers. I didn't proof-read CSS2.1 REC table layout ;) ). Be prepared to different results.
HTML
<div class="table">
<div class="table_cell">Cell-1</div>
<div class="table_cell">Cell-2 Cell-2 Cell-2 Cell-2Cell-2 Cell-2</div>
<div class="table_cell">Cell-3Cell-3 Cell-3Cell-3 Cell-3Cell-3</div>
<div class="table_cell">Cell-4Cell-4Cell-4 Cell-4Cell-4Cell-4 Cell-4Cell-4Cell-4Cell-4</div>
</div>​
CSS
.table{
display:table;
width:100%;
table-layout:fixed;
}
.table_cell{
display:table-cell;
width:100px;
border:solid black 1px;
}
DEMO.
Just using max-width: 0 in the display: table-cell element worked for me:
.table {
display: table;
width: 100%;
}
.table-cell {
display: table-cell;
max-width: 0px;
border: 1px solid gray;
}
<div class="table">
<div class="table-cell">short</div>
<div class="table-cell">loooooong</div>
<div class="table-cell">Veeeeeeery loooooong</div>
</div>
Replace
<div style="display:table;">
<div style="display:table-cell;"></div>
<div style="display:table-cell;"></div>
</div>
with
<table>
<tr><td>content cell1</td></tr>
<tr><td>content cell1</td></tr>
</table>
Look at all the issues surrounding trying to make divs perform like tables. They had to add table-xxx to mimic table layouts
Tables are supported and work very well in all browsers. Why ditch them? the fact that they had to mimic them is proof they did their job and well.
In my opinion use the best tool for the job and if you want tabulated data or something that resembles tabulated data tables just work.
Very Late reply I know but worth voicing.
this will work for everyone
<table border="your val" cellspacing="your val" cellpadding="your val" role="grid" style="width=100%; table-layout=fixed">
<!-- set the table td element roll attr to gridcell -->
<tr>
<td roll="gridcell"></td>
</tr>
</table>
This will also work for table data created by iteration
This can be done by setting table-cell style to width: auto, and content empty. The columns are now equal-wide, but holding no content.
To insert content to the cell, add an div with css:
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
You also need to add position: relative to the cells.
Now you can put the actual content into the div talked above.
https://jsfiddle.net/vensdvvb/
Here you go:
http://jsfiddle.net/damsarabi/gwAdA/
You cannot use width: 100px, because the display is table-cell. You can however use Max-width: 100px. then your box will never get bigger than 100px. but you need to add overflow:hidden to make sure the contect don't bleed to other cells. you can also add white-space: nowrap if you wish to keep the height from increasing.

CSS to simulate tables: inline divs which also have borders and break text?

I'm trying to float two divs inline with each other inside a div of set width. Additionally they have borders and content that requires wrapping. It stops working when there's more content than fits on one line.
I'm trying to be avoid using tables to solve this (see solution below) but but no luck so far. Any one got any ideas?
Edited question: expanding requirements to include:
the divs should minimise their total width and not expand beyond the boundarys of the two main 50% columns. I've managed to achieve the first and second part (please see my own answer below) however I have an additional third requirement in that as these can be nested, the content then still stays within the two main columns but doesn't expand to fill up to a maximum width of 50% of the columns width. I'm working on a javascript solution which I won't be able to post back for some time.
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Demo</title>
<style>
body {
width: 1024px;
}
.a_column {
width: 50%;
float:left;
}
.some_text {
float:left;
display:inline;
border: thin solid green;
}
.a_block {
float:left;
display:inline;
border: thin solid red;
/*width: I can't set this as I don't know how much some_text will need, this can vary from nothing to a lot.*/
word-wrap: break-word; /* this doesn't work without a width specified*/
}
/*solution when using tables */
.some_text_in_table, .a_block_in_table {
vertical-align:top;
}
.some_text_in_table div {
border: thin solid green;
}
.a_block_in_table div {
border: thin solid red;
word-wrap: break-word;
}
</style>
</head>
<body>
<div class="a_column">
<div class="some_text">
some text here.
</div>
<div class="a_block">
Less text and there's no problem.
</div>
</div>
<div class="a_column">
<div class="some_text">
some text here.
</div>
<div class="a_block">
Putting a lot of text into a div that you want a border around will
cause it to move down one line. Instead I'd like it to float inline
with its sibling div; you can remove the float:left but then it
completely messes up the border. An_additional_thing_I'd_like_is_for_long_sentences_to_be_broken_by_the_word_wrap,_but_this_requires_that_the_width_of
a_column be set and I can't do this as I don't always know how much
room some_text will need.
</div>
</div>
<div style="clear:both;"></div>
<h3> With tables, solution with in 7 minutes. So much easier:</h1>
<table style="table-layout: fixed; width: 100%;">
<tr>
<td colspan="2" style="width: 50%;">
</td>
<td colspan="2" style="width: 50%;">
</td>
</tr>
<tr>
<td class="some_text_in_table">
<div>
some text here.
</div>
</td>
<td class="a_block_in_table">
<div>
some text here.
</div>
</td>
<td class="some_text_in_table">
<div>
Less text and there's no problem.
</div>
</td>
<td class="a_block_in_table">
<div>
Putting a lot of text into a div that you want a border around will cause it to move down one line. Instead I'd like it to float inline with its sibling div; you can remove the float:left but then it completely messes up the border. An_additional_thing_I'd_like_is_for_long_sentences_to_be_broken_by_the_word_wrap,_but_this_requires_that_the_width_of a_column be set and I can't do this as I don't always know how much room some_text will need.
</div>
</td>
</tr>
</table>
</body>
</html>
Fiddle with my code here: http://jsfiddle.net/cdepZ/
display:table-cell;
Example: http://jsfiddle.net/TAhAv/
You are right in wanting to avoid tables with this layout - as you mentioned, this is not tabular data which you are chosing to display.
You mention in your CSS that you cannot set a width on .a_block because you do not know how much space you need. However, when you use a table you are actually setting a width (25%) as each cell is equally split amongst the over-all width.
So to achieve what you want to do (which will match the tables layout), you will have to set a width on these elements.
Here is a JSFiddle of how you could achieve this:
http://jsfiddle.net/ndhrd/39/
Set your widths properly with the space you have. Borders take 2px vertically and horizontally as well.
.a_column {
width: 512px;
float:left;
}
.a_block, .some_text{
width: 254px;
float: left;
word-wrap: break-word;
}
.a_block{
border: 1px solid green;
}
.some_text{
border: 1px solid red;
}
I got it working here:
http://jsfiddle.net/cdepZ/7/
Putting a lot of text into a div is now no problem, it will wrap and break any long sentences that go over 50% of it's parent divs' width. And it will minimise any content that it can whilst maintaining good looking borders.
Nesting this structure can keep it with in the limits of the .a_column but then doesn't allow all elements to expand fully.
I think the only solution is a javascript one :|
http://jsfiddle.net/uHEVJ/1/
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Demo</title>
<style>
body {
width: 1024px;
}
.a_column {
width: 49%; /* 49% rather than 50% to cope with the 1 pixel width borders*/
float:left;
border: thin solid blue;
}
.a_container{
display:inline;
}
.a_container > div{
max-width: 49%; /* 49% rather than 50% to cope with the 1 pixel width borders*/
float: left;
word-wrap: break-word;
}
.some_text {
border: thin solid green;
}
.a_block {
border: thin solid red;
}
</style>
</head>
<body>
<h3> Used a "display:inline;" div as a container to position each Div inside which has float:left (to minimise it's size)</h3>
<div class="a_column">
<div class="a_container">
<div class="some_text">
some text
</div>
</div>
<div class="a_container">
<div class="a_block">
Less text and there's no problem.
</div>
</div>
</div>
<div class="a_column">
<div class="a_container">
<div class="some_text">
some text here.
</div>
</div>
<div class="a_container">
<div class="a_block">
Putting a lot of text into a div is now no problem, it_will_wrap_and_break_any_long_sentences_that_go_over_50%_of_it's_parent divs' width. And it will minimise any content that it can whilst maintaining good looking borders
</div>
</div>
</div>
<div class="a_column">
<div class="a_container">
<div class="some_text">
Nesting this structure can keep it with in the limits of the .a_column but then doesn't allow all elements to expand fully.
</div>
</div>
<div class="a_container">
<div class="some_text">
Nesting this structure can keep it with in the limits of the .a_column but then doesn't allow all elements to expand fully.
<div>
<div class="a_container">
<div class="a_block">
some text
</div>
</div>
<div class="a_container">
<div class="a_block">
Nesting this structure can keep it with in the limits of the .a_column but then doesn't allow all elements to expand fully.
</div>
</div>
</div>
</div>
</div>
</div>
</body>
</html>