How to set column width to be as small as possible? - css

I'm trying to set the last three columns to be as small as possible since they're just holding icons/links for actions.
I'd also want to the large text columns to have as much of the remaining width as possible.
Here's what I was able to find, but didn't work for me:
Two columns table : one as small as possible, the other takes the rest
This solution doesn't work for me because I have multiple columns that I want to take up as much space as possible, so I can't set any of them to width = 100%.
force column size to smallest possible
I tried using relative lengths (width="*"), but it doesn't seem to have any effect. Maybe it's because I didn't set any widths prior so there's no 'remaining width' to distribute out?
HTML:
<table>
<colgroup class='data' span='5'>
<col class='date' span='1'/>
<col class='id' span='1'/>
<col class='title' span='1'/>
<col class='status' span='1'/>
<col class='description' span='1'/>
</colgroup>
<colgroup class='action' span='3'>
<col class='show' span='1'/>
<col class='edit' span='1'/>
<col class='delete' span='1'/>
</colgroup>
<tr>
<th>Date</th>
<th>ID</th>
<th>Title</th>
<th>Status</th>
<th>Description</th>
<th colspan='3'></th>
</tr>
<tr>
<td class='date'>medium</td>
<td class='id'>medium</td>
<td class='title'>large</td>
<td class='status'>medium</td>
<td class='description'>large</td>
<td class='show'>small</td>
<td class='edit'>small</td>
<td class='delete'>small</td>
</tr>
</table>
CSS:
table {
width: 100%;
}
table td.title, td.description {
text-align: left;
}
table td.date, td.id, td.status {
text-align: center;
}
table td.show, td.edit, td.delete {
}
table colgroup.action col {
width:"1*";
}
table colgroup.data col {
width:"*";
}
So in the order of priority:
table spans entire width of parent container
the last three icon/action columns to be as small as possible without any cutoff
the columns with 'large' data (class title and description) should take up as much of the remaining space as possible
the columns with 'medium' data should be the size of their content with some margin on both sides (I don't mind just throwing in a fixed width if it's too difficult to accomplish this)
I don't need the colgroup and col tags, but I just left them in here in case they can be useful. I've tried different permutations of using and not using them, but still can't seem to get it to work. I also thought about using percents for the data columns, but I'd want the browser to determine the widths based on the actual content rather than me imposing predefined rules that might not be optimal.

For the columns you want to shrink, set the width to 1 px:
table {
width: 100%;
}
th, td {
border: 1px solid #eee;
}
td.title, td.description {
text-align: left;
}
td.date, td.id, td.status {
padding: 0 10px;
text-align: center;
width: 1px;
}
td.show, td.edit, td.delete {
width: 1px;
}
Then you can get rid of the colgroups altogether.
See demo here.
By the way, you might consider using CSS flexible boxes instead.

To answer one of your requests:
the last three icon/action columns to be as small as possible without
any cutoff
To do this, I would float the tds or set them to display:inline-block;
If you know the size of the icons you are using, you can then set the width on the th above the icons (which I would call class="icons").
If you don't know the width, you could calculate using some jQuery.
var a = $('td.show').width();
var b = $('td.edit').width();
var c = $('td.delete').width();
$('.icons').css('width', a+b+c+6+"px");
Example: http://jsfiddle.net/KQs2K/1/
Extra 6px needed to pad out the border bits I threw in the example
Note: these tds will stack when the screen size gets real small.

Related

How to split extra space evenly between columns when setting width on table

I've been looking for an answer to this question for a long time but never saw a glimpse of an answer.
I am making a table in HTML and sets it a specific width (usualy so it occupies all the space). It is bigger than it has to be so there is extra space split between the different columns. The problem is that it is split proportionally to the cell's width and not evenly which looks weird.
For instance for a width of 120px, you would have something like a 10px large column with a 20px extra space on the left than a 30px large column with a 60px extra space on the left.
Instead of 10 + 20 + 30 + 60, I would prefer 10 + 40 + 30 + 40 but I cannot see a way to do it. It would probably be a table-layout in my opinion but the only other option is "fixed" which gives a fixed size to the entire column and not the extra space (giving 10 + 50 + 30 + 30)
I hope I managed to make my question clear, sorry for the bad english
EDIT : I managed to make the snippet work, as you can see, the white space on the right of every cell is never the same which looks weird
table{
width: 600px;
border-collapse: collapse;
}
.fixed{
table-layout: fixed;
}
td{
border: 1px solid black;
}
<table>
<tr>
<td>Short</td>
<td>A much much much much longer cell</td>
<td>A</td>
</tr>
</table>
<table class="fixed">
<tr>
<td>Short</td>
<td>A much much much much longer cell</td>
<td>A</td>
</tr>
</table>
If you're looking for equal spacing on the right side of content in a cell, I don't believe this is possible with HTML and CSS alone. You will probably need to use JavaScript to get the results you are looking for. I've pieced together this "Frankenstein" script for you. I doubt it's the cleanest code or most functional, but it seems to accomplish what you need. If this doesn't work for you, I would look into Sass or completely abandon a table layout and use divs.
const table = document.getElementById('myTable'); // Select Table
const width = table.clientWidth; // Record Fixed Width
table.style.width = "auto"; // Remove Table Width (I can't get this to work without removing the table width).
let length = 0;
let padding = 0;
const row = table.rows[0]; // Select First Row
const cols = row.children; // Select Each Cell in First Row
[].forEach.call(cols, function(col) {
length += col.clientWidth; // Measure Cell Content
});
// Calculate Padding
if (width >= length) {
padding = (width - length) / cols.length;
} else {
// If Content Length is >= Table Width, the Default to Table Width (No Padding).
table.style.width = `${width}px`;
}
// Add Padding to Each Cell in Table
const rows = table.rows;
[].forEach.call(rows, function(row) {
const cells = row.children;
[].forEach.call(cells, function(cell) {
cell.style.paddingRight = `${padding}px`
});
});
table {
width: 500px;
border-collapse: collapse;
}
td { border: 1px solid black; }
<table id="myTable">
<tr>
<td>Stuff</td>
<td>A lot more stuff</td>
<td>Some stuff</td>
</tr>
<tr>
<td>Stuff</td>
<td>A lot more stuff</td>
<td>Some stuff</td>
</tr>
<tr>
<td>Some Stuff</td>
<td>Fun stuff that I like</td>
<td>Some stuff</td>
</tr>
</table>
I think you have to provide fixed widths for <tr> and <td> too.

min-width isn't preferred strongly enough when child is a table

My previous question got an answer using min-width to set the width of a containing block but allow it to grow when its children are too big.
This worked fine with some kinds of children (simple divs with their own min-width and max-width specified explicitly). Now I'm looking at a more complex variation in which the children are tables. (Legitimate tables with semantically meaningful rows and columns, not page-layout tables.)
There is no manually-specified min-width or max-width on these tables, but tables have an inherent maximum and minimum width, corresponding to the width that the table would have if rendered with no line breaks in any of the cells (maximum) and the width that it would have with line breaks inserted insertion of all possible line breaks (minimum).
In the existing page layout which I'm trying to replace, the outermost container is a table (the bad kind of table) with a single cell in a single row, and a CSS width (not min-width) set to the preferred width. When the children are tables, they try really hard to fit into the container's width. A wide table will be rendered with line breaks to make it fit, and the container will expand only if the child still doesn't fit after all line breaks are inserted.
In other words, the parent's width property is treated as a minimum, but it is also a strongly preferred width, which has a higher priority than the child's preferred (i.e. maximum) width.
By contrast, when the parent is a plain div with display:inline-block and a specified min-width, the parent's min-width is not strongly preferred. The child prefers to be wider, so the parent expands, even if the child is capable of being rendered with a smaller width.
Here's a snippet, much like the one in the previous question, which demonstrates all of this. The goal is to make the second container act like the first one in some way that is more "proper" than using display:table for layout.
(Note: the table widths at the heart of this question are very sensitive to choice of font. I hope the Courier New comes through and everybody sees the same widths in the snippet.)
var containers = document.querySelectorAll(".container");
for(var i = 0; i < containers.length; ++i) {
(function() {
var c = containers[i],
b = c.nextElementSibling;
b.addEventListener("click", function(ev) {
big = c.querySelector(".bigchild");
medium = c.querySelector(".mediumchild");
small = c.querySelector(".smallchild");
if(big.style.display != "block" &&
medium.style.display != "block" &&
small.style.display != "block") {
big.style.display = "block";
} else if(big.style.display == "block") {
big.style.display = "none";
medium.style.display = "block";
} else if(medium.style.display == "block") {
medium.style.display = "none";
small.style.display = "block";
} else {
small.style.display = "none";
}
});
})();
}
body {
background-color: #ccc;
text-align: center;
font-size: 14px;
font-family: "Courier New";
}
table {
border-collapse: collapse;
}
td {
border: 1px solid black;
padding: 5px;
}
.container {
background-color: white;
min-height: 250px;
margin-left: auto;
margin-right: auto;
}
.bigchild, .mediumchild, .smallchild {
display: none;
}
button {
display: block;
margin: 10px auto 20px;
}
#container1 {
display: table;
width: 400px;
}
#container2 {
display: inline-block;
min-width: 400px;
}
<div class="container" id="container1">
<table class="bigchild">
<tr>
<td>Lots of</td>
<td>columns</td>
<td>make this</td>
<td>a very</td>
<td>wide</td>
<td>table</td>
<td>that won't</td>
<td>fit</td>
<td>even with</td>
<td>added</td>
<td>line breaks</td>
</tr>
</table>
<table class="mediumchild">
<tr>
<td>This table</td>
<td>is smaller</td>
<td>and</td>
<td>it fits</td>
<td>but</td>
<td>only with</td>
<td>added</td>
<td>line breaks</td>
</tr>
</table>
<table class="smallchild">
<tr>
<td>very</td>
<td>small</td>
</tr>
</table>
</div>
<button>Next</button>
<div class="container" id="container2">
<table class="bigchild">
<tr>
<td>Lots of</td>
<td>columns</td>
<td>make this</td>
<td>a very</td>
<td>wide</td>
<td>table</td>
<td>that won't</td>
<td>fit</td>
<td>even with</td>
<td>added</td>
<td>line breaks</td>
</tr>
</table>
<table class="mediumchild">
<tr>
<td>This table</td>
<td>is smaller</td>
<td>and</td>
<td>it fits</td>
<td>but</td>
<td>only with</td>
<td>added</td>
<td>line breaks</td>
</tr>
</table>
<table class="smallchild">
<tr>
<td>very</td>
<td>small</td>
</tr>
</table>
</div>
<button>Next</button>
I think .container {min-width: 400px;width: min-content;}, modulo vendor prefixes, is what you want.

column width not controlled by row above it

Putting 2 one-row tables after each other I get the desired outcome: 2 adjacent rows that don't have the same column width. http://jsfiddle.net/x2SQN/
---------------------
|100px | 100% - 100px|
---------------------
| 50% | 50% |
---------------------
Can I achieve this also with a single <table>?
http://jsfiddle.net/x2SQN/
Basically I cannot use javascript or not in-line css.
No. Within a table the columns remain consistent from top to bottom.
You can play around with the colspans of each cell but that's about it.
e.g. if you wanted you could do this.
<table>
<tr>
<td width="20%">20%</td>
<td width="30%">30%</td>
<td width="50%">50%</td>
</tr>
<tr>
<td width="50%" colspan="2">50%</td>
<td width="50%">50%</td>
</tr>
</table>
But you will be limited to using a combination of fixed px sizes OR % sizes as you can't do 50% - 100px for example.
Usually, We transform block elements to the table model to achieve a 'Table like' display, and now, as a solution to your problem: I found myself doing just the opposite.
the main idea is to transform your table, to a block model design, where we can take control of the width of every element.
the main gain of my solution, is that you can use CSS function (like calc) to give responsive width to column [like calc(100% - 100px)].
but the main downsize of my solution is the scenario when you have different cells height in the same row.
luckily that can be easily fixed with faux columns techniques. (I used one-true-layout)
so, after all that been said, lets take a look at the solution: (some of it is written in the CSS section, with regular CSS selectors and not inline as you requested, because it was easier for me. but you can copy-past everything to the right place and make it all-inline)
Working Fiddle Tested on: Chrome, IE10, FF
HTML (I've add the <tbody> so you can apply the inline-CSS styling)
<table>
<tbody>
<tr>
<td style="background-color:red; width: 100px;">100px</td>
<td style="background-color:yellow; width: calc(100% - 100px);">100% - 100px<br/>another line to demonstrate <i>faux column</i></td>
</tr>
<tr>
<td style="background-color:azure; width:50%;">50%</td>
<td style="background-color:pink; width:50%;">50%</td>
</tr>
</tbody>
</table>
CSS (all of that styling can be placed inline)
*
{
margin: 0;
padding: 0;
}
table, tbody, tr
{
display: block;
}
tr
{
overflow: hidden; /*Faux column*/
}
td
{
float: left;
padding-bottom: 99999px; /*Faux column*/
margin-bottom: -99999px; /*Faux column*/
}
You can do this using fake colspan values. Treat them as percentages to keep it simple.
<table border="0" cellspacing="6" width="400">
<tr>
<td colspan="30" style="background-color:red;" />
<td colspan="70" style="background-color:yellow;"/>
</tr>
<tr>
<td colspan="70" style="background-color:black;" />
<td colspan="30" style="background-color:pink;" />
</tr>
</table>

Responsive table alignment of columns

In responsive table design to refer I got this link jsfiddle.net/n4rUG/27/
This gives me below output:
Now I want to align title to left and its value to right
means it need to look aligned properly
How to do this?
The text-align: right doesn't work for your tds because it's overridden by the Bootstrap style with higher specifity. The quickest solution is just to add !important. Also, I'd suggest to make the labels floating to left (see modified fiddle):
td {
...
text-align: right !important;
overflow: hidden; /* for containg floats */
}
td:before {
...
float:left;
}
Your JSFiddle is different then the image in your post.
Refering to your image, you could make it like this, using colspan to set your colums width:
<table>
<colgroup>
<col width="100px" />
<col width="200px" />
</colgroup>
<tr>
<td>title</td>
<td>value</td>
</tr>
<tr>
<td>title</td>
<td>value</td>
</tr>
...
</table>
As for your JSFiddle, you have 5 <th>'s and 6 <td>'s. Which is possible, however, one of the <th> should cover two <td>'s, you can make that by using this:
<th colspan="2">Title</th>

fixed column height and width

I am having a table as follows:
<table>
<tr style ="height: 10px;" >
<td style="width: 200px, height : "10px;"> </td> <td style="width: 200px , height : "10px;"> </td> <td style="width: 200px , height : "10px;"> </td> <td style="width: 200px , height : "10px;"> </td>
</tr>
</table>
The problem is, when the contents in the second column of any row are slightly large, the width of the second column exceeds 150px, and to compensate the width of the first column reduces. How can I prevent that from happening. I want to widths to not change and even if the extra texts are not shown it`s fine.
I also want the height of the rows and columns to be of 3 lines of text and fixed in height.
First off, the code was incorrect. Here's your code corrected, try does it work what you wanted it to:
<table>
<tr style="height: 10px;" >
<td style="width: 200px; height:10px;"></td>
<td style="width: 200px; height:10px;"></td>
<td style="width: 200px; height:10px;"></td>
<td style="width: 200px; height:10px;"></td>
</tr>
</table>
Second, the way you're styling is very old-school and hard on you, try creating a CSS class which you can then apply to every element, no need to repeat the rules. In fact, if this will be the only table on your page, you can put something like this inside head:
<style type="text/css">
td {
width: 200px;
height:10px;
}
</style>
That will apply your rules to all tags on page, so you don't have to explicitly style each and every one.
Or you can do:
<style type="text/css">
.exampleclass {
width: 200px;
height:10px;
}
</style>
<table>
<tr style="height: 10px;" >
<td class="exampleclass"></td>
<td class="exampleclass"></td>
<td class="exampleclass"></td>
<td class="exampleclass"></td>
</tr>
</table>
That way you control your styling from one place, and are also able to apply it to other elements as you see fit.
If there's anything else, ask away.
EDIT: And for fulfilling your requirement of widths being fixed at cost of extra content not showing, apply both answers of Guzzie and QQping. Although if you're ok with varying height, you don't have to set overflow:hidden;
You should set the table's style to fixed like this and add the total width of the table
<table style='table-layout:fixed' width='300px'>
Firefox may not like to see table cells with overflowing long texts cause of fixed column-widths, to better display this you should set the following TD style in your css or on your current page
<style>
td {overflow:hidden;}
</style>
Simply add max-width with to your table cell.

Resources