Prevent wrapping in CSS Flexbox - html

I have a re-sizable sidebar using Javascript. The problem is when the size of the sidebar is less than the content's wrapping occurs. (i think because of flex-box).
My grid is based on Rows and Columns kinda like Bootstrap.
.column {
flex-basis: 0;
max-width: 100%;
flex-grow: 1;
}
.row {
display: flex;
flex-wrap: nowrap;
margin: 0 -1rem;
}
What I want to achieve is truncating the content (without shrinking) indicating that there is more.
Here is a fiddle with what i achieved so far.

When it comes to Flexbox, you need to set min-width: 0 or overflow: hidden to every level, down from the child of the element with the width constraint, to the one having ellipsis.
So in this case, from the sidebar's child, and the reason is that a flex item's min-width defaults to auto, which mean it can't be smaller than its content.
To make it easy to follow how I mean, I created a flex-ellipsis class and added it to all elements down that chain.
Note, I also removed the negative margin, margin: 0 -1rem;, from the row class, or else one can't see the ellipsis.
Updated fiddle
Stack snippet
const resizeHandle = document.getElementsByClassName("vertical-resize")[0];
const navbar = document.getElementById('sidebar');
function resizeNavbar(e) {
let size = (e.pageX + 5);
navbar.style.width = (e.pageX + 5) + "px";
}
function removeEvents() {
document.removeEventListener('mousemove', resizeNavbar);
document.removeEventListener('mouseup', resizeNavbar);
}
resizeHandle.addEventListener('mousedown', () => {
document.addEventListener('mousemove', resizeNavbar);
document.addEventListener('mouseup', removeEvents);
});
* {
user-select: none;
color: #dadada;
}
.flex-ellipsis {
min-width: 0; /* added */
/* or overflow: hidden; */
}
p,
h6 {
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
.rounded-circle {
border-radius: 50% !important;
}
.no-margin {
margin: 0 !important;
}
.column {
flex-basis: 0;
max-width: 100%;
flex-grow: 1;
background: #4a4a4a;
}
.column-1 {
flex: 0 0 8.33333%;
max-width: 8.33333%;
}
.row {
display: flex;
flex-wrap: nowrap; /*Even though no-wrap it still wraps as shown in picture.*/
/*margin: 0 -1rem;*/
}
.custom {
margin: auto;
padding: 10px 0px;
flex-wrap: nowrap;
}
.vertical-resize {
position: relative;
right: 0;
top: 0;
cursor: col-resize;
width: 5px;
background: aquamarine;
height: 100vh;
}
<div class="row">
<div id="sidebar" style="width: 570px;">
<div class="align-items-center row custom flex-ellipsis" id="sidebar">
<div style="max-width: 2.5rem;" class="column-1">
<img class="rounded-circle" style="max-width: 28px; min-width: 28px;" alt="Avatar" src="https://d30y9cdsu7xlg0.cloudfront.net/png/138926-200.png">
</div>
<div class="column flex-ellipsis">
<div class="row">
<div class="column">
<p class="no-margin">Ahmed Tarek</p>
</div>
</div>
<div class="row flex-ellipsis">
<div class="column flex-ellipsis">
<h6 style="font-size: 11px;" class="no-margin">01 January, 0001</h6>
</div>
</div>
</div>
</div>
</div>
<div class="vertical-resize"></div>
<div class="column">
</div>
</div>

You need to use text-overflow property along with other properties inside a media query or per your needs.
e.g
.list {
width: 200px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 48px; /* just for test */
}
<div class="list">
this is a ver long list this is a ver long list this is a ver long list.
</div>
Hope this will help you out.

As you have not shared full code with us, it will be difficult for us to provide you working solution. But you can add this css to your code with you want to truncate.
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
This will help you with text truncate with "..."

Related

Images inside a display:flex item partially distorted or cut off

I am currently building a horizontal scroller for an image gallery.
The scroller works so far, but unfortunately the images are partially distorted or part of it is cut off.
I suspect that it has something to do with Flexbox ...
Here you can see the code of the scroll slider (markup + scss)
https://jsfiddle.net/3cdkxbvm/
.scroll-slider-title {
display: flex;
justify-content: center;
flex-direction: column;
align-items: flex-start;
margin-bottom: 0.5em;
font-weight: 700;
}
.scroll-slider-title svg {
margin-right: 1rem;
font-size: 1.5em;
}
.scroll-slider-title a {
color: inherit;
}
.scroll-slider {
width: 100%;
overflow: hidden;
position: relative;
margin-bottom: 4rem;
}
.scroll-slider .scroll-slider-pane {
width: 100%;
overflow: auto;
padding: 2rem 0 3rem;
box-sizing: border-box;
-webkit-overflow-scrolling: touch;
scroll-behavior: smooth;
}
.scroll-slider .scroll-slider-track {
display: inline-block;
padding: 0;
margin: 0;
}
.image-gallery {
display: flex;
}
.image-gallery .image-gallery-item {
margin-right: 1rem;
overflow: hidden;
flex-shrink: 0;
width: auto;
}
.image-gallery .image-gallery-item img {
height: 100%;
width: auto;
}
<div class="scroll-slider" id="js_image_gallery">
<div class="scroll-slider-pane">
<div class="scroll-slider-track">
<div class="image-gallery">
<div class="image-gallery-item">
<img src="https://s1.waazz.com/thumbs/l800/83/1083_af8cbfd999d37bbac86691e9c5ffb76f">
</div>
<div class="image-gallery-item">
<img src="https://s1.waazz.com/thumbs/p800/84/1084_72a6840640a8650cc01f41d55346973c">
</div>
<div class="image-gallery-item">
<img src="https://s1.waazz.com/thumbs/p800/85/1085_5f18260d83ea0790be5a8029b7638872">
</div>
<div class="image-gallery-item">
<img src="https://s1.waazz.com/thumbs/p800/86/1086_66daf815df8570e11564f3426c074f3c">
</div>
</div>
</div>
</div>
</div>
Now the all-important question:
Why are my images partially distorted or part of it is cut off.? And how can I solve this?
It is important that the pictures always have the same height. However, the width may vary depending on the picture.
Here you can find a working fiddle where you can see the problem with the images. I have tested it in the latest Chrome version.
https://jsfiddle.net/3cdkxbvm/
Thanks in advance for your help
You probably need something like this:
HTML
<div class="scroll-slider-track">
<div class="image-gallery">
<div class="image-gallery-item">
<img src="https://s1.waazz.com/thumbs/l800/83/1083_af8cbfd999d37bbac86691e9c5ffb76f">
</div>
<div class="image-gallery-item">
<img src="https://s1.waazz.com/thumbs/p800/84/1084_72a6840640a8650cc01f41d55346973c">
</div>
<div class="image-gallery-item">
<img src="https://s1.waazz.com/thumbs/p800/85/1085_5f18260d83ea0790be5a8029b7638872">
</div>
<div class="image-gallery-item">
<img src="https://s1.waazz.com/thumbs/p800/86/1086_66daf815df8570e11564f3426c074f3c">
</div>
</div>
</div>
SCSS
.scroll-slider-track {
// do not set a height for this container
// because the horizontal scroller also needs
// space and this varies in every browser
width: 800px; // set the width you need
overflow: auto;
}
.image-gallery {
height: 300px; // height of the gallery images, set one you like best
display: flex;
flex-flow: row nowrap;
}
.image-gallery-item {
flex: 0 0 auto; // turn off shrink and grow behavior
// needed, so the img element can calculate its height
// using a value in percent:
height: 100%;
&:not(:first-child) { // addressing all items except the first one
margin-left: 1rem;
}
img {
height: 100%;
width: auto; // this will keep the image ratio intact
flex: 0 0 auto; // turn off shrink and grow behavior
display: block; // making sure, no whitespace or line-height issues occur
}
}
Remove margin-right or add margin-right more than 1rem

IE 10 flex box and text truncate

.wrapper {
background: tomato;
width: 100px;
display: flex;
}
.left {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.right {
}
<div class=wrapper>
<div class="left">
title title title title
</div>
<div class="right">
123
</div>
</div>
I have a DIV (wrapper) with 2 DIVs inside: left and right.
wrapper's width is known. I want to truncate text in left DIV if it doesn't fit. Text in right should be always visible. I tried several techniques here, but the only one is working is based on flex box. Unfortunately it doesn't work on IE10. I used -ms- prefixes, without success.
Is there any way to make it work on IE10?
I can't test this on IE10 myself, though since its -ms-flex defaults to 0 0 auto, you will need to add -ms-flex: 0 1 auto to the left, so it is allowed to shrink.
And as the default on IE11 and the rest of the browsers is 0 1 auto, they work as is.
Fiddle demo
Stack snippet
.wrapper {
background: tomato;
width: 100px;
display: -ms-flexbox; /* IE10 */
display: flex;
}
.left {
-ms-flex: 0 1 auto; /* IE10 */
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.right {
}
<div class=wrapper>
<div class="left">
title title title title
</div>
<div class="right">
123
</div>
</div>
Here is an idea without the use of flexbox but using display:table:
.wrapper {
background: tomato;
width: 100px;
display: table;
}
.left {
display: table-cell;
position: relative;
width: 100%;
}
.left span {
position: absolute;
top:0;
left:0;
width: 100%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.right {
display: table-cell;
}
<div class=wrapper>
<div class="left">
<span>
title title title title title title
</span>
</div>
<div class="right">
123
</div>
</div>

How to fit an image to a flex item with max-height restriction on its ancestor?

I have a reusable component to display two horizontal sections shared with same shape. The two sections are distributed evenly based on there content.
I post the component in https://jsfiddle.net/kezhuw/7pzmgz6c/2/.
I post a modified version in https://jsfiddle.net/kezhuw/7pzmgz6c/3/ with the desired vision, but it set direct restriction max-height on the img tag.
The max-height restriction should be set on component level, served as API.
Some notes:
The two sections in the component has flex: 1 1 auto;, it is a method to achieve "distributed evenly based on there content".
With max height of the component restricted, the title of section two should be the longest horizontal content in this component. Space should be distributed around this. But it is not, due to object-fit: contain;. Without object-fit: contains;, the image fill its parent div wholly. You can see it in https://jsfiddle.net/kezhuw/7pzmgz6c/4/.
HTML:
<-- language: lang-html -->
<div class="device">
<div class="app">
<div class="component">
<div class="section section1">
<div class="logo">
<img class="image" src="https://www.w3schools.com/css/img_lights.jpg" />
</div>
<div class="title">Section One</div>
</div>
<div class="section section2">
<div class="logo">
<img class="image" src="https://www.w3schools.com/css/img_fjords.jpg" />
</div>
<div class="title">Section Two: Another Title Here, Longer than first</div>
</div>
</div>
<div class="another-component">
Another component
</div>
</div>
</div>
CSS:
.device {
width: 600px;
height: 1200px;
}
.app {
display: flex;
flex-flow: column nowrap;
border: thick solid purple;
}
.app > * {
min-height: 0;
}
.component {
/*
* max-height is an API exposed by this component,
* used by client to restrict max height of component.
*
* This API is exposed as raw css style, not an Vue/React prop.
*
* As an Vue/React Prop, it is possible to calculate max-height of image
* from this prop. I think this calculation process is not maintainable and the result
* may not accurate.
*
* Another way to solve this problem is to treat this max-height as the restriction
* of image, not the component. But I think that may not be friend to consumer.
*/
max-height: 120px;
display: flex;
border: thick solid lightseagreen;
}
.component > * {
min-width: 0;
flex: 1 1 auto;
}
.section1 {
background-color: yellow;
}
.section2 {
background-color: green;
}
.section {
display: flex;
flex-flow: column nowrap;
/* Align from bottom to top, to fix title at the bottom,
* even if there is no logo for this section.
*/
justify-content: flex-end;
}
.section > * {
min-height: 0;
text-align: center;
}
.title {
/* Don't shrink title */
flex: 0 0 auto;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.logo {
opacity: 0.5;
display: flex;
flex-flow: column nowrap;
align-items: center;
}
.logo > * {
min-height: 0;
min-width: 0;
}
.image {
max-height: 100%;
max-width: 100%;
object-fit: contain;
/* max-height: 70px; */
}
.another-component {
font-size: 30px;
min-height: 50px;
background-color: darkslateblue;
}

text-overflow ellipsis not working in nested flexbox

I have a two-column layout created with flexboxes.
In the right column, I have two rows, the first containing a header and the second containing the page content.
Within the header I have three columns, a button, some text, and a button.
I want the buttons to sit on the left and right of the column with the text taking up any additional room.
Finally, I want the text to have white-space:nowrap and text-overflow:ellipsis properties to truncate long titles.
My problem is this: I cannot get the text wrapping to work correctly in a flexbox that is nested in another flexbox, as shown in this fiddle:
http://jsfiddle.net/maxmumford/rb4sk3mz/3/
.container {
display: flex;
height: 100vh;
}
.left {
width: 200px;
background-color: yellow;
}
.right {
flex: 1;
background-color: blue;
color: white;
}
.header {
background: red;
color: white;
display: flex;
flex-direction: row;
}
.header .content {
white-space: nowrap;
flex: 0 1 auto;
text-overflow: ellipsis;
overflow: hidden;
min-width: 0;
}
.header .buttons {
background: green;
flex: 1 0 auto;
}
.header .content:hover {
white-space: normal;
}
<div class="container">
<div class="left">
content left
</div>
<div class="right">
<div class="header">
<div class="buttons">buttons</div>
<div class="content">
This content is really long and should wrap with ellipses, but for some reason it doesn't work when it's nested in a container with display: flex
</div>
<div class="buttons">buttons</div>
</div>
content right
</div>
</div>
However, the exact same code works when the header is not nested within a flex box:
http://jsfiddle.net/maxmumford/p7115f2v/1/
.header {
background: red;
color: white;
display: flex;
flex-direction: row;
}
.header .content {
white-space: nowrap;
flex: 0 1 auto;
text-overflow: ellipsis;
overflow: hidden;
min-width: 0;
}
.header .buttons {
background: green;
flex: 1 0 auto;
}
<div class="header">
<div class="buttons">buttons</div>
<div class="content">
This content is really long and is wrapped correctly... This content is really long and is wrapped correctly... This content is really long and is wrapped correctly... This content is really long and is wrapped correctly... This content is really long
and is wrapped correctly... This content is really long and is wrapped correctly... This content is really long and is wrapped correctly...
</div>
<div class="buttons">buttons</div>
</div>
How can I achieve what I want in the first fiddle?
Thanks
There are two issues in your code preventing the ellipsis from working:
div.right contains div.header, which in turn contains the button and text.
div.right is a flex item in the main container (.container).
By default, a flex item cannot be smaller than the size of its content. The initial setting on flex items is min-width: auto.
This means that the length of your text, which is not wrapping, will set a minimum size for parent flex items. One way to enable flex items to shrink past their content is to set a flex item to min-width: 0.
You've done this already for the .content flex item, but it needs to be set on the .right item, as well.
You've got the .content element set to flex: 0 1 auto.
This tells the flex item to use the size of the content (flex-basis: auto). The text sets the size.
Instead, set the width to 0 and let the flex container distribute space, as necessary. You can do this with flex: 1 1 0, which is the same as flex: 1.
.container {
display: flex;
height: 100vh;
}
.left {
width: 200px;
background-color: yellow;
}
.right {
flex: 1;
background-color: blue;
color: white;
min-width: 0; /* NEW */
}
.header {
background: red;
color: white;
display: flex;
flex-direction: row;
}
.header .content {
white-space: nowrap;
flex: 1; /* ADJUSTMENT */
text-overflow: ellipsis;
overflow: hidden;
min-width: 0;
}
.header .buttons {
background: green;
flex: 1 0 auto;
}
.header .content:hover {
white-space: normal;
}
<div class="container">
<div class="left">
content left
</div>
<div class="right">
<div class="header">
<div class="buttons">buttons</div>
<div class="content">
This content is really long and should wrap with ellipses, but for some reason it doesn't work when it's nested in a container with display: flex
</div>
<div class="buttons">buttons</div>
</div>
content right
</div>
</div>
revised fiddle
The values of :
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
Will work only if the content of your element exceeds it's width.
You can set the width of .header .content:
.header .content {
width: 50%;
}
And it will work as you expect it to:
http://jsfiddle.net/t82pqks4/
I hope this solution helps someone as nothing else I found worked because of how my page was a giant nested combination of flexbox. so min-width 0 didn't work, nothing I tried worked except this.
Inside the flex column that has the copy you want to wrap, you need to do this.
.row {
display: flex;
}
.col1 {
position: relative;
flex: 1 1 70%;
overflow: hidden;
}
.nested {
width: 100%;
position: absolute;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.col2 {
flex: 1 1 30%;
padding-left: 1rem;
}
<div class="row">
<div class="col1">
<div class="nested">This is my really long copy that will push it out of the screen, and will not respect the elippse no matter what I do!!!</div>
</div>
<div class="col2">
Last Text
</div>
</div>

tricky css: 3 sections in a row, all 3 can be variable width

check this out
http://jsfiddle.net/38Hmp/
The dom structure is this
<div class="outer">
<div class="left">aaa</div>
<div class="middle">middlemiddlemiddlemiddlemiddlemiddle</div>
<div class="right">bbb</div>
</div>
outer is fixed width,
left and right to be on the left and right, respectively
all three sections contain variable width content.
The middle section should not overflow or push the right section out of the container.
Ideally the middle would have ellipses in the event of overflow.
I can't see how to avoid pushing the right section out in the event of long middle section without a max width, but that kills the variable width of the right section.
How do I resolve this?
Can you use flexbox?
It has the properties you need. Setting the growth property to 0 & shrink property to 1, perhaps?
-webkit-box-flex: 0;
-moz-box-flex: 0;
-webkit-flex: 0 1 auto;
-ms-flex: 0 1 auto;
flex: 0 1 auto;
And maybe you could play with it, here.
Incomplete but it can get you started
html
<div class="outer">
<div class="left">aaa</div>
<div class="inner">
<div class="right">bbb</div>
<div class="middle">middlemiddlemiddlemiddlemiddlemiddle</div>
</div>
</div>
css
.outer {
background-color: yellow;
height: 20px;
width: 200px;
}
.left {
float: left;
display: inline-block;
}
.inner {
float: right;
}
.middle {
float:left;
display: inline-block;
text-overflow: ellipsis;
}
.right {
float: right;
display: inline-block;
}
Ok I found a pure css solution.
http://jsfiddle.net/38Hmp/2/
<div class="outer">
<div class="left">aaa</div>
<div class="right">bbb</div>
<div class="middle">middlemiddlemiddlemiddlemiddlemiddle</div>
</div>
left and right both float (left and right) and middle has no float.
Its key that left and right go into the dom before middle.
css
.outer {
background-color: yellow;
height: 20px;
width: 200px;
}
.left {
float: left;
margin-right: 10px;
}
.middle {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.right {
float: right;
margin-left: 10px;
}