Stretch table to vertically fit TD - html

I am placing a table inside a td. By setting width:100%, I can get the table to stretch horizontally, but I have not been able to do the same vertically. No matter what I've tried, the table will have the minimum height necessary to contain its contents.
Below is the structure of the table
table {
border-collapse: collapse;
border-spacing: 2px;
border-color: black;
}
td {
border: 1px solid #ddd;
background: #f2f5f7;
}
<table >
<tbody>
<tr>
<td rowspan="2" style="background-color:#ff0000"/>
<table>
<tr>
<td>A</td>
<td>B</td>
</tr>
<tr>
<td>C</td>
<td>D</td>
</tr>
</table>
<td><br>Extra<br></td>
</tr>
<tr>
<td>Space<br><br></td>
</tr>
</table>
I am trying to get rid of the red areas above and below the ABCD table. I've tried solutions from dozens of various questions, and I thought this would be straightfoward, but nothing has worked.
I have tried (in various permutations):
height:100% on any and all componentns
display:flex or display:block on the nested table and/or parent td
explicitly setting padding:0px !important on all components
None of these have affected the height of the table.
The most promising result so far: setting the height to a pixel value (like height:100px does change the height of the table. Unfortunately, the necessary height of the table will change based on factors outside of my knowledge/control. I'm looking for a programmatic solution to this issue.
(NOTE: I know how to use JS to grab the height of the neighboring cells and set the height of the trs in the nested table after the page loads. However, I don't have a guarantee that JS will be executable, so this is my last resort.)

Here is a solution that I've created using CSS Grid.
.grid-table {
display: grid;
grid-template-columns: repeat(3, minmax(50px, 1fr));
background-color: #fff;
color: #444;
max-width: 800px;
background-color: #ccc;
}
.grid-table > .row:not(:last-of-type) {
border-bottom: 1px solid #ddd
}
.row {
grid-column: 1 / -1;
display: grid;
grid-template-columns: repeat(3, minmax(50px, 1fr));
align-items: center;
}
.row > .box:not(:last-of-type) {
border-right: 1px solid #ddd;
}
.box {
height: 100%;
display: flex;
align-items: center;
}
.box-item {
padding: 5px;
}
<div class="grid-table">
<!-- Table Row -->
<div class="row">
<div class="box">
<div class="box-item">Column 1</div>
</div>
<div class="box">
<div class="box-item">Column 2</div>
</div>
<div class="box">
<div class="box-item">Column 3</div>
</div>
</div>
<!-- Table Row -->
<div class="row">
<div class="box">
<div class="box-item">A</div>
</div>
<div class="box">
<div class="box-item">B</div>
</div>
<div class="box">
<div class="box-item">Extra<br>Space</div>
</div>
</div>
<!-- Table Row -->
<div class="row">
<div class="box">
<div class="box-item">C</div>
</div>
<div class="box">
<div class="box-item">D</div>
</div>
<div class="box">
<div class="box-item">Extra<br>Space</div>
</div>
</div>
</div>
With this solution, the height of the individual columns will always be the height of the tallest column. You can control whether you want the rows to be centered or not by modifying the align-items attribute within the .box class.
JSFiddle

Related

HTML table cell column mixing fixed widths + percentages

I want to do something very basic, a table with 4 columns: 2 columns should be 50px each, the other 2 columns should take 50% of the remaining space each.
I'm surprised to find out that calc() does not work for setting width on table cells. So doing something like td { width: calc(50% - 100px); } is not a possibility.
Is there a way to achieve this with the table element or is using another layout method like flexbox the only choice?
You could use a grid layout with grid-template-columns
grid-template-columns: 50px 50px 1fr 1fr;
Defines 4 columns in your grid which represent (respectively) 50px, 50px and 1fr takes one fraction of the remaining space (twice)
.grid {
display: grid;
grid-template-columns: 50px 50px 1fr 1fr;
grid-gap: 1px;
}
.col {
height: 100px;
background-color: red;
}
.col:nth-child(2) {
background-color: yellow;
}
.col:nth-child(3) {
background-color: teal;
}
.col:nth-child(4) {
background-color: navy;
}
<div class="grid">
<div class="col"></div>
<div class="col"></div>
<div class="col"></div>
<div class="col"></div>
</div>
Width calculation for tables is a bit clunky, but can be improved by using table-layout: fixed because then cell widths will no longer be calculated based on what's inside the cells. And then you may not even need calc() anymore, although you definitely can.
It should also be noted that a table by default takes up the least width possible, it usually gets better if we tell the table to use 100% width (or whatever is needed in your case).
width: 100% combined with table-layout: fixed and no calc() gives the following results:
table {
width: 100%;
table-layout: fixed;
}
td {
background: #eee;
height: 70px;
}
td.fixed {
width: 50px;
}
td.rest {
width: 50%;
background: #fca;
}
<table>
<tbody>
<tr>
<td class="fixed">1</td>
<td class="fixed">234</td>
<td class="rest">a</td>
<td class="rest">bcd efg</td>
</tr>
</tbody>
</table>
You can use a grid system (Bootstrap) that can design table, It's a sample
<div class="container">
<div class="row">
<div class="col">
1 of 3
</div>
<div class="col-6">
2 of 3 (wider)
</div>
<div class="col">
3 of 3
</div>
</div>
<div class="row">
<div class="col">
1 of 3
</div>
<div class="col-5">
2 of 3 (wider)
</div>
<div class="col">
3 of 3
</div>
</div>
</div>

Table with CSS Grid

My CSS Grid table doesn't have same width on its columns, I want to replicate the table structure but with CSS Grid.
I'm using grid-auto-flow: column; because in my app, the cells are dynamically generated and will be different in number.
An image to show the issue:
The code:
https://jsfiddle.net/w8sdvnr7/1/
div {
display: grid;
grid-auto-flow: column;
}
p {
border: 1px solid red;
margin: 0;
}
table {
border-collapse: collapse;
}
td {
border: solid 2px red;
}
<h3>Not working: CSS Grid: The cells in the rows have different size.</h3>
<div>
<p>ABC</p>
<p>A</p>
<p>ABCDEFGHIJKLMNOP</p>
</div>
<div>
<p>ABCDEFGHIJKLMNOP</p>
<p>A</p>
<p>AB</p>
</div>
<hr>
<br>
<hr>
<h3>What I want: CSS Table: The cells in the rows have same size.</h3>
<table>
<tr>
<td>ABC</td>
<td>A</td>
<td>ABCDEFGHIJKLMNOP</td>
</tr>
<tr>
<td>ABCDEFGHIJKLMNOP</td>
<td>A</td>
<td>AB</td>
</tr>
</table>
There is a solutions for your question
.wrapper {
display: grid;
grid-template-columns: repeat(3, auto);
background-color: #fff;
color: #444;
max-width: 800px;
}
.box {
background-color: #444;
color: #fff;
border-radius: 5px;
padding: 10px;
font-size: 150%;
}
.row {
display: contents;
}
<div class="wrapper">
<div class="box a">col 1</div>
<div class="box b">col 2</div>
<div class="box c">col 3</div>
<!-- Table Row -->
<div class="row">
<div class="box d">short data</div>
<div class="box e">a really long piece of dataa really long piece of data</div>
<div class="box f">short data</div>
</div>
<!-- Table Row -->
<div class="row">
<div class="box d">short data</div>
<div class="box e">a really long piece of data</div>
<div class="box f">short data</div>
</div>
</div>
You might want to use the grid-template-columns property to set the number of columns, however, you should also update the HTML structure for that to work:
div {
display:grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
}
here's the updated fiddle: https://jsfiddle.net/dk9epf57/9/
div {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
}
p {
border: 1px solid red;
margin: 0;
}
table {
border-collapse: collapse;
}
td {
border: solid 2px red;
}
<h3>Not working: CSS Grid: The cells in the rows have different size.</h3>
<div>
<p>ABC</p>
<p>A</p>
<p>ABCDEFGHIJKLMNOP</p>
<p>ABCDEFGHIJKLMNOP</p>
<p>A</p>
<p>AB</p>
</div>
<hr>
<br>
<hr>
<h3>What I want: CSS Table: The cells in the rows have same size.</h3>
<table>
<tr>
<td>ABC</td>
<td>A</td>
<td>ABCDEFGHIJKLMNOP</td>
</tr>
<tr>
<td>ABCDEFGHIJKLMNOP</td>
<td>A</td>
<td>AB</td>
</tr>
</table>
You had a few answers, this one is to complete my earlier comment with examples to help you sort out what you want and decide to dig further into grid tutorials like https://css-tricks.com/snippets/css/complete-guide-grid/ or ressource alike https://gridbyexample.com/
display:table and display:grid may look similar somehow but are not.
about max-content used in the examples, you also can see How do min-content and max-content work?
div {
display: grid;
grid-template-columns: repeat(3, auto);
justify-content: start;
}
p {
border: 1px solid red;
margin: 0;
}
table {
border-collapse: collapse;
}
td {
border: solid 2px red;
}
div.bc {
background: red;
border: red 1px solid;
background: red;
gap: 1px;
width: max-content;
}
div.bc>* {
background: white;
border: none;
}
div.bnc {
width: max-content;
border: solid 1px red;
gap: 2px;
padding: 2px;
}
div.bnc p {
padding:0.5em;
}
<h3>CSS grid layout dispatching children into 3 columns</h3>
<b>border-collapse not avalaible;<b><br><br>
<div>
<p>ABC</p>
<p>A</p>
<p>ABCDEFGHIJKLMNOP</p>
<!--</div>
<div>-->
<p>ABCDEFGHIJKLMNOP</p>
<p>A</p>
<p>AB</p>
</div>
<hr>
<br>
<hr>
<h3>HTML table-layout</h3>
<table>
<tr>
<td>ABC</td>
<td>A</td>
<td>ABCDEFGHIJKLMNOP</td>
</tr>
<tr>
<td>ABCDEFGHIJKLMNOP</td>
<td>A</td>
<td>AB</td>
</tr>
</table>
<br>
<hr>
<br>
<h3>CSS grid layout faking table-layout </h3>
<b> table-layout and border-collapse faked through gap and background and width<b><br><br>
<div class="bc">
<p>ABC</p>
<p>A</p>
<p>ABCDEFGHIJKLMNOP</p>
<!--</div>
<div>-->
<p>ABCDEFGHIJKLMNOP</p>
<p>A</p>
<p>AB</p>
</div>
<br>
<hr>
<br>
<h3>CSS grid layout faking table-layout </h3>
<b> table-layout without border-collapse faked width<b><br><br>
<div class="bnc">
<p>ABC</p>
<p>A</p>
<p>ABCDEFGHIJKLMNOP</p>
<!--</div>
<div>-->
<p>ABCDEFGHIJKLMNOP</p>
<p>A</p>
<p>AB</p>
</div>

How to shrink column to max width of that column in all rows, like td width in a table?

I want to replace a table with flexbox elements.
Basically from this:
<table>
<tr>
<td>row_1.col_1</td>
<td>row_1.col_2</td>
</tr>
<tr>
<td>row_2.col_1.with_longer_content</td>
<td>row_2.col_2</td>
</tr>
</table>
To this:
<div>
<div>
<div>row_1.col_1</div>
<div>row_1.col_2</div>
</div>
<div>
<div>row_2.col_1.with_longer_content</div>
<div>row_2.col_2</div>
</div>
</div>
In the case of the table, the first row's first cell will expand in width so that the second cell row_1.col_2 will align properly with the cell beneath it row_2.col_2
-------------------------------------------------
| row_1.col_1 | row_1.col_2 |
| row_2.col_1.with_longer_content | row_2.col_2 |
-------------------------------------------------
How can I do the same with divs, using flexbox, so that the first column consumes the least amount of width, but the second column is still aligned?
Is this even possible?
The reason why I want to do this is because I want each row to be a Quasar q-card, but the elements in there should align with the cards above and below, yet still consume the least amount of space and not be width-controlled through the "12-column"-grid-system.
Basically like this, where I need the badges and inputs to be aligned as if it were a table (I cannot use a q-table, and -- due to the use of UMD -- also not a q-markup-table):
<q-card>
<q-card v-for='element in elements'>
<q-badge>{{element.badge}}</q-badge>
<q-input v-model='element.text'></q-input>
</div>
</div>
Instead of flex, it would probably be better to use display:table
div {
display: table;
}
div>div {
display: table-row;
}
div>div>div {
display: table-cell;
}
<div>
<div>
<div>row_1.col_1</div>
<div>row_1.col_2</div>
</div>
<div>
<div>row_2.col_1.with_longer_content</div>
<div>row_2.col_2</div>
</div>
</div>
Using display: flexbox you can do this by organizing the data by column instead of by row. Using display: table you can maintain the structure of the table. Examples:
.flex-table {
display: flex;
}
.column {
padding: 4px;
}
.table {
display: table;
}
.table-row {
display: table-row;
}
.table-cell {
display: table-cell;
padding: 0 4px;
}
<h3>table</h3>
<table>
<tr>
<td>row_1.col_1</td>
<td>row_1.col_2</td>
</tr>
<tr>
<td>row_2.col_1.with_longer_content</td>
<td>row_2.col_2</td>
</tr>
</table>
<h3>flexbox table</h3>
<div class="flex-table">
<div class="column">
<div>row_1.col_1</div>
<div>row_2.col_1.with_longer_content</div>
</div>
<div class="column">
<div>row_1.col_2</div>
<div>row_2.col_2</div>
</div>
</div>
<h3>display table</h3>
<div class="table">
<div class="table-row">
<div class="table-cell">row_1.col_1</div>
<div class="table-cell">row_1.col_2</div>
</div>
<div class="table-row">
<div class="table-cell">row_2.col_1.with_longer_content</div>
<div class="table-cell">row_2.col_2</div>
</div>
</div>
<style>
.row {
display: -ms-flexbox;
display: flex;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
margin-right: -15px;
margin-left: -15px;
}
.col {
-ms-flex-preferred-size: 0;
flex-basis: 0;
-ms-flex-positive: 1;
flex-grow: 1;
max-width: 100%;
position: relative;
width: 100%;
padding-right: 15px;
padding-left: 15px;
}
.text-wrap {
white-space: normal !important;
}
</style>
<div>
<div class="row">
<div class="col text-wrap">row_1.col_1</div>
<div class="col text-wrap">row_1.col_2</div>
</div>
<div class="row">
<div class="col text-wrap">row_2.col_1.with_longer_content</div>
<div class="col text-wrap">row_2.col_2</div>
</div>
</div>
Try writing like this & if you don't want to use the above styles use the bootstrap css link instead.

How to Get Float Behavior Inside Flex Element?

Looking to have one large item on the left and a lot of small items on the right. If the browser window is big enough, I'd like the small items to "float" in a columnar manner such that they don't exceed the height of the large item. However, when the browser shrinks, I'd like the small items to wrap down below the large one in a single row.
Here's a codepen to demonstrate: https://codepen.io/anon/pen/WXQdEN
div.container {
display: flex;
flex-wrap: wrap;
}
div.right-variable {
max-height: 320px;
align-items: center;
}
div.test-700 {
width: 700px;
height: 320px;
background: green;
color: #ffffff;
font-size: 40px;
}
div.test-100 {
width: 100px;
height: 100px;
background: red;
outline: 1px solid black;
margin: 2px;
float: left;
}
<table>
<tr>
<td>
<div class="test-700">Example Table</td>
</td>
<td>
<div class="test-100"></div>
<div class="test-100"></div>
<div class="test-100"></div>
<div class="test-100"></div>
<div class="test-100"></div>
<div class="test-100"></div>
</td>
</tr>
</table>
<div class="container">
<div class="left-fixed">
<div class="test-700">Non-Working Flex</div>
</div>
<div class="right-variable">
<div class="test-100"></div>
<div class="test-100"></div>
<div class="test-100"></div>
<div class="test-100"></div>
<div class="test-100"></div>
<div class="test-100"></div>
</div>
</div>
The table shows the desired behavior of the red boxes at large resolutions. As the browser shrinks, the boxes float around to fill the space.
But when the browser gets too small to contain them, I want the flex behavior where the red boxes wrap down under the green one. I understand that this doesn't work because I can't float the items within the flex, but I don't understand how to achieve a similar behavior without float. I'd like to achieve this using flex and CSS only. Is that possible?
Thank you for any assistance.
The main issue here is related to sequence for wrapping and since the browser don't know which to wrap before the other, they start with the outer element.
Also, there is no property that one can set, to define the order, but there is media query, where we can set a breaking point, and in this case, use it to tell when the container is allowed to wrap.
Remove flex-wrap: wrap from the container and add it back at a desired maximum width using a media query.
Then also make the div.right-variable a flex container and have the red elements centered.
Stack snippet
div.container {
display: flex;
}
div.right-variable {
margin: auto 0; /* center vert. */
max-height: 320px;
display: flex;
flex-wrap: wrap;
}
div.test-700 {
width: 700px;
height: 320px;
background: green;
color: #ffffff;
font-size: 40px;
}
div.test-100 {
margin: auto 0; /* center vert. */
width: 100px;
height: 100px;
background: red;
outline: 1px solid black;
margin: 2px;
}
#media (max-width: 816px) {
div.container {
flex-wrap: wrap;
}
}
<div class="container">
<div class="left-fixed">
<div class="test-700">Working Flex</div>
</div>
<div class="right-variable">
<div class="test-100"></div>
<div class="test-100"></div>
<div class="test-100"></div>
<div class="test-100"></div>
<div class="test-100"></div>
<div class="test-100"></div>
</div>
</div>

Set div to have its siblings width

I'm looking for a CSS solution to the following:-
<div style="display:inline;">
<div>The content of this div is dynamically created but will always be wider than
the below div.
</div>
<div> Need this div to have the same width as the above div.
</div>
</div>
The wrapper div has an inline display and works as expected, both child divs have dynamically generated content. I need the bottom one to take the width of the previous sibling.
Many thanks for any suggestions in advance.
Here's another Flexbox solution which allows for the second child to wrap to match the width of the variable height sibling.
.wrapper > div {
border: 1px solid;
}
.child {
display: flex;
}
.child div {
flex-grow: 1;
width: 0;
}
.wrapper {
display: inline-block;
}
<div class="wrapper">
<div>This div is dynamically sized based on its content</div>
<div class="child"><div>This div will always be the same width as the preceding div, even if its content is longer (or shorter too).</div></div>
</div>
Edit:
To support multiple divs under .child, where each div is on its own line, add break-after: always; ...
.child div {
flex-grow: 1;
width: 0;
break-after: always;
}
Floats and tables are so 2000 and late. With today's browsers we can make the two sibling DIVs match each other's width, regardless which is bigger/smaller.
Here's a Flexbox solution fit for 2016:
.wrapper {
display: inline-block;
}
.parent {
display: flex;
flex-direction: column;
}
/* For visualization */
.child {
border: 1px solid #0EA2E8;
margin: 2px;
padding: 1px 5px;
}
<div class="wrapper">
<div class="parent">
<div class="child">Child number one</div>
<div class="child">Child #2</div>
</div>
</div>
Set your div to display:inline-block instead, this way your div will expand with the content inside of it.
http://jsfiddle.net/CpKDX/
2023 keep it simple...
Use grid and the fr unit. Then you can split up into as many equally sized rows or columns as you want:
.container {
display: grid;
grid-template-columns: repeat(2, 1fr);
grid-column-gap: 1em;
}
.container > div {
border: 1px solid black;
padding: 0.5em;
}
<div class="container">
<div>I'm a part of a grid. I will be split up into equal parts with my other sibling(s) depending on how many columns the grid is given.</div>
<div>I am a sibling element.</div>
</div>
Here is still a flexbox-based approach.
The essential idea: in an outermost wrapper, elements that need to be of equal width are wrapped into another wrapper.
.wrapper {
display: inline-block;
}
.flex-wrapper {
display: flex;
flex-direction: column;
}
.demo-bar {
height: 4px;
background-color: deepskyblue;
}
<div class="wrapper">
<div class="flex-wrapper">
<div contenteditable>Some editable text.</div>
<div class="demo-bar"></div>
</div>
</div>
Another practical example: an adaptive progress bar with the same width below a media (video or audio) element.
video.addEventListener("timeupdate", () =>
progress.style.width = `${video.currentTime / video.duration * 100}%`
)
.wrapper {
display: flex;
flex-direction: column;
position: relative;
align-items: center;
}
video {
display: block;
max-width: 100%;
}
.progress-bar {
height: 0.25rem;
background: #555;
}
#progress {
width: 0%;
height: 100%;
background-color: #595;
}
<div class="wrapper">
<div data-css-role="wrapper">
<video id="video" controls>
<source src="https://raw.githubusercontent.com/mdn/interactive-examples/master/live-examples/media/cc0-videos/flower.webm">
</video>
<div class="progress-bar">
<div id="progress"></div>
</div>
</div>
</div>
UPDATE: This works with me, I've just tried it:
<div style="max-width:980px;border:1px solid red;">
<div style="background:#EEE;float:left;">
<div style="width:auto;border:1px solid blue;float:left;">If you use 100% here, it will fit to the width of the mother div automatically.</div>
<div style="border:1px solid green;"> The div will be 100% of the mother div too.</div>
</div>
<div style="clear:both;"></div>
</div>
Is this what you want? The borders and background are just to show the divs ;)
Just go like this:
Let's say you want the whole divs be max. 980px (otherwise just leave that out or replace with 100%)...
<div style="max-width:980px;">
<div style="width:100%;">If you use 100% here, it will fit to the width of the mother div automatically.
</div>
<div style="width:100%;"> The div will be 100% of the mother div too.
</div>
</div>
The second option would be, to use one more div... or you use style="width:auto;" for the dynamic div...
Not sure if I understood what you are trying to do, but looks like setting a 100% width to the last div should work:
<div style="width:100%;">
BTW the style in the first div is not well defined, you should use a colon instead of a equal sign in the properties definition:
<div style="display:inline;">
If your willing to give up on a couple of <div>s then I have the solution for you:
<div style=“display: inline-block;”>
<table>
<tr>
<td>The table automatically makes its siblings the same width</td>
</tr>
<tr>
<td>So this will be as wide</td>
</tr>
</table>
</div>
Remember to set the div display:inline-block;