text-overflow: ellipsis and flex - javascript

I have a container element with display: flex property set.
A children have fixed width (flex: 0 0 auto), another one no (flex: 1). The flexible children has some other children: I want this container (inner) to clip its children according to the parent width.
I managed to do this, but also I'd like to get the ellipsis overflow in case the content is clipped (the number of children is not fixed).
This is my code so far:
.outer {
border: 1px solid red;
display: flex;
width: 400px;
}
.inner {
display: flex;
min-width: 0;
overflow: hidden;
flex: 1;
text-overflow: ellipsis;
}
.child {
display: inline-block;
white-space: nowrap;
flex: 1;
border: 1px solid blue;
}
.btn {
border: 1px solid green;
flex: 0 0 auto;
}
Live here: http://jsbin.com/niheyiwiya/edit?html,css,output
How can I get the following desired result? (hacks welcome - css only please!)

There are a few problems with your layout:
text-overflow: ellipsis only works with display: block and display: inline-block containers. It's failing because you have .inner set to display: flex.
text-overflow: ellipsis must include white-space: nowrap in the same declaration. It's missing in your .inner rule.
ellipsis works on text, not block-level elements
Try this:
* {
margin: 15px 1px
}
.outer {
border: 1px solid red;
display: flex;
width: 400px;
}
.inner {
/* display: flex */ /* removed */
min-width: 0;
overflow: hidden;
flex: 1;
text-overflow: ellipsis;
white-space: nowrap; /* new */
}
.child {
display: inline; /* adjusted */
white-space: nowrap;
flex: 1;
}
.btn {
border: 1px solid green;
flex: 0 0 auto;
}
<div class="outer">
<div class="inner">
<div class="child">child 1</div>
<div class="child">child 2</div>
<div class="child">child 3</div>
<div class="child">child 4</div>
<div class="child">child 5</div>
<div class="child">child 6</div>
<div class="child">child 7</div>
</div>
<div class="btn">My big big big button!</div>
</div>
More about text-overflow: ellipsis here: Applying an ellipsis to multiline text

Here is JS approach where you could find which child div have position that overflows with position of button, and hide all divs after that div and append ... after that div.
var child = $('.child');
var btn = $('.btn');
var oW = $('.outer').innerWidth();
var w = btn.outerWidth();
var c = oW - w;
var last;
child.each(function() {
var l = $(this).position().left + $(this).outerWidth();
if (l > c) {
if (last == undefined) last = $(this).index() - 1;
}
})
$('.child:gt(' + last + ')').css('display', 'none');
$('.child:eq(' + last + ')').after(' ...')
* {
margin: 15px 1px
}
.outer {
border: 1px solid red;
display: flex;
width: 400px;
}
.inner {
overflow: hidden;
white-space: nowrap;
flex: 1;
}
.child {
border: 1px solid blue;
display: inline-block;
}
.btn {
border: 1px solid green;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="outer">
<div class="inner">
<div class="child">child 1</div>
<div class="child">child 2</div>
<div class="child">child 3</div>
<div class="child">child 4</div>
<div class="child">child 5</div>
<div class="child">child 6</div>
<div class="child">child 7</div>
</div>
<div class="btn">My big big big button!</div>
</div>

In addition to the previous answer:
if you nest the flex-elements, than you have to add
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
to the parent container otherwise the hiding of the overflow may not work any more.
In some cases you need width: 0; in addition/instead of to min-width: 0;.

A great example with min-width: 0; which just works: https://css-tricks.com/flexbox-truncated-text/
BUT:
If your text to trancate is inside the a-tag, than you have to wrap that a-tag, in e.g. h2 or p. Otherwise the text will not be truncated because of the a-tag!
So here is the working example with the a-tag basing on example above:
.flex-parent {
display: flex;
align-items: center;
}
.long-and-truncated-with-child-corrected {
flex: 1;
min-width: 0;
/* or some value */;
}
.long-and-truncated-with-child-corrected h2 {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.short-and-fixed {
white-space: nowrap;
}
.short-and-fixed > div {
width: 30px;
height: 30px;
border-radius: 10px;
background: lightgreen;
display: inline-block;
}
<div class="flex-parent">
<div class="long-and-truncated-with-child-corrected">
<h2>
333333333333333333333333333333333333333333333333333333333333333333333333333333333333333
</h2>
</div>
<div class="long-and-truncated-with-child-corrected">
<h2>
<a href="https://vgn.de">
44444444444444444444444444444444444444444444444444444444444444444444444444444444444444444
</a>
</h2>
</div>
<div class="short-and-fixed">
<div></div>
<div></div>
<div></div>
</div>
</div>

Related

Block Positon changes after changing innerHTML

I am trying to make a X-O game
so html is this:
const blocks = document.querySelectorAll(".block")
let turn = "X"
for (let i = 0; i < blocks.length; i++) {
blocks[i].addEventListener("click", function () {
if (this.innerHTML == "") {
this.innerHTML = turn
}}
)}
.block {
width: 100px;
height: 100px;
border: 1px solid black;
text-align: center;
line-height: 100px;
font-size: 50px;
font-weight: bold;
cursor: pointer;
padding: 0;
display: inline-block;
}
#game{
max-width: 400px;
max-height: 400px;
}
<div id="game">
<div class="block"></div>
<div class="block"></div>
<div class="block"></div>
<div class="block"></div>
<div class="block"></div>
<div class="block"></div>
<div class="block"></div>
<div class="block"></div>
<div class="block"></div>
</div>
And every thing is OK.
But when I press a block it's position changes a little bit:
I have a slightly different solution using rows and column structure and flex.
Divide the structure into a tabular structure (ex: row, column). Try using display:flex to display the boxes in the same line.
const blocks = document.querySelectorAll(".col");
let turn = "X";
for (let i = 0; i < blocks.length; i++) {
blocks[i].addEventListener("click", function () {
if (this.innerHTML == "") {
this.innerHTML = turn;
}
});
}
.row{
display: flex;
}
.col {
width: 100px;
height: 100px;
border: 1px solid black;
text-align: center;
line-height: 100px;
font-size: 50px;
font-weight: bold;
cursor: pointer;
padding: 0;
}
#game {
max-width: 400px;
max-height: 400px;
}
<div id="game">
<div class="row">
<div class="col"></div>
<div class="col"></div>
<div class="col"></div>
</div>
<div class="row">
<div class="col"></div>
<div class="col"></div>
<div class="col"></div>
</div>
<div class="row">
<div class="col"></div>
<div class="col"></div>
<div class="col"></div>
</div>
</div>
Instead of using inline-block for your blocks, you could use a flex (display: flex) and wrapped (flex-wrap: wrap) container with fixed width and height for your #game div.
Using flex-wrap saves you from manually splitting your rows.
display: flex, by default, set flex-direction to row.
Using flex-wrap: wrap, if the content horizontally exceeds the width of the container, it is wrapped.
In our case, the container has dimention 400px, so we will get 3 element per row (since every block has width: 100px).
As in this runnable example
const blocks = document.querySelectorAll(".block")
let turn = "X"
for (let i = 0; i < blocks.length; i++) {
blocks[i].addEventListener("click", function() {
if (this.innerHTML == "") {
this.innerHTML = turn
}
})
}
#game {
/* Flex Wrapped Container*/
display: flex;
justify-content: start;
align-items: center;
flex-wrap: wrap;
/* Dimensions */
max-width: 400px;
max-height: 400px;
}
.block {
width: 100px;
height: 100px;
border: 1px solid black;
margin: 1px; /* margin for some gap between boxes */
text-align: center;
line-height: 100px;
font-size: 50px;
font-weight: bold;
cursor: pointer;
padding: 0;
display: inline-block;
vertical-align: center;
}
<div id="game">
<div class="block"></div>
<div class="block"></div>
<div class="block"></div>
<div class="block"></div>
<div class="block"></div>
<div class="block"></div>
<div class="block"></div>
<div class="block"></div>
<div class="block"></div>
</div>

Make rows expand to scrollable parent's width

I’m making a table-like layout using flexbox.
It has a body, rows and cells.
Cells have the fixed widths in pixels.
Body should be horizontally scrollable.
I would like to achieve that rows have the same width as cumulative widths of cells.
Here’s the codepen.
<div class="grand-parent">
<div class="parent">
<div class="child">Child 1</div>
<div class="child">Child 2</div>
<div class="child">Child 3</div>
</div>
<div>
Is there any way to do this using CSS only?
P.S. I know I can calculate the widths using JS and set that to parent, or I can set the background color to grand-parent to make it look nicer, but that's not what I need here.
one way is to not fix size on child component but use flex-grow: 1; to let them take all available size
.child {
flex-grow: 1;
color: white;
background: blue;
border: 1px solid black;
}
OR
if you want to force container to take child width you have to :
.child have display: inline-flex;
.parent have width: max-content;
.parent {
background: red;
padding: 2em 0;
width: max-content;
}
.child {
display: inline-flex;
width: 300px;
color: white;
background: blue;
border: 1px solid black;
}
following the running snippet of this reply
.grand-parent {
width: 800px;
overflow: auto;
}
.parent {
display: flex;
background: red;
padding: 2em 0;
}
.child {
flex-grow:1;
color: white;
background: blue;
border: 1px solid black;
}
.parent2 {
background: red;
padding: 2em 0;
width: max-content;
}
.child2 {
display: inline-flex;
width: 300px;
color: white;
background: blue;
border: 1px solid black;
}
::-webkit-scrollbar {
-webkit-appearance: none;
width: 7px;
}
::-webkit-scrollbar-thumb {
border-radius: 4px;
background-color: rgba(0, 0, 0, .5);
box-shadow: 0 0 1px rgba(255, 255, 255, .5);
}
<h1> child take width of parent</h1>
<div class="grand-parent">
<div class="parent">
<div class="child">Child 1</div>
<div class="child">Child 2</div>
<div class="child">Child 3</div>
</div>
<div>
<h1> parent take width of child</h1>
<div class="grand-parent">
<div class="parent2">
<div class="child2">Child 1</div>
<div class="child2">Child 2</div>
<div class="child2">Child 3</div>
</div>
<div class="parent2">
<div class="child2">Child 1</div>
<div class="child2">Child 2</div>
<div class="child2">Child 3</div>
</div>
<div>
Well, just like Jeremy's answer, you can set them to take available space
OR
Instead of making the grand-parent fixed-width, you can set the parent to be of fixed width;
.parent {
display: flex;
background: red;
padding: 2em 0;
width: 800px;
overflow: auto;
}
I took all the styles of grand-parent and added the to the style of parent
The following snippet works perfectly fine:
.parent {
display: flex;
background: red;
padding: 2em 0;
width: 800px;
overflow: auto;
}
.child {
flex: 0 0 300px;
color: white;
background: blue;
border: 1px solid black;
}
<div class="grand-parent">
<div class="parent">
<div class="child">Child 1</div>
<div class="child">Child 2</div>
<div class="child">Child 3</div>
</div>
</div>

Align text in the center by ignoring the absolutely positioned element

I am developing a flex table from scratch and the table supports filtering and sorting. The icons for filters and sorting are displayed in the table header (right corner). Also my table supports that the user can position the header text left/center;
My problem:
Since the icons are inside the table header, icons as well occupies some space. So when i position the elements in the center, i see the alignment gets disturbed as shown below.
body {
width: 100%;
}
.table-header, .table-body {
display: flex;
width: fit-content;
border: 1px solid black;
padding: 10px;
}
.header, .data {
display: flex;
min-width: 150px;
width: 150px;
border-right: 1px solid black;
display: flex;
justify-content: center;
position: relative;
}
.header .text {
width: 100%;
white-space: nowrap;
text-align: center;
overflow: hidden;
text-overflow: ellipsis;
}
.icons {
float: right;
right: 0;
display: flex;
}
<div class="table">
<div class="table-header">
<div class="header">
<div class="text">Hlkjklkjlkjlkj lkjlkjlkjlkjlkjljlkjlkj</div>
<div class="icons">
<span> &#9760</span>
<span> &#9760</span>
</div>
</div>
<div class="header">9747
<div class="text">Header 2</div>
<div class="icons">
<span>b</span>
<span>b</span>
</div>
</div>
<div class="header">
<div class="text">Header 3</div>
<div class="icons">
<span>a</span>
<span>b</span>
</div>
</div>
<div class="header">
<div class="text">Header 4</div>
<div class="icons">
<span>a</span>
<span>b</span>
</div>
</div>
</div>
<div class="table-body">
<div class="data">123</div>
<div class="data">123</div>
<div class="data">123</div>
<div class="data">123</div>
</div>
<div class="table-body">
<div class="data">123</div>
<div class="data">123</div>
<div class="data">123</div>
<div class="data">123</div>
</div><div class="table-body">
<div class="data">123</div>
<div class="data">123</div>
<div class="data">123</div>
<div class="data">123</div>
</div>
</div>
Code: Here
What i tried
So since the icons as well take some space, to avoid this i positioned them absolutely relative to the header. So the alignment problem got solved . But for long headers where ellipsis has to be shown, the ellipsis hides behind the icons as shown below
Code: Here
So what is the solution to this ? I want to maintain the center position by reducing the space occupied by the icons. Is it possible through CSS? Please help. Thanks :)
If you try to do that with absolute positioning you need to know what exact width your icons can take.
Then possible solution is to add padding rule (left/right) into table headers, so CSS code should be like this:
body {
width: 100%;
}
.table-header, .table-body {
display: flex;
width: fit-content;
border: 1px solid black;
padding: 10px;
}
.header, .data {
box-sizing: border-box;
padding: 0 30px;
display: flex;
min-width: 150px;
width: 150px;
border-right: 1px solid black;
display: flex;
justify-content: center;
position: relative;
}
.header .text {
width: 100%;
white-space: nowrap;
text-align: center;
overflow: hidden;
text-overflow: ellipsis;
}
.icons {
position: absolute;
right: 0;
}

List item will go second column automatic and container space will also increase [duplicate]

This question already has answers here:
When flexbox items wrap in column mode, container does not grow its width
(9 answers)
Closed 4 years ago.
I'm trying to build navigation which will be vertical. Navigation's outer width will be fixed and when the item will be increased then other items will go to the next column.
I tried it with flexbox and added flex-wrap: wrap; in the container. But cant design this.
I tried with these codes.
.container {
display: flex;
flex-direction: column;
height: 320px;
width: 80px;
flex-wrap: wrap;
background: red;
padding: 10px
}
.item {
padding: 20px 30px;
background: #efefef;
display: inline-block;
margin: 0 5px 5px 0;
width: 20px
}
<div class="container">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
<div class="item">4</div>
<div class="item">5</div>
<div class="item">6</div>
<div class="item">7</div>
</div>
Instead of width: 80px; give width: auto or do not provide width at all. When the number of items increases touches to the bottom of the container it will be added to the next column.
You do not have control over the container with here. You should make it flexible with auto width.
Learn more here.
.container {
display: flex;
flex-direction: column;
height: 320px;
flex-wrap: wrap;
background: red;
padding: 10px;
width: auto;
}
.item {
padding: 20px 30px;
background: #efefef;
display: block;
margin: 0 5px 5px 0;
width: 20px;
}
<div class="container">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
<div class="item">4</div>
<div class="item">5</div>
<div class="item">6</div>
<div class="item">7</div>
<div class="item">8</div>
</div>

white spacing between my columns can't overwrite it using css and can't see the css on it showing space

I have a set of columns with some sliding i am doing between them but then when i arranged them to look like how in my fiddle i found a space between each of them
This is my fiddle, how I can get rid of this spacing to make them attached to each others?
$(document).ready(function() {
jQuery("#switcher1").click(function() {
jQuery(".middle-wrap").animate({left: "0px"});
});
jQuery("#switcher2").click(function() {
jQuery(".middle-wrap").animate({left: "-198.4px"});
});
jQuery("#switcher3").click(function() {
jQuery(".middle-wrap").animate({left: "-396.8px"});
});
jQuery("#switcher4").click(function() {
jQuery(".middle-wrap").animate({left: "-595.2px"});
});
jQuery("#switcher5").click(function() {
jQuery(".middle-wrap").animate({left: "-793.6px"});
});
jQuery("#switcher6").click(function() {
jQuery(".middle-wrap").animate({left: "-992px"});
});
jQuery("#switcher7").click(function() {
jQuery(".middle-wrap").animate({left: "-1190.4px"});
});
jQuery("#switcher8").click(function() {
jQuery(".middle-wrap").animate({left: "-1388.8px"});
});
});
.outer-wrap {
overflow-x: hidden;
position: relative;
max-width: 1050px;
min-width: 1050px;
margin: 0;
padding: 0;
height: 450px;
background-color: #fff;
-webkit-border-radius: 5px;
border-radius: 5px;
border: 1px solid #e3e3e3;
display: inline-block;
background-color: #fff;
border-top: 1px solid #e3e3e3;
transition: all 50ms ease-in-out;
}
.middle-wrap {
position: relative;
max-width: 1890px;
left: 0px;
margin: 0;
padding: 0;
height: 450px;
min-width: 1890px;
}
.inner-wrap {
display: inline-block;
max-width: 210px;
min-width: 210px;
border-right: 1px solid #e3e3e3;
vertical-align: top;
border: none;
margin: 0;
padding: 0;
height: 100%;
/* float: left;*/
}
.year_list {
background-color: darksalmon;
}
.make_list {
background-color: red;
}
.model_list {
background-color: aquamarine;
}
.body_style {
background-color: blue;
}
.transmission {
background-color:darkviolet;
}
.options {
background-color: darkslategray;
}
.aftermarket_modifications {
background-color: darkseagreen;
}
.mileage {
background-color: darkred;
}
.license_plate {
background-color: darkorange;
}
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.2/jquery.min.js"></script>
<div id="switcher1">See Part 1</div>
<div id="switcher2">See Part 2</div>
<div id="switcher3">See Part 3</div>
<div id="switcher4">See Part 4</div>
<div id="switcher5">See Part 5</div>
<div id="switcher6">See Part 6</div>
<div id="switcher7">See Part 7</div>
<div id="switcher8">See Part 8</div>
<div class="outer-wrap">
<div class="middle-wrap">
<div class="inner-wrap year_list"></div>
<div class="inner-wrap make_list"></div>
<div class="inner-wrap model_list"></div>
<div class="inner-wrap body_style"></div>
<div class="inner-wrap transmission"></div>
<div class="inner-wrap options"></div>
<div class="inner-wrap aftermarket_modifications"></div>
<div class="inner-wrap mileage"></div>
</div>
</div>
Due to your display: inline-blocks, the white spaces appear in between your block elements.
There are many resolutions to the same, refer to David Walsh's blog
What I would prefer to do here is use float instead of display: inline-block.
Check updated fiddle: https://jsfiddle.net/b6fw4u0z/2/
Uncomment float: left in .inner-wrap styling
jsfiddle
If you have to use display: inline-block then to remove the white space between elements, you can set
font-size: 0
to them.
See updated fiddle:
https://jsfiddle.net/b6fw4u0z/3/
You will notice i just put it on all the nested divs.

Categories