I need a two column table that has only one row. The data in the first column should always display in full, but the second column should resize and the data in it should ellipse if it can't fit in the cell. If the first column expands to fit its data, the second column should contract, all while keeping the table width the same.
I tried to fix width of table and all kinds of ways to achieve this with CSS, but I couldn't figure out. It does seem like it's something that should be achievable.
This is how the table should behave with different data in the first column:
.ellipsis {
width: 190px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
display: inline-block;
}
<h3>table width always the same</h3>
<table border="1">
<tr>
<th>
Column1
</th>
<th>
Column2
</th>
</tr>
<tr>
<td>
<label>Display in full</label>
</td>
<td>
<label class="ellipsis">Ellipsis this if length is too long</label>
</td>
</tr>
</table>
Like I mention in the comments, it can be achieved using flex-box.
.parent has display: flexbox
Column 1 has white-space: nowrap to make it fit its content.
Column 2 has flex-grow so it will take all the remain space.
.parent {
display: flex;
width: 350px;
border: 1px solid;
}
.header {
text-align: center;
font-weight: bold;
border-bottom: 1px solid;
}
.parent > div:first-child {
white-space: nowrap;
border-right: 1px solid;
}
.parent > div:last-child {
flex-grow: 1;
}
.parent div:last-child {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.parent > div > div {
padding: 1px;
}
<div class="parent">
<div>
<div class="header">Column1</div>
<div>Display in full</div>
</div>
<div>
<div class="header">Column 2</div>
<div>Ellipsis this if length is too long</div>
</div>
</div>
https://jsbin.com/ferixiq/3/edit?html,css,output
Related
I'm working on a table layout that needs CSS love. My goal is simple: 2 rows, 2 cols. The table will have a fixed width of say 250px, the first col will have a max width of say 100px (but the text inside can wrap), and the second col should occupy the remainder of the table width, but should not wrap and should instead have a text ellipsis at the end of the first line.
Here's my current approach. You'll see the second column makes the table wider than 250px:
.table {
display: table;
width: 250px;
overflow: hidden;
background: #f7f5eb;
color: #cf6824;
}
.tr {
display: table-row;
}
.tc {
display: table-cell;
padding: 10px 0;
}
.truncate {
max-width: 100px;
}
.no-wrap {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
<div class='table'>
<div class='tr'>
<div class='tc truncate'>Wow such CSS very style</div>
<div class='tc no-wrap'>That was a very loud beep. I don't even know if this is working.</div>
</div>
<div class='tr'>
<div class='tc truncate'>Mark? Mark? Are you there?</div>
<div class='tc no-wrap'>Are you screening your calls? It's Mom? We wanted to call and say we love you.</div>
</div>
</div>
As you can see, my second col (.no-wrap) is extending the table width, which I'd like to prevent.
How can I achieve the goal expressed above? Any pointers would be very welcome!
I'm a having a bit of an issue here. I have a flexbox container with children of different sizes. Based on quantity and their content children might overflow the parent.
What I want is the children to shrink so they try to fit in the parent container. I did that by adding shrink and overflow properties to the children. So far so good.
.container > div {
background-color: orange;
padding: 5px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
flex-shrink: 1;
}
I end up with something like this:
Now I want them to shrink but up to a certain point (lets say 80px). I don't care if they end up overflowing the container but I don't want to render any smaller than 80px.
Of course, I added min-width: 80px to the children... but here is my problem. I want the children to shrink up to 80px but I don't want any of those that were smaller than 80px already (like Child1, Child4 and Child5) I don't want them to be enlarged by the min-width property (or, I want them to shrink further up to min-content)
In other words. I don't want this:
I would love to have something like this:
I tried doing something like min-width: min(min-content, 80px) but of course, didn't work.
Here is an small codepen with the issue: https://codepen.io/claudiofpen/pen/QWELVJO
.container {
width: 300px;
border: 1px solid black;
display: flex;
flex-direction: row;
padding: 5px;
}
.container > div {
background-color: orange;
padding: 5px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
flex-shrink: 1;
min-width: min-content;
}
.container > div:not(:last-child) {
margin-right: 5px;
}
/* I don't want the following css classes, I cannot
tell in before hand which children are going to have
a larger content */
.container > div:nth-child(2),
.container > div:nth-child(3) {
min-width: 80px;
}
<div class="container">
<div>Child 1</div>
<div>Longer Child 2</div>
<div>Longer Child 3</div>
<div>Child 4</div>
<div>Child 5</div>
</div>
Temani Afif's solution solves the problem of ensuring that a text element will not shrink below the specified width unless its intrinsic width is already below that width (in which case it uses its intrinsic width as the rendered width). But it does not work unless the sum of the specified widths of all the child elements exceeds the container's width.
So I tried giving each outer elements a flex-grow parameter, so that they would grow above their specified width, if the container had room. But I also give the outer elements a maximum width set to their intrinsic maximum content width, so they would never grow beyond the actual size of the text. Thus I added the following styles to the wrapping div.
flex: 1 1 auto;
max-width: max-content;
With that tweak I believe it solves the entire problem. The elements expand fully if there is room in the container. As we add more elements the longer elements start to shrink. But they never shrink below their specified width, so the container overflows once all inserted elements have shrunk down to that width. But elements that started with a shorter width never flex at all.
I have added an example below.
.container {
width: 340px;
border: 1px solid black;
display: flex;
flex-direction: row;
padding: 5px;
}
.container>div {
background-color: orange;
padding: 5px;
flex: 1 1 auto;
width: 80px;
max-width: max-content;
}
.container>div>div {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
width: 100%;
}
.container>div:not(:last-child) {
margin-right: 5px;
}
<h5>When the items fit they expand to their intrinsic length</h5>
<div class="container">
<div>
<div>Medium length</div>
</div>
<div>
<div>Tiny</div>
</div>
<div>
<div>Longer text element</div>
</div>
</div>
<h5>When the container limit is reached the longer elements start shrinking</h5>
<div class="container">
<div>
<div>Medium length</div>
</div>
<div>
<div>Tiny</div>
</div>
<div>
<div>Longer text element</div>
</div>
<div>
<div>Filler</div>
</div>
</div>
<h5>Adding more elements...</h5>
<div class="container">
<div>
<div>Medium length</div>
</div>
<div>
<div>Tiny</div>
</div>
<div>
<div>Longer text element</div>
</div>
<div>
<div>Filler</div>
</div>
<div>
<div>Filler</div>
</div>
</div>
<h5>When there is no room it overflows<br> The tiny element stays at its intrinsic width, but the bigger elements stop shrinking at the specified width</h5>
<div class="container">
<div>
<div>Medium length</div>
</div>
<div>
<div>Tiny</div>
</div>
<div>
<div>Longer text element</div>
</div>
<div>
<div>Filler</div>
</div>
<div>
<div>Filler</div>
</div>
<div>
<div>Filler</div>
</div>
</div>
With an extra wrapper you can do it:
.container {
width: 300px;
border: 1px solid black;
display: flex;
flex-direction: row;
padding: 5px;
}
.container > div {
background-color: orange;
padding: 5px;
flex-shrink: 1;
width: 80px;
}
.container > div > div {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
width: 100%;
}
.container > div:not(:last-child) {
margin-right: 5px;
}
<div class="container">
<div><div>Ch 1</div></div>
<div><div>Longer Child 2</div></div>
<div><div>Longer Child 3</div></div>
<div><div>Child 4</div></div>
<div><div>Child 5</div></div>
</div>
Grid Solution
.container {
width: 300px;
border: 1px solid black;
display: grid;
grid-template-columns: max-content 80px 80px repeat(2,max-content);
padding: 5px;
}
You can use javascript to make the grid-template-column dynamic.
Here is the jquery (javascript) solution using flex
.container {
width: max-content;
border: 1px solid black;
display: flex;
padding: 5px;
}
$(".container > div").each(function(){
($(this).width() < 50) ?
$(this).css('width','max-content') :
$(this).css('flex','0 0 80px');
})
This is more dynamic than the grid solution. The only thing is that you will need to have a desired number in $(this).width() < 50 instead of fifty based on your content.
I have a inline-flex container with two inner blocks that must expand (without wrapping).
In the second block there is another inline-flex container with two inner inline-blocks that must never wrap their content.
What I need
Is to show the text-overflow: ellipsis when the width of the most-top container (div.width) is not enough for displaying all the inner blocks as white-space: nowrap.
The content of div.width must never overflow its container, in the case the content of the a link is too long.
Snippet
.splitbutton {
display: inline-flex;
border: 4px solid violet;
}
.default {
display: inline-block;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
min-width: 0;
}
.default a {
/* white-space: nowrap; */
}
.button {
background-color: green;
padding: 5px;
}
.container1 {
white-space: nowrap;
}
.container1,
.container2 {
flex: 1 1 auto;
border: 3px double green;
}
.width {
border: 3px solid red;
/*width: 350px;*/
display: inline-flex;
flex-wrap: nowrap;
flex-direction: row;
}
<div class="width">
<div class="container1">
<span>Any kind of inline text</span>
</div>
<div class="container2">
<div class="splitbutton">
<div class="default">
Looooooooooooong text with many many spaces and letters
</div>
<span class="button">button</span>
</div>
</div>
</div>
Note
None of the present blocks can specify a specific fixed width!
The button must always stay visible (the ellipsis should eventually be applied to the a link element).
I'm trying to position a few elements in a row, so that they all fit in the width of the container. To prevent them from word-wrapping I added "white-space: nowrap" to the parent, and added "white-space: normal" to the children to allow them to wrap the text (as desired).
The problem is that with this configuration the right most child sometimes exceeds the width of the parent.
HTML:
<div id="container">
<div class="child">
child 1
</div>
<div class="child">
child 2 text that might be long enough to wrap, but still exceed the parent
</div>
</div>
CSS:
#container {
white-space: nowrap;
width: 200px;
background: yellow;
border: 1px solid brown;
padding: 5px;
}
.child {
display: inline-block;
border: 2px solid red;
vertical-align: top;
white-space: normal;
}
http://jsfiddle.net/7e5TU/1/ (change the length of the text if the problem doesn't appear straight away).
I know that I can solve it with a table, and probably with a float on the left child, and "overflow: hidden" on the right, but I see no reason why this should not work.
Could anyone provide some insights? I'd mostly love to understand what in the box model causes this behavior. Thanks!
I agree with #hashem That's the expected behavior. By using white-space: nowrap; for the parent, you've collapsed the whitespaces between inline(-block) elements. white-space treats the children, not the element itself.
Well if you still need a fix you can add width to second child to make it fit inside container.
fiddle
e.g.
.child2
{
width: 70%;
}
If you are willing to use flexbox (https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Flexible_boxes) you could do it like this:
http://jsfiddle.net/7e5TU/6/
HTML
<div id="container">
<div class="child1">
child 1
</div><div class="child2">
child 2 text that might be long enough to wrap,
but still exceed the parent
</div>
</div>
CSS
#container {
width: 200px;
background: yellow;
border: 1px solid brown;
padding: 5px;
display: flex;
flex-direction: row
}
.child1, .child2 {
display: block;
border: 1px solid red;
vertical-align: top;
}
.child1 {
min-width: 50px;
}
You can do this with CSS display:table. This way no sizing details are needed.
It ensures the elements stay in a row and the text will wrap perfectly to the width of the parent container.
HTML
<div class='container'>
<div class='field'>
<div class='data'>
child 1
</div>
</div>
<div class='field'>
<div class='data'>
child 2 text that might be long enough to wrap, but still exceed the parent
</div>
</div>
</div>
CSS
.container {
display: inline-table;
border-spacing: 4px;
background: yellow; border: 1px solid brown;
padding: 5px;
}
.field {
display: table-cell;
}
.data {
border: 2px solid red;
padding: 3px;
}
How can I implement a table that is both horizontally and vertically scrollable with fixed header using css?
I found this Scrolling a div from an outer div, but it is implemented by using Javascript/Jquery. Any way to implement it by using only CSS?
The updated code:
#div-table-content {
width: 100%;
overflow-x: auto;
}
table {
font-size: 12px;
white-space:nowrap;
overflow-x: scroll;
}
tbody {
height: 400px;
overflow-y: auto;
width: 100%;
display: block;
}
thead tr {
display: block;
width: 100%;
}
For a start divide your <table> semantically to headers inside <thead> and content inside <tbody>.
Then, for vertical scrolling, give a fixed height to your <tbody> and set overflow-y: auto and display: block.
For horizontal scrolling, I belive you have to wrap your entire table with a container (lets say <div> and give it a fixed width and overflow-x: auto.
jsFiddle Demo
You can fake table with css-grid (if you don't mind).
.table {
display: grid;
width: 100px;
height: 70px;
overflow: auto;
grid-auto-columns: max-content;
}
.head {
position: sticky;
top: 0;
grid-row: 1;
background-color: #fff;
font-weight: bold;
}
Than you put all cells into single element
<div class="table">
<div class="head">column 1</div>
<div class="head">column 2</div>
<div class="head">column 3</div>
<div>data - column 1 - row 1</div>
<div>data - column 2 - row 1</div>
<div>data - column 3 - row 1</div>
<div>data - column 1 - row 2</div>
<div>data - column 2 - row 2</div>
<div>data - column 3 - row 2</div>
<div>data - column 1 - row 3</div>
<div>data - column 2 - row 3</div>
<div>data - column 3 - row 3</div>
</div>
Now you can see both scrollbars all the time; header scrolls horizontally but not vertically.
Horizontal and vertical scrolling with sticky column headers using css only can be done with the following.
A container div with overflow: scroll
A thead with position: sticky and inset-block-start: 0;
Full example below:
.container {
overflow: scroll;
height: 180px;
width: 300px;
}
table {
border-collapse: collapse;
}
table th,
table td {
max-width: 300px;
padding: 8px 16px;
border: 1px solid #ddd;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
table thead {
position: sticky;
inset-block-start: 0;
background-color: #ddd;
}
<div class="container">
<table>
<thead>
<tr>
<th>Fruits</th>
<th>Nuts</th>
<th>Vegetables</th>
<th>Meats</th>
</tr>
</thead>
<tbody>
<tr>
<td>Apple</td>
<td>Peanut</td>
<td>Carrot</td>
<td>Chicken</td>
</tr>
<tr>
<td>Banana</td>
<td>Pecan</td>
<td>Potato</td>
<td>Pork</td>
</tr>
<tr>
<td>Cherry</td>
<td>Cashew</td>
<td>Tomato</td>
<td>Beef</td>
</tr>
<tr>
<td>Grape</td>
<td>Almond</td>
<td>Cabbage</td>
<td>Lamb</td>
</tr>
<tr>
<td>Kiwi</td>
<td>Brazil Nut</td>
<td>Onion</td>
<td>Chicken</td>
</tr>
<tr>
<td>Lemon</td>
<td>Hazelnut</td>
<td>Cucumber</td>
<td>Fish</td>
</tr>
</tbody>
</table>
</div>