Showing ellipsis in CSS table-cell element - css

I have a 100% width table containing several cells. I want one of this cells to always show its contents in one line white-space: nowrap and to display an ellipsis at the end of the line if the contents exceed the table cell text-overflow: ellipsis.
The problem i have is that the table will stop contracting it's with when reaching the cells content. So the minium width of the cell will allways be the width of its content instead the table will be pushed out as a whole.
I just can't figure out how to solve this:
My HTML:
<div class="otrCompactView">
<div class="otrLastEditTable">
<div class="otrLastEditRow">
<div class="otrLastEditor">LastEditor</div>
<div class="otrLastEdited">LastModified</div>
</div>
</div>
<div class="otrTitleRow otrRow">
<div class="otrTitle">Title asdasdasdas asd asd asd asdas as asd </div>
</div>
<div vlass="otrTaskRow otrRow">
</div>
<div class="otrColumnsRow otrRow">
<div class="otrColumns"></div>
</div>
</div>
My CSS:
.otrCompactView {
display: table;
background: yellow;
width: 100%;
height: 100%;
}
.otrRow {
display: table-row;
}
.otrLastEditTable {
display: table;
width: 100%;
}
.otrLastEditRow {
display: table-row;
}
.otrLastEditor {
display: table-cell;
}
.otrLastEdited {
display: table-cell;
text-align: right;
}
.otrTitle {
border: 1px dotted red;
min-width: 50px;
white-space: nowrap;
}
And a fiddle for direct testing:
http://jsfiddle.net/67B6G/

Does this look like what you're after?
updated
HTML
<div class='table'>
<div class='row'>
<div class='cell'>Something quite long</div>
</div>
<div class='row'>
<div class='cell'>
here is some moreSomething quite long that should exceed the table cell.Something quite long that should exceed the table cell.
</div>
</div>
</div>
CSS
.table{
margin:0;
padding:0;
display:table;
table-layout: fixed;
width:100%;
max-width:100%;
}
.row{
display:table-row;
}
.cell{
display:table-cell;
border:1px solid grey;
}
.cell:last-child{
white-space: nowrap;
overflow:hidden;
text-overflow: ellipsis;
}

Here's a way to do it without using table-layout: fixed that allows you to keep dynamic widths with jQuery.
HTML:
<div class="table">
<div class="left">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</div>
<div class="right">Lorem Ipsum</div>
</div>
In the CSS, you use your standard ellipsis code but add max-width: 0 (as explained here with respect to actual table elements):
.table {
display: table;
width: 100%;
}
.left, .right {
display: table-cell;
padding: 0 5px 0 5px;
max-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
If you stopped there, you'd end up with each child div taking up 50% of the total width of the parent div, so you still wouldn't have fit-to-content dynamic widths. To remedy this, I adapted this code, which calculates the width of the text in an element, to calculate the width and then use that to dynamically set the width of the right column. The left column will then have the ellipsis.
// Calculate width of text from DOM element or string. By Phil Freo <http://philfreo.com>
$.fn.textWidth = function(text, font) {
if (!$.fn.textWidth.fakeEl) $.fn.textWidth.fakeEl = $('<span>').hide().appendTo(document.body);
$.fn.textWidth.fakeEl.text(text || this.val() || this.text()).css('font', font || this.css('font'));
return $.fn.textWidth.fakeEl.width();
};
$('.right').on('input', function() {
var $width = $(this).textWidth(); // Get width of text
$width += 10; // Add left and right padding
$(this).width($width); // Set width
}).trigger('input');
Note that the above code requires you to take padding into account; otherwise, the right column will have an ellipsis as well. Here's a fiddle.
To use this in a table with multiple rows, you could modify the jQuery iterate over the cells in a column and set the width of the column to the requisite width of the widest cell in the column. Or, if you know which one is the widest, you can just direct the jQuery to get the width of that.

Related

Using calc() with a dynamic value?

I am wondering if this is possible: I have a header that can contain a variable amount of text. Below that I have another element which I want to take up the remaining height of the page.
<div class="header row">
<div class="title column large-5">Potentially very long text</div>
<div class="menu column large-7">Menu items</div>
</div>
<div class="content">
</div>
<div class="footer">
</div>
Normally I would do this using calc, eg:
.content {
height: calc(100vh - 75px);
}
Where 75px is the set height of .header.
But in this example, the .header element is dynamic and does not have a set height. Only a padding and font-size are set.
To complicate things, this also uses the Foundation Grid layout, which makes me nervous about using display: table (.title and .menu sit side by side on desktop, but stacked on mobile) .
Is there anyway to get the height of the dynamic header element (without resorting to JQuery)?
You can use flexbox and set .content to flex-grow: 1 so that it will fill to grow the available space.
body {
display: flex;
flex-direction: column;
min-height: 100vh;
margin: 0;
}
.content {
flex-grow: 1;
background: #eee;
}
<div class="header row">
<div class="title column large-5">Potentially very long text</div>
<div class="menu column large-7">Menu items</div>
</div>
<div class="content">
</div>
<div class="footer">
</div>
I made a small pen to show the way to do this using flex box, it involved changing your markup a bit:
css:
.container {
display: flex;
flex-direction: column;
height: 250px; // whatever you want here
}
.header {
width: 100%;
background: red;
padding: 10px;
}
.content {
background: yellow;
width: 100%;
flex-grow: 1;
}
So the content will always take the available space inside the content div.
check the whole pen: http://codepen.io/anshul119/pen/yMYeLa
hope this helps.

How to make text wrap before inner floating elements inside a container

How to make text wrap before inner floating elements inside a container?
Here is what I'm trying to do...
http://codepen.io/W3Max/pen/tKwqz
<div>
<div style="height:100px;width:300px;background-color:blue;float:left;"></div>
<div style="height:100px;float:left;word-wrap: break-word;background-color:green;">sdffds dgsdfgsdg sdfgsdfg sdfgsdfg ijhjkhkh lkjlk</div>
<div style="height:100px;width:300px;background-color:red;float:left;"></div>
</div>
I would like the text inside the green div (in the middle) to wrap before the row wraps when I resize the screen.
I would prefer to to support IE9. Is it possible without flexbox?
display:table is compatible with IE8+ and can achieve what you're looking for:
Forked pen.
.container {
display: table;
width: 100%;
/* if you don't want 100% width, set a max-width too */
word-wrap: break-word;
}
.container > div {
display: table-cell;
height: 100px;
}
.container > div:first-child, .container > div:last-child {
width: 300px;
}
<div class="container">
<div style="background-color:blue;"></div>
<div style="background-color:green;">Lorem ipsum dolor sit amet, consectetur adipisicing elit.</div>
<div style="background-color:red;"></div>
</div>
HTML
<div id="green">sdffds dgsdfgsdg sdfgsdfg sdfgsdfg ijhjkhkh lkjlk<div>
CSS
#green {padding:10px} (resize it) on green div .

Make div of text only able to be as wide as its container

HTML
<div class="cont">
<div class="size" id="size1"></div>
<div class="text">Here is some textHere is some text Here is some text</div>
</div>
<div class="cont">
<div class="size" id="size2"></div>
<div class="text">Here is some textHere is some text Here is some text</div>
</div>​
CSS
.size {
background-color: red;
height: 100px;
width: 100px;
}
#size2 {
width: 200px;
}
.cont {
padding: 10px;
float: left;
}​
I need div.cont's widths to be the width of their contained div.size (in my actual example div.size is an image and its with will vary in each instance).
This isnt happening as div.text takes up more space than its container, how can I stop this and make the text wrap?
JS Fiddle
Deleted all the previous stuff as I have (after doing some digging) found an exact duplicate with working solution.
My answer was also incorrect (as the op then specified the image MUST be allowed to be variable)
The answer is found on this jsfiddle and is an exact duplicate of css - shrink a parent div to fit one child's width and constrain the width of the other child
//html
<div id="container">
<div id="child1"><img src="//www.google.com/logos/2012/Teachers_Day_Alt-2012-hp.jpg" width="300" height="116"></div>
<div id="child2">Lorem ipsum dolor sit amet.</div>
</div>
<br/>
<a id="longtext" href="#">lengthen/shorten text</a>
//css
#container{border:1px solid #f00;display:inline-block;margin:10px; display: table;}
#child1{border:1px solid #0f0;margin:10px; display: table-row; width: 1px;}
#child2{border:1px solid #00f;margin:10px; display: table-cell; width: 1px;}
img {border:1px solid #000;}
and basically it works using display:table-* (have a good read up)
'.size{ float:left;}'
let me know if this helps.
Expanding on Paul Sullivan's approach,
in your css:
.size {
...
display:block; /*assuming its an image - making sure its block level*/
...
}
.cont {
...
position:relative; /*add this to parent container if comming from cms*/
...
}
.text {
...
position:absolute;
top:100%; /*just to make sure content doesnt overlaps image*/
...
}
Just gives a plus point for getting content to stretch as wide as the image (plus padding)
Hope it helps,
Fiddle: http://jsfiddle.net/BKRsT/3/

table-cell - some kind of colspan?

I am a bit puzzled right now, because I had CSS code that worked, but it wasn't beautiful at all. I now want to rework this CSS styles and build them via LESS. And I have big problems with display:table; / display:table-row; and display:table-cell;.
For example I have the following code: http://jsfiddle.net/La3kd/2/
How can I do it that the last cell (center) does not shift the above second cell to the right? The last cell should have the width of the 2 cells above. Some kind of colspan is needed. It is so weird, because I have the impression that it worked before I reworked the code. But now all elements to the right are totally shifted.
CSS has no colspan analog. Based on your example, you can just mark up your last row as a separate nontably block.
You could also use display: table-caption in conjunction with caption-side: bottom to display the table row as a last “row” that spans all columns. See live demo.
One idea would be to leverage absolute positioning. Relative position a wrapper around the table, then all absolute positioning becomes coordinate centric to the wrapper. See below. Notice I define a class of tableWrapper which will be set position:relative, then define class of tableRow and - I'm assuming you'll set .tableRow div { display: table-cell; } so I didn't bother putting a class on each div. You'll have to find a way to prevent it from overlapping the div below it if it's height gets larger than the 2nd div. Should be very doable.
<div class="tableWrapper">
<div class="tableRow">
<div>Column 1</div>
<div>Column 2</div>
</div>
<div class="tableRow">
<div style="border: 1px solid black; position: absolute; width: 100%;">appears like colspan=2</div>
<div> (only here to force a row break before the next table row)</div>
</div>
<div class="tableRow">
<div>Column 1</div>
<div>Column 2</div>
</div>
</div>
Use a real table when you are forced to do so to get the layout you want.
The ONLY necessary reason to not use a table for layout is that a speaking browser for the blind gives the row number and column number coordinates of each table cell. This confuses the blind reader when table cells are used for layout.
Of course, it is much easier to use margins, borders, and padding where they do the job much better than faking them with tables, but when you have something with a layout similar to a newspaper want-ad page, it is better to use a real table, a set of nested tables, or a table full of divs.
I will always use div or div faking a table with display table parts when they work.
When they do not work, or when the div layout falls apart at different screen resolutions, I will use a real table. It never falls apart.
This kludgery by the W3C would have had a better solution with a CSS code to tell the speaking browser to not treat a real table as a table.
I also treat a table of comments arranged around the page title as tabular data, even though it is not numeric. Tabular data can include categorical data.
One idea is to hide (with same foreground and background colors) a disclaimer telling the blind person to ignore the table coordinates the speaking browser provides because the use of a table was forced by the lack of ability to make the layout work with divs.
Depending on your needs, flexbox layout may accomplish what you are looking for.
div.table{
display:block;
width:100%;
}
div.table >div{
display:flex;
width:100%;
border:1px solid gray;
flex-direction:horizonal;
}
div.table > div >div{
display: block;
flex-grow:1;
border-bottom:1px solid #ddd;
vertical-align: middle;
height:30px;
padding:4px;
}
See demo:
http://jsbin.com/mimegodiba/edit?html,css,output
When I needed colspan I used "display: grid" instead, and defined the columns using grid-template-areas.
There's a brilliant example here: https://css-tricks.com/snippets/css/complete-guide-grid/ (look for grid-template-areas)
The table-caption is a good idea if you need header and footer row regardless of columns width...
The absolute positioning works great except when your text is line-feeding at least once more than other cells in that row...
So here's a pseudo solution to have header in between rows of a responsive table and be sure to have line-feed according to the table header content (which is important if the table is populated dynamically). I've also included a sort of colspan as well (although not line-feeding accurately) :
CSS :
.table
{ display:table;
position:relative;
}
.table > .header
{ display:table-caption;
position:absolute;
left:0;
right:0;
}
.table > .l50{right:50%;}
.table > .r50{left:50%;}
.table > .row{display:table-row;}
.table > .row > *{display:table-cell;}
/* We add an extra cell where neededed to allow or header repositioning using % instead of fixed units */
.table > .header + .row > :last-child
{ width:1%;
max-width:1px;
overflow:hidden;
visibility:hidden;
}
.table > .header + .row > :last-child > div
{ float:left;
display:inline;
visibility:hidden;
width:10000%;/* 100% = parent element width (1%) ⇒ 100*100% = gran-parent element width*/
}
.table > .header + .row > :last-child > div > .l50
.table > .header + .row > :last-child > div > .r50{width:5000%;}
/* No responsive line-feed thought it's possible using % to estimate the size the span should take but it's not accurate (see HTML render) */
.table > .row > div > .span{position:absolute;left:0;right:33%;}
/* THIS MAKES SURE TRADITIONAL CELLS ARE VISIBLE */
.table > .row > .top
{ position:relative;
z-index:1;
}
http://jsfiddle.net/sp2U4/
I found a solution using jquery and table-layout: fixed. Here is my fiddle: http://jsfiddle.net/emilianolch/5nvxv5ko/
HTML:
<div class="table">
<div class="table-row">
<div class="table-cell">
top left cell
</div>
<div class="table-cell">
top right cell
</div>
</div>
<div class="table-row">
<div class="table-cell colspan">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
</div>
</div>
<div class="table-row">
<div class="table-cell">
bottom left cell
</div>
<div class="table-cell">
bottom right cell
</div>
</div>
</div>
CSS:
.table {
display: table;
table-layout: fixed;
width: 100%;
border-collapse: collapse;
}
.table-row {
display: table-row;
border-collapse: collapse;
}
.table-cell {
display: table-cell;
padding: 5px;
border: 1px solid black;
}
.table-cell.colspan {
display: none;
/* collapse border */
margin-top: -1px;
margin-bottom: -1px;
}
JS:
var rowWidth = $('.table-row:first').width();
var colWidth = $('.table-cell:first').width();
var marginRight = colWidth - rowWidth + 11;
$('.table-cell.colspan').css('margin-right', marginRight + 'px').show()
I could achieve the col-span with the table-row-group
div {
border: solid 1px;
min-width: 10px;
min-height: 10px;
}
.table-head {
display: table-row;
}
.table-row {
display: table-row;
}
.table-cell {
display: table-cell;
}
.table-row-group {
display: table-row-group;
}
.table-cell-group {
display: table-row;
}
<div style="display: table;">
<div class="table-head">
<div class="table-cell">h1</div>
<div class="table-cell">h2</div>
</div>
<div class="table-row">
<div class="table-cell">c1</div>
<div class="table-cell">c2</div>
</div>
<div class="table-row-group">
<div class="table-cell-group">
cc
</div>
</div>
<div class="table-row">
<div class="table-cell">c1</div>
<div class="table-cell">c2</div>
</div>
<div class="table-row">
<div class="table-cell">c1</div>
<div class="table-cell"></div>
</div>
</div>
CSS3 has a column-span attribute. But please try to use flexbox or css grid for layout.

How to make an inline-block element fill the remainder of the line?

Is such a thing possible using CSS and two inline-block (or whatever) DIV tags instead of using a table?
The table version is this (borders added so you can see it):
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head></head>
<body>
<table style="width:100%;">
<tr>
<td style="border:1px solid black;width:100px;height:10px;"></td>
<td style="border:1px solid black;height:10px;"></td>
</tr>
</table>
</body>
</html>
It produces a left column with a FIXED WIDTH (not a percentage width), and a right column that expands to fill THE REMAINING SPACE on the line. Sounds pretty simple, right? Furthermore, since nothing is "floated", the parent container's height properly expands to encompass the height of the content.
--BEGIN RANT--
I've seen the "clear fix" and "holy grail" implementations for multi-column layouts with fixed-width side column, and they suck and they're complicated. They reverse the order of elements, they use percentage widths, or they use floats, negative margins, and the relationship between the "left", "right", and "margin" attributes are complex. Furthermore, the layouts are sub-pixel sensitive so that adding even a single pixel of borders, padding, or margins will break the whole layout, and send entire columns wrapping to the next line. For example, rounding errors are a problem even if you try to do something simple, like put 4 elements on a line, with each one's width set to 25%.
--END RANT--
I've tried using "inline-block" and "white-space:nowrap;", but the problem is I just can't get the 2nd element to fill the remaining space on the line. Setting the width to something like "width:100%-(LeftColumWidth)px" will work in some cases, but performing a calculation in a width property is not really supported.
See: http://jsfiddle.net/qx32C/36/
.lineContainer {
overflow: hidden; /* clear the float */
border: 1px solid #000
}
.lineContainer div {
height: 20px
}
.left {
width: 100px;
float: left;
border-right: 1px solid #000
}
.right {
overflow: hidden;
background: #ccc
}
<div class="lineContainer">
<div class="left">left</div>
<div class="right">right</div>
</div>
Why did I replace margin-left: 100px with overflow: hidden on .right?
A modern solution using flexbox:
.container {
display: flex;
}
.container > div {
border: 1px solid black;
height: 10px;
}
.left {
width: 100px;
}
.right {
width: 100%;
background-color:#ddd;
}
<div class="container">
<div class="left"></div>
<div class="right"></div>
</div>
http://jsfiddle.net/m5Xz2/100/
Compatible with common modern browers (IE 8+): http://jsfiddle.net/m5Xz2/3/
.lineContainer {
display:table;
border-collapse:collapse;
width:100%;
}
.lineContainer div {
display:table-cell;
border:1px solid black;
height:10px;
}
.left {
width:100px;
}
<div class="lineContainer">
<div class="left">left</div>
<div class="right">right</div>
</div>
You can use calc (100% - 100px) on the fluid element, along with display:inline-block for both elements.
Be aware that there should not be any space between the tags, otherwise you will have to consider that space in your calc too.
.left{
display:inline-block;
width:100px;
}
.right{
display:inline-block;
width:calc(100% - 100px);
}
<div class=“left”></div><div class=“right”></div>
Quick example: http://jsfiddle.net/dw689mt4/1/
I've used flex-grow property to achieve this goal. You'll have to set display: flex for parent container, then you need to set flex-grow: 1 for the block you want to fill remaining space, or just flex: 1 as tanius mentioned in the comments.
If you can't use overflow: hidden (because you don't want overflow: hidden) or if you dislike CSS hacks/workarounds, you could use JavaScript instead. Note that it may not work as well because it's JavaScript.
var parent = document.getElementsByClassName("lineContainer")[0];
var left = document.getElementsByClassName("left")[0];
var right = document.getElementsByClassName("right")[0];
right.style.width = (parent.offsetWidth - left.offsetWidth) + "px";
window.onresize = function() {
right.style.width = (parent.offsetWidth - left.offsetWidth) + "px";
}
.lineContainer {
width: 100% border: 1px solid #000;
font-size: 0px;
/* You need to do this because inline block puts an invisible space between them and they won't fit on the same line */
}
.lineContainer div {
height: 10px;
display: inline-block;
}
.left {
width: 100px;
background: red
}
.right {
background: blue
}
<div class="lineContainer">
<div class="left"></div>
<div class="right"></div>
</div>
http://jsfiddle.net/ys2eogxm/
When you give up the inline blocks
.post-container {
border: 5px solid #333;
overflow:auto;
}
.post-thumb {
float: left;
display:block;
background:#ccc;
width:200px;
height:200px;
}
.post-content{
display:block;
overflow:hidden;
}
http://jsfiddle.net/RXrvZ/3731/
(from CSS Float: Floating an image to the left of the text)
If, like me, you want something that will expand to the end of the line even if the left-hand box wraps, then JavaScript is the only option.
I'd make use of the calc feature to get this right:
Array.from(document.querySelectorAll(".right")).forEach((el) => {
el.style.width = `calc(100% - ${el.offsetLeft + 1}px)`;
});
.container {
outline: 1px solid black;
}
.left {
outline: 1px solid red;
}
.right {
outline: 1px solid green;
}
<div class="container">
<span class="left">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin tristique aliquet quam, at commodo lorem fringilla quis.</span>
<input class="right" type="text" />
</div>
A solution using grid layout and fractional units (fr):
/* For debugging and visibility */
html, body {
border: 2px solid navy;
}
.grid-layout {
border: thick solid sandybrown;
background-color: gray;
}
.grid-layout div:nth-child(odd) {
border: 2px solid brown;
background-color: azure;
}
.grid-layout div:nth-child(even) {
border: 2px solid red;
background-color: lightyellow;
}
/* Grid layout.
* Horizontal and vertical gaps.
* two columns, fixed and responsive.
* Note no containing div per line.
*/
.grid-layout {
display: grid;
gap: 4px 2px ;
grid-template-columns: 100px 1fr;
}
<p>How to make an element fill the remainder of the line?</p>
<p>Note no encompassing div per line.</p>
<div class="grid-layout">
<div>Lorem ipsum line 1</div>
<div>Lorem ipsum dolor sit amet,
consectetur adipiscing elit,
sed do eiusmod tempor incididunt ut labore
et dolore magna aliqua.</div>
<div>Lorem ipsum line 2</div>
<div>Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris
nisi ut aliquip ex ea commodo consequat.</div>
</div>
A similar solution with encompassing divs:
.lineContainer {
display: grid;
gap: 2px 4px;
grid-template-columns: 100px 1fr;
}
<p>Display grid per line.</p>
<div class="lineContainer">
<div style="border:1px solid black; ">
Lorem ipsum …
</div>
<div style="border:1px solid black; ">
Lorem ipsum dolor sit amet,
consectetur adipiscing elit,
sed do eiusmod tempor incididunt ut labore
et dolore magna aliqua.
</div>
</div>

Resources