CSS-based layout equivalent of HTML-based table - html

I want a CSS solution (in principle HTML5/CSS3) that would reproduce the behaviour of the following table-based layout:
<table width="80%" align="center" border="1">
<tr valign="top">
<td>Some content that varies in size</td>
<td width="200">Maybe an image, maybe some short text</td>
</tr>
</table>
My best attempt with CSS gets me the left-side contents (the "content that varies in size" above) to wrap around the div on the right.
Here's what I'm trying:
div.outsidecontainer {
position: relative;
width: 80%;
border: 1px solid silver;
margin-left: auto;
margin-right: auto;
}
div.absolute {
float: right;
width: 200px;
margin-bottom: 1px;
border: 1px solid silver;
}
div.filler {
border: 1px solid silver;
margin-bottom: 1px;
}
<div class="outsidecontainer">
<div class="absolute">This is the fixed-size div on the right</div>
<div class="filler">Another div element with a lot of text .....</div>
</div>
Any suggestions?

You can acomplish this in a few ways.
Instead of using float right to get the content on the right, just place it on the right. With float: left; on each of the containers contents and placing a clearfix:both; in the bottom of the container:
Your approach - fixed
* {
box-sizing: border-box;
}
.outsidecontainer {
width: 100%;
border: 1px solid black;
}
.cell {
float: left;
}
.absolute {
width: 200px;
}
.filler {
width: calc(100% - 200px);
height: 100%;
}
/*used to stop the container from collapsing*/
.clearfix {
clear: both;
}
<div class="outsidecontainer">
<div class="filler cell">Another div element with a lot of text .....</div>
<div class="absolute cell">This is the fixed-size div on the right</div>
<div class="clearfix"></div>
</div>
Alternatively you can use the display: table to replicate a table using divs.
display: table Approach
.t-body {
width: 80%;
display: table;
}
.t-row {
display: table-row;
}
.t-cell {
display: table-cell;
border: 1px solid black;
}
.fw {
width: 200px;
}
<div class="t-body">
<div class="t-row">
<div class="t-cell">Another div element with a lot of text ....</div>
<div class="t-cell fw">This is the fixed-size div on the right</div>
</div>
</div>

a common pattern is to set the parent ("outsidecontainer" in this case) to position: relative then the child element ("absolute") to position: absolute and right: 0. This pattern set's a position: absolute child elements to be constrained to the boundaries of the parent element (rather than being constrained by default to boundaries of the 'body' element)
this is an alternative to float: right (which would also work)
then set margin-right to compensate for the width of the "absolute" div
div.outsidecontainer {
position: relative;
width: 80%;
border: 1px solid red;
margin-left: auto;
margin-right: auto;
}
div.absolute {
position: absolute;
right: 0; /* position to the right of "outsidecontainer" div */
width: 200px;
margin-bottom: 1px;
border: 1px solid blue;
}
div.filler
{
border: 1px solid black;
margin-bottom: 1px;
margin-right: 200px; /* compensate for "absolute" div's width */
}
<div class="outsidecontainer">
<div class="absolute">
<p>This is the fixed-size div on the right</p>
<p>This is the fixed-size div on the right</p>
<p>This is the fixed-size div on the right</p>
</div>
<div class="filler">
<p>Another div element with a lot of text ..... </p>
<p>Another div element with a lot of text ..... </p>
<p>Another div element with a lot of text ..... </p>
<p>Another div element with a lot of text ..... </p>
<p>Another div element with a lot of text ..... </p>
<p>Another div element with a lot of text ..... </p>
</div>
</div>

Related

2 divs, side by side, with right-hand div taking up remainder of containing div

I have the classic two divs side-by-side problem, which usually I have no problem with (float: left both divs and add a clear:both div after them).
My requirements are making this more complicated to solve...
I would like the left-hand div to occupy, as a column, the left hand side of the containing div (the left hand div will hold a number, ie '1.')
I would like the right-hand div to occupy the remaining space to the right of the left div - and most importantly I would like it NOT to drop below the left-hand div when there is insufficient 'space' for it to fit. Instead, I would like the right-hand div to remain in position and for the text within to WRAP, staying to the right of the left-hand div. Surely this is simple!
I do NOT want to set arbitrary width values because the length of the number in the left-hand div will vary, affecting the distance between the number and the right-hand text.
Here is some example html:
<div class="popup-container"> // set to width: 300px; in css
<div class="popup-text">
<div class="float-left">
<h3>2.<.h3>
</div>
<div class="float-left">
<h3>Example text here, long enough to wrap around<.h3>
</div>
<div class="clear"></div>
</div>
</div>
And the css:
.popup-container {
width: 300px;
}
.popup-text h3 {
line-height: 1.25;
padding: 0px 8px 0px 0px;
}
.float-left {
float: left;
}
.clear {
clear: both;
}
OK, I think that's about it. If anyone knows how to have the left div operate as a column, against which the text in the right-hand div remains justified left (instead of dropping 'below' the left hand div), that would be swell.
EDIT
Thanks for all the answers. I should have mentioned (!!) it has to work in IE8. I know. But it really does. Big organisation, not updating its machines, unfortunately.
Flexbox and CSS Tables can both do that.
Support
Flexbox is IE10+
CSS Tables are IE8+
FLEXBOX
.popup-container {
width: 300px;
border:1px solid grey;
}
.popup-text {
display: flex;
}
.popup-text h3 {
line-height: 1.25;
padding: 0px 8px 0px 0px;
}
.left {
flex: 0 0 auto;
background: #c0ffee;
}
.right {
flex:1;
background: yellow;
}
<div class="popup-container">
<div class="popup-text">
<div class="left">
<h3>2.</h3>
</div>
<div class="right">
<h3>Example text here, long enough to wrap around</h3>
</div>
</div>
</div>
CSS Tables
.popup-container {
width: 300px;
border:1px solid grey;
}
.popup-text {
display: table
}
.popup-text h3 {
line-height: 1.25;
padding: 0px 8px 0px 0px;
}
.left {
background: #c0ffee;
display: table-cell;
}
.right {
background: yellow;
display: table-cell;
}
<div class="popup-container">
<div class="popup-text">
<div class="left">
<h3>2.</h3>
</div>
<div class="right">
<h3>Example text here, long enough to wrap around</h3>
</div>
</div>
</div>
Use display:flex;
.popup-container {
width: 300px;
}
.popup-container .popup-text {
display: flex;
}
.popup-text h3 {
line-height: 1.25;
padding: 0px 8px 0px 0px;
}
.float-left {
float: left;
}
.clear {
clear: both;
}
<div class="popup-container">
<!-- set to width: 300px; in css -->
<div class="popup-text">
<div class="float-left">
<h3>2.</h3>
</div>
<div class="float-left">
<h3>Example text here, long enough to scroll</h3>
</div>
<div class="clear"></div>
</div>
</div>
Here is a solution using display: flex
.popup-container {
width: 300px;
background-color: coral;
}
.popup-text {
display: flex;
}
.popup-text div.two {
flex: 1;
background-color: cornflowerblue;
}
.popup-text h3 {
line-height: 1.25;
padding: 0px 8px 0px 0px;
}
<div class="popup-container">
<!-- set to width: 300px; in css -->
<div class="popup-text">
<div class="one">
<h3>2.</h3>
</div>
<div class="two">
<h3>Example text here, long enough to scroll</h3>
</div>
</div>
</div>

why float collapse does not arise with fixed position

I play with floats and I noticed then "float collapse bug" does not arise with fixed position. Here is example.
So I have two divs:
<body
<div class="static">
<img>
<p>text text text</p>
</div>
<div class="fixed">
<img>
<p>text text text</p>
</div>
</body>
First with static position and second with fixed:
.fixed, .static{
outline: 1px solid black;
width: 150px;
}
.fixed{
position: fixed;
left: 200px;
top: 200px;
}
img{
float: right;
background-color: green;
width: 100px;
height: 100px;
}
And result:
So why the second fixed-div does not need something like .clearfix to fix float collapse?
Because position: fixed; creates Block formatting context.
Try the below styles also, which have similar effect in your div.
float
position absolute and fixed
display - inline-blocks, table, table-cells
overflow - hidden, auto
if you want them both to appear the same you can put in overflow-y:hidden;
https://jsfiddle.net/1nq8b7xs/3/
or if you want them to appear beside each other use display:inline-block and remove position-fixed from your fixed class
https://jsfiddle.net/1nq8b7xs/4/
.fixed, .static{
outline: 1px solid black;
width: 150px;
overflow-y:hidden; /*added this*/
}
.fixed{
left: 200px;
top: 200px;
}
img{
float: right;
background-color: green;
width: 100px;
height: 100px;
}
.fixed, .static{display:inline-block;}
<body>
<div class="static">
<img>
<p>text text text</p>
</div>
<div class="fixed">
<img>
<p>text text text</p>
</div>
</body>

How to force inline-block element to correctly wrap it's multiline child element?

I need to display left and right borders padded 10px away from left and right edges of the centered text. There's no problem when the all text fits into one line, but when text takes up multiple lines the wrapping inline-block element stretches to 100% of it's container width.
I need a pure CSS solution.
Here's JSFiddle with working demo of the problem: https://jsfiddle.net/k8wrbctr/
Here's HTML:
<div class="container">
<div class="borders-wrapper"><span>The title</span></div>
<div class="borders-wrapper"><span>The title that takes up multiple lines</span></div>
</div>
Here's CSS:
.container {
width: 200px;
text-align: center;
background-color: #ddd;
}
.borders-wrapper {
display: inline-block;
border-left: 2px solid black;
border-right: 2px solid black;
padding-left: 10px;
padding-right: 10px;
margin-bottom: 20px;
}
Here's the result:
| The title |
| The title that takes up |
| multiple lines |
And here's what I want to achieve:
| The title |
| The title that takes up |
| multiple lines |
I need to display left and right borders padded 10px away from left
and right edges
You need to give margins not padding for that.
when text takes up multiple lines the wrapping inline-block element
stretches to 100% of it's container width
That is because the content is long and the div will stretch as far as it can (upto parent width) to accommodate the content before it wraps to the next line.
There is another problem with your div being inline-block - if the content is less then the next div will start just right after the first one and not on its own line.
Solution (Keeping the div as inline-block):
Use a pseudo-element to break the line.
* { box-sizing: border-box; }
.container {
width: 200px;
text-align: center;
background-color: #ddd;
}
.borders-wrapper {
display: inline-block;
border-left: 2px solid black;
border-right: 2px solid black;
padding: 0px 10px; margin: 10px;
}
.borders-wrapper::after {
content:"\A"; white-space:pre;
}
<div class="container">
<div class="borders-wrapper"><span>The title</span></div>
<div class="borders-wrapper"><span>The title that</span></div>
<div class="borders-wrapper"><span>The title that takes up multiple lines</span></div>
</div>
Note:
Thanks #Kaiido for pointing it out. The pseudo-element trick won't work with its element being inline-block. In order for it to work, you do your padding/margin on the span, and float the divs. Then use transform trick to center it. A little more complicated.
Example:
* { box-sizing: border-box; }
.container {
width: 200px;
text-align: center;
background-color: #ddd;
}
.borders-wrapper {
float: left; clear: left;
position: relative; left: 50%;
transform: translateX(-50%);
margin: 0px auto;
}
.borders-wrapper > span {
display: inline-block;
padding: 0px 10px; margin: 10px;
border-left: 2px solid black;
border-right: 2px solid black;
}
.container:after { content:''; display:block; clear: both; }
.div2 { width: 400px; }
<div class="container">
<div class="borders-wrapper"><span>The title</span></div>
<div class="borders-wrapper"><span>The title that</span></div>
<div class="borders-wrapper"><span>The title that takes up multiple lines</span></div>
</div>
<br />
<div class="container div2">
<div class="borders-wrapper"><span>The title</span></div>
<div class="borders-wrapper"><span>The title that</span></div>
<div class="borders-wrapper"><span>The really long title that takes up multiple lines in a large width</span></div>
</div>

Issue with textarea inside a div for which display: table-cell

I have trouble with textarea inside a div whose display style is table-cell. You can see the problem here. The last div has a textarea and somehow it causes an empty area below itself and above other divs.
BTW I am trying to have a structure like this. According to selection, cells will be displayed in a fixed height area with equal widths having a total 100%. Problem occurs when there is a textarea inside any div. If there is an existing component that behaves like this any recommendation will be appreciated.
HTML
<div class="panes">
<div id="pane1" class="pane">
<div class="pane-content"></div>
</div>
<div id="pane2" class="pane">
<div class="pane-content"></div>
</div>
<div id="pane3" class="pane">
<div class="pane-content">
<textarea></textarea>
</div>
</div>
</div>
CSS
.panes {
display: table;
table-layout: fixed;
width:100%;
height:100px;
}
.pane {
display: table-cell;
border: solid 1px;
}
.pane-content {
display: block;
overflow: auto;
height: 100px;
border: solid 1px red;
}
.pane-content textarea {
display: block; /*This fix the issue in IE but other browsers still broken*/
width: 100%;
height: 100px;
}
make it like this:
.pane {
display: table-cell;
border: solid 1px;
vertical-align: top;
}

Make a div fill the space

I'd like to put two columns on the side of the content div. The part I have problems with is that I want the columns being built from 3 parts. The top and bottom should have fixed heights, but the middle one would adjust depending on the content height. Look at the sample with one column:
<html>
<head>
<style>
* { border: 1px solid black;}
#contentWrapper { width:450px; }
#leftColumn { width:100px; float: left; }
#leftColumnTop { width:100px; height:50px;
background-color: gray; }
#leftColumnMiddle { background-color: red; }
#leftColumnBottom { width: 100px; height:50px;
background-color: gray; }
#content { width: 300px; float: left; }
#footer { width: 400px; clear: both; }
</style>
</head>
<body>
<div id="contentWrapper">
<div id="leftColumn">
<div id="leftColumnTop"> </div>
<div id="leftColumnMiddle"> </div>
<div id="leftColumnBottom"> </div>
</div>
<div id="content">content<br> here <br>more
<br>more <br>more <br>more <br>more
<br>more <br>
</div>
<div id="footer">footer text</div>
</div>
</body>
</html>
What I want is the #leftColumnBottom stick at the top of the footer and red #leftColumnMiddle to fill the space between top and bottom part.
This works in everything except IE6; for that you'll need a conditional comment and css expression to set a height instead of bottom on #leftColumnMiddle
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html><head>
<style>* { border: 1px solid black;}
#contentWrapper { position: relative; float:left; width: 450px; }
#leftColumnTop { position: absolute; width: 100px; height: 50px; left: 0; background-color: gray; }
#leftColumnMiddle { position: absolute; width: 100px; top: 50px; bottom: 50px; left: 0; background-color: red; }
#leftColumnBottom { position: absolute; width: 100px; height: 50px; left: 0; bottom: 0; background-color: gray; }
#content { width: 300px; float: left; margin-left: 100px;}
#footer { width: 400px; clear: both; }
</style>
</head>
<body>
<div id="contentWrapper">
<div id="leftColumnTop"> </div>
<div id="leftColumnMiddle"> </div>
<div id="leftColumnBottom"> </div>
<div id="content">content<br>
here<br>more<br>more<br>more<br>more<br>more<br>more<br>
</div>
</div>
<div id="footer">footer text</div>
</body>
</html>
And to the commenter - it nearly worked, so that's why. ;)
try min-height for the one that needs to grow
If you need both columns to be of equal height, and work in IE6, you basically have to hack.
A solution I've used in the past involves setting up a fake margin/padding for one of the columns. This assumes that you know a upper limit of how large the columns can grow (could be in the magnitude of several thousand px's).
This solution is outlined here.
Quoting from the page I linked:
The basic method works like this:
Blocks which will act as columns must be wrapped in a container element
Apply overflow: hidden to the container element
Apply padding-bottom: $big_value [2] to the column blocks, where $big_value is a large enough value to guarantee that it's equal to or larger than the tallest column
Apply margin-bottom: -$big_value to the column blocks