A very short prehistory
My story begins with struggling to make overflow-wrap: break-word; working inside a flexbox. Flexbox container didn't want to understand that its item can be shrunk despite the fact that the item can break long words:
.body {
width: 300px;
border: 1px solid black;
padding: 8px;
background-color: #ccc;
}
.flex-column {
display: flex;
}
.item {
overflow-wrap: break-word;
background-color: #fff;
padding: 8px;
}
<div class="body">
<div class="flex-column">
<div class="item">
This is Spaaaaaaaaaaaaaaaarrrrrrrrrrrrrttttttttttttttaaaaaaaaaaaaaaaaaaaaaa!11 It's not a bug. Firefox is correctly implementing min-width: auto for flex items. When you change it to min-width: 0, you're just using a different value for min-width to get your example looking how you want it to look. But both values are being rendered correctly.
</div>
</div>
</div>
Fortunately, we can help flexbox to understand that it can shrink its item using min-width: 0; on the item:
.body {
width: 300px;
border: 1px solid black;
padding: 8px;
background-color: #ccc;
}
.flex-column {
display: flex;
}
.item {
overflow-wrap: break-word;
background-color: #fff;
padding: 8px;
/* Okay, it fixes this */
min-width: 0;
}
<div class="body">
<div class="flex-column">
<div class="item">
This is Spaaaaaaaaaaaaaaaarrrrrrrrrrrrrttttttttttttttaaaaaaaaaaaaaaaaaaaaaa!11 It's not a bug. Firefox is correctly implementing min-width: auto for flex items. When you change it to min-width: 0, you're just using a different value for min-width to get your example looking how you want it to look. But both values are being rendered correctly.
</div>
</div>
</div>
However, the real world is a little bit more complicated.
The problem
In our application, we have many nested flexboxes. So the example should look like this:
.body {
width: 300px;
border: 1px solid black;
padding: 8px;
background-color: #ccc;
}
.flex {
display: flex;
}
.flex-column {
display: flex;
}
.item {
min-width: 0;
padding: 8px;
background-color: #fff;
overflow-wrap: break-word;
}
<div class="body">
<div class="flex">
<div class="flex">
<div class="flex">
<div class="flex-column">
<div class="item">
This is Spaaaaaaaaaaaaaaaarrrrrrrrrrrrrttttttttttttttaaaaaaaaaaaaaaaaaaaaaa!11 It's not a bug. Firefox is correctly implementing min-width: auto for flex items. When you change it to min-width: 0, you're just using a different value for min-width to get your example looking how you want it to look. But both values are being rendered correctly.
</div>
</div>
</div>
</div>
</div>
</div>
</div>
As you may see, the flex container of our flex-column ignores the fact that its children can shrink very well. I do not understand why is it behaves that way. Could you explain this to me? Why is the flexbox-container doesn't respect its child flexbox min-width: 0?
The solution that I've found is to set min-width: 0 to all flexboxes in the hierarchy which looks very hacky and dangerous because I can break our application layout in unexpected places.
To understand this, simply add border with different colors to your items and you will see that you have overflow at different levels. More precesily, we have only one overflow that is moving to a lower lever after adding each min-width.
.body {
width: 300px;
border: 1px solid black;
padding: 8px;
background-color: #ccc;
}
.flex {
display: flex;
}
.flex-column {
display: flex;
}
.item {
padding: 8px;
background-color: #fff;
overflow-wrap: break-word;
}
<div class="body">
<div class="flex" style="border:5px solid red;">
<div class="flex" style="border:5px solid green;">
<div class="flex" style="border:5px solid blue;">
<div class="flex-column" style="border:5px solid yellow;">
<div class="item" style="border:5px solid pink;">
This is Spaaaaaaaaaaaaaaaarrrrrrrrrrrrrttttttttttttttaaaaaaaaaaaaaaaaaaaaaa!11 It's not a bug. Firefox is correctly implementing min-width: auto for flex items. When you change it to min-width: 0, you're just using a different value for min-width to get
your example looking how you want it to look. But both values are being rendered correctly.
</div>
</div>
</div>
</div>
</div>
</div>
Every min-width will fix one overflow, allow the element to shrink and move the overflow to next level. That's why you need a cascading min-width.
Adding one:
.body {
width: 300px;
border: 1px solid black;
padding: 8px;
background-color: #ccc;
}
.flex {
display: flex;
}
.flex-column {
display: flex;
}
.item {
padding: 8px;
background-color: #fff;
overflow-wrap: break-word;
}
<div class="body">
<div class="flex" style="border:5px solid red;">
<!-- adding min-width at this level -->
<div class="flex" style="border:5px solid green;min-width:0;">
<div class="flex" style="border:5px solid blue;">
<div class="flex-column" style="border:5px solid yellow;">
<div class="item" style="border:5px solid pink;">
This is Spaaaaaaaaaaaaaaaarrrrrrrrrrrrrttttttttttttttaaaaaaaaaaaaaaaaaaaaaa!11 It's not a bug. Firefox is correctly implementing min-width: auto for flex items. When you change it to min-width: 0, you're just using a different value for min-width to get your example looking how you want it to look. But both values are being rendered correctly.
</div>
</div>
</div>
</div>
</div>
</div>
</div>
Adding another:
.body {
width: 300px;
border: 1px solid black;
padding: 8px;
background-color: #ccc;
}
.flex {
display: flex;
}
.flex-column {
display: flex;
}
.item {
padding: 8px;
background-color: #fff;
overflow-wrap: break-word;
}
<div class="body">
<div class="flex" style="border:5px solid red;">
<div class="flex" style="border:5px solid green;min-width:0;">
<!-- adding min-width at this level -->
<div class="flex" style="border:5px solid blue;min-width:0">
<div class="flex-column" style="border:5px solid yellow;">
<div class="item" style="border:5px solid pink;">
This is Spaaaaaaaaaaaaaaaarrrrrrrrrrrrrttttttttttttttaaaaaaaaaaaaaaaaaaaaaa!11 It's not a bug. Firefox is correctly implementing min-width: auto for flex items. When you change it to min-width: 0, you're just using a different value for min-width to get
your example looking how you want it to look. But both values are being rendered correctly.
</div>
</div>
</div>
</div>
</div>
</div>
Again:
.body {
width: 300px;
border: 1px solid black;
padding: 8px;
background-color: #ccc;
}
.flex {
display: flex;
}
.flex-column {
display: flex;
}
.item {
padding: 8px;
background-color: #fff;
overflow-wrap: break-word;
}
<div class="body">
<div class="flex" style="border:5px solid red;">
<div class="flex" style="border:5px solid green;min-width:0;">
<div class="flex" style="border:5px solid blue;min-width:0">
<!-- adding min-width at this level -->
<div class="flex-column" style="border:5px solid yellow;min-width:0;">
<div class="item" style="border:5px solid pink;">
This is Spaaaaaaaaaaaaaaaarrrrrrrrrrrrrttttttttttttttaaaaaaaaaaaaaaaaaaaaaa!11 It's not a bug. Firefox is correctly implementing min-width: auto for flex items. When you change it to min-width: 0, you're just using a different value for min-width to get
your example looking how you want it to look. But both values are being rendered correctly.
</div>
</div>
</div>
</div>
</div>
</div>
The last one:
.body {
width: 300px;
border: 1px solid black;
padding: 8px;
background-color: #ccc;
}
.flex {
display: flex;
}
.flex-column {
display: flex;
}
.item {
padding: 8px;
background-color: #fff;
overflow-wrap: break-word;
}
<div class="body">
<div class="flex" style="border:5px solid red;">
<div class="flex" style="border:5px solid green;min-width:0;">
<div class="flex" style="border:5px solid blue;min-width:0">
<div class="flex-column" style="border:5px solid yellow;min-width:0;">
<!-- adding min-width at this level -->
<div class="item" style="border:5px solid pink;min-width:0">
This is Spaaaaaaaaaaaaaaaarrrrrrrrrrrrrttttttttttttttaaaaaaaaaaaaaaaaaaaaaa!11 It's not a bug. Firefox is correctly implementing min-width: auto for flex items. When you change it to min-width: 0, you're just using a different value for min-width to get
your example looking how you want it to look. But both values are being rendered correctly.
</div>
</div>
</div>
</div>
</div>
</div>
Related
First of all, here is a codepen with the issue I am trying to solve.
This is a simplified version of the problem I have on an actual project. My goal is to keep the grid in the same format with 5 columns and to be able to increase the width of these cells so the content is always visible, but also so that it doesn't wrap before the first row of 5 columns is displayed. Whenever I try to increase the width of the cells the grid wraps and I lose the structure I want.
So, basically, increase width of items, but prevent wrapping, is it possible? It is fine if the content overflows the flex container itself, the goal is to add overflow-x to this grid.
.flex-container {
border: 1px solid silver;
display: flex;
width: 50%;
}
.wrap {
flex-wrap: wrap;
}
.wrap div {
background: gold;
}
.flex-item {
width: 160px;
border-bottom: 1px solid black;
border-right: 1px solid black;
line-height: 100px;
color: black;
font-weight: bold;
font-size: 2em;
text-align: center;
}
<div class="flex-container wrap">
<div class="flex-item">11111111111111</div>
<div class="flex-item">22222222222222</div>
<div class="flex-item">33333333333333</div>
<div class="flex-item">44444444444444</div>
<div class="flex-item">55555555555555</div>
<div class="flex-item">66666666666666</div>
<div class="flex-item">77777777777777</div>
<div class="flex-item">88888888888888</div>
<div class="flex-item">99999999999999</div>
<div class="flex-item">00000000000000</div>
</div>
From the comments, it does look like grid is the option you need, it won't allow content to be wrapping and justify content will stick it on the side if shorter thant the width of the container.
here is the snippet with grid:
/* flex turned into grid */
.flex-container {
border: 1px solid silver;
display: grid;
grid-template-columns:repeat(5,auto);
justify-content:start;
overflow:auto;
width: 80%;
}
.wrap {
}
.wrap div {
background: gold;
}
.flex-item {
border-bottom: 1px solid black;
border-right: 1px solid black;
line-height: 100px;
color: black;
font-weight: bold;
font-size: 2em;
text-align: center;
}
<div class="flex-container wrap">
<div class="flex-item">11111111111111</div>
<div class="flex-item">22222222222222</div>
<div class="flex-item">33333333333333</div>
<div class="flex-item">44444444444444</div>
<div class="flex-item">55555555555555</div>
<div class="flex-item">66666666666666</div>
<div class="flex-item">77777777777777</div>
<div class="flex-item">88888888888888</div>
<div class="flex-item">99999999999999</div>
<div class="flex-item">00000000000000</div>
</div>
I think, if it is allowable, that css grid may be a better candidate for the layout you are proposing...
.grid-container {
border: 1px solid silver;
display: grid;
width: 50%;
grid-template-columns: 20% 20% 20% 20% 20%; /* hard set five columns and no more */
}
.grid-container div {
background: gold;
}
.grid-item {
/* width: 160px; */
border-bottom: 1px solid black;
border-right: 1px solid black;
line-height: 100px;
color: black;
font-weight: bold;
font-size: 2em;
text-align: center;
overflow-x: hidden; /* overflow-x to hide overflow as discussed in question */
}
<div class="grid-container">
<div class="grid-item">11111111111111</div>
<div class="grid-item">22222222222222</div>
<div class="grid-item">33333333333333</div>
<div class="grid-item">44444444444444</div>
<div class="grid-item">55555555555555</div>
<div class="grid-item">66666666666666</div>
<div class="grid-item">77777777777777</div>
<div class="grid-item">88888888888888</div>
<div class="grid-item">99999999999999</div>
<div class="grid-item">00000000000000</div>
</div>
.flex-container {
display: flex;
flex-wrap: wrap;
background-color:red;
}
.flex-container > div {
background-color: #f1f1f1;
width: 100px;
margin: 10px;
text-align: center;
line-height: 75px;
font-size: 30px;
word-wrap: break-word;
}
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<div class="flex-container">
<div>11111111111111</div>
<div>22222222222222</div>
<div>33333333333333</div>
<div>44444444444444</div>
<div>55555555555555</div>
<div>66666666666666</div>
<div>77777777777777</div>
<div>88888888888888</div>
<div>99999999999999</div>
<div>00000000000000</div>
</div>
</body>
I'm trying to do a responsive layout, I'm not good with css so I need help.
Here is the code:
.container {
outline: 1px solid black;
max-width: 490px;
margin: 0 auto;
}
.columns {
outline: 1px solid black;
display: inline-flex;
flex-wrap: wrap;
}
.map {
background-color: cyan;
width: 150px;
min-width: 150px;
height: 150px;
min-height: 150px;
margin-right: 20px;
}
.content {
outline: 1px solid black;
background-color: lightgray;
max-width: 320px;
}
.cards {
outline: 1px solid black;
display: inline-flex;
flex-wrap: wrap;
}
.card {
background-color: pink;
outline: 1px solid black;
width: 150px;
height: 70px;
display: inline-block;
}
.card.left {
margin-right: 20px;
}
.texts {
outline: 1px solid black;
display: inline-flex;
flex-wrap: wrap;
}
.text {
background-color: gold;
outline: 1px solid black;
width: 150px;
height: 200px;
display: inline-block;
}
.text.left {
margin-right: 20px;
}
<div class="container">
<div class="columns">
<div class="map"></div>
<div class="content">
<div class="cards">
<div class="card left">card #1</div>
<div class="card">card #2</div>
<div class="card left">card #3</div>
<div class="card">card #4</div>
</div>
<div class="texts">
<div class="text left">text #1</div>
<div class="text">text #2</div>
</div>
</div>
</div>
</div>
Basically there are two rows.
The first one contains an element with fixed width and height, and on the right four cards.
The second rows contains only two elements.
Each element of this layout has width 150px.
The code shown above works partially.
The first row is ok, the second one no because the gold elements should stay aligned with the cards so when cards are on the right of el1, contents should below the cards.
It is like if there were to be a hidden element (on the left side of contents) that has the same size as el1.
Also I would like everything to always be centered because now it is only if the window width is > 490px.
This is what I'd like to have:
How can I do that?
I'm trying to use flexbox in order to create two columns of three row for the Products. I looked to other similar problem on StackOverflow but the answers given didn't work for me. Could you help me please ?
Here the HTML code:
Informations {
list-style-type: none;
margin: 0;
padding: 0;
border: 1px solid blue;
width: 100%;
display: flex;
justify-content: space-between;
}
.Information {
border: 1px solid blue;
margin: 0.5em;
padding: 0.5em;
}
Game {
list-style-type: none;
border: 1px solid red;
width: 100%;
display: flex;
}
.ProductContainer {
display: flex;
flex-flow: column wrap;
border: 1px solid black;
width: 90%;
}
.Product {
border: 1px solid red;
margin: 0.5em;
padding: 0.5em;
}
.UpgradeContainer {
border: 1px solid black;
width: 10%;
}
.Upgrade {
display: flex;
flex-flow: column wrap;
border: 1px solid red;
margin: 0.5em;
padding: 0.5em;
}
<!DOCTYPE world>
<html>
<head>
<title> World </title>
</head>
<body>
<Informations>
<div class="Information">Your World:</div>
<div class="Information">Your Money:</div>
<div class="Information">Your ID:</div>
</Informations>
<Game>
<div class="UpgradeContainer">
<div class="Upgrade">Unlocks</div>
<div class="Upgrade">Cash</div>
<div class="Upgrade">Angels</div>
<div class="Upgrade">Managers</div>
<div class="Upgrade">Investors</div>
</div>
<div class="ProductContainer">
<div class="Product">Product1</div>
<div class="Product">Product2</div>
<div class="Product">Product3</div>
<div class="Product">Product4</div>
<div class="Product">Product5</div>
<div class="Product">Product6</div>
</div>
</Game>
</body>
</html>
I basically want to have to the left my upgrades (Cash, angels...) and in the middle and right two column of three row of products.
Here is my code pen to see: https://codepen.io/Tameiki/pen/oNXpNVe
You can use the flex-wrap property together with setting the flex-basis on the child elements:
.ProductContainer{
display: flex;
flex-flow: wrap;
border: 1px solid black;
width: 90%;
}
.Product {
border: 1px solid red;
margin: 0.5em;
padding: 0.5em;
flex-basis: calc(50% - 2em - 5px); /* - Margins - Borders - 1px to mitigate subpixel rounding issues*/
}
<div class="ProductContainer">
<div class="Product">Product1</div>
<div class="Product">Product2</div>
<div class="Product">Product3</div>
<div class="Product">Product4</div>
<div class="Product">Product5</div>
<div class="Product">Product6</div>
</div>
Notice how I removed the flex-direction:column property: the child elements will attempt to fit in a single row, overflowing the container if necessary.
.ProductContainer{
display: flex;
/*flex-flow: wrap;*/
border: 1px solid black;
width: 90%;
}
.Product {
border: 1px solid red;
margin: 0.5em;
padding: 0.5em;
/*flex-basis: calc(50% - 2em - 5px); /* - Margins - Borders - 1px to mitigate subpixel rounding issues*/
}
<div class="ProductContainer">
<div class="Product">Product1</div>
<div class="Product">Product2</div>
<div class="Product">Product3</div>
<div class="Product">Product4</div>
<div class="Product">Product5</div>
<div class="Product">Product6</div>
</div>
flex-wrap is what makes them start a new line instead of overflowing:
.ProductContainer{
display: flex;
flex-flow: wrap;
border: 1px solid black;
width: 90%;
}
.Product {
border: 1px solid red;
margin: 0.5em;
padding: 0.5em;
/*flex-basis: calc(50% - 2em - 5px); /* - Margins - Borders - 1px to mitigate subpixel rounding issues*/
}
<div class="ProductContainer">
<div class="Product">Product1</div>
<div class="Product">Product2</div>
<div class="Product">Product3</div>
<div class="Product">Product4</div>
<div class="Product">Product5</div>
<div class="Product">Product6</div>
</div>
But how do we get only two of them per row? By telling each of the child elements to be half the row's width:
.ProductContainer{
display: flex;
flex-flow: wrap;
border: 1px solid black;
width: 90%;
}
.Product {
border: 1px solid red;
margin: 0.5em;
padding: 0.5em;
flex-basis: 50%; /*calc(50% - 2em - 5px); /* - Margins - Borders - 1px to mitigate subpixel rounding issues*/
}
<div class="ProductContainer">
<div class="Product">Product1</div>
<div class="Product">Product2</div>
<div class="Product">Product3</div>
<div class="Product">Product4</div>
<div class="Product">Product5</div>
<div class="Product">Product6</div>
</div>
Unfortunately, flex-basis applies to the inner width of an element - including paddings, but excluding margins and borders. Usually, Flexbox tries to shrink child elements to fit the row if possible, but flex-wrap disables this, so we will have to adjust manually. That gets you to the code at the top.
I have a content div with a variable length of content, horizontally.
I would like the width of this content div to auto-size depending on the length of it's content. For example, I would like to be able to remove the arbitrary "20%" value, and have the div size accordingly. Currently removing the 20% value from the width is forcing it to resize to 100% of it's container. What CSS am I missing?
Fiddle
.wrapper {
border: 2px solid green;
}
.content {
margin: 0 auto;
text-align: center;
border: 2px solid orange;
width: 20%;
}
<div class="wrapper">
<div class="content">
<span>One</span>
<span>Two</span>
<span>Three</span>
<span>Four</span>
</div>
</div>
Put text-align:center on the wrapper and set the display of the content div to inline or inline-block:
.wrapper {
border: 2px solid green;
text-align:center;
}
.content {
margin: 0 auto;
text-align: center;
border: 2px solid orange;
display: inline;
}
<div class="wrapper">
<div class="content">
<span>One</span>
<span>Two</span>
<span>Three</span>
<span>Four</span>
</div>
</div>
If you want fluid resizing behavior I'd suggest flexbox:
.wrapper {
border: 2px solid green;
display: flex;
justify-content: center;
}
.content {
margin: 0 auto;
text-align: center;
border: 2px solid orange;
/*width: 20%;*/
}
<div class="wrapper">
<div class="content">
<span>One</span>
<span>Two</span>
<span>Three</span>
<span>Four</span>
</div>
</div>
inline:
flexbox:
I am trying to create this layout using only CSS:
When title fits:
When title doesn't fit:
The btn on the right should be centered if it wraps.
I tried this:
.container {
width: 100%;
border: 1px solid grey;
padding: 5px;
}
.block {
padding: 5px;
border: 1px solid orange;
float: left;
}
.right-block {
float: right;
}
<div class="container">
<div class="block">Logo</div>
<div class="block">Title that is too long</div>
<div class="block right-block">right-btn</div>
<div style="clear: both"></div>
</div>
But obviously, the btn is still on the right after it wraps. Any idea how to center it when it wraps ? And I'd like to avoid javascript.
Fiddle here: http://jsfiddle.net/b7rvhwqg/
Pure CSS solution using a flexbox layout:
Updated Example Here
The trick is to add justify-content: center/flex-wrap: wrap to the parent .container element for horizontal centering. Then adjust the first element's margin-right value to auto in order to prevent the last element from being centered when it's on the same line.
(You may need to resize the browser to see how it adjusts).
.container {
width: 100%;
border: 1px solid grey;
padding: 5px;
display: flex;
flex-wrap: wrap;
justify-content: center;
}
.logo-text {
display: flex;
margin-right: auto;
}
.block {
padding: 5px;
border: 1px solid orange;
}
.center-block {
white-space: nowrap;
margin-right: auto;
}
<div class="container">
<div class="logo-text">
<div class="block logo">Logo</div>
<div class="block text">This title is short.</div>
</div>
<div class="block right-block">right-btn</div>
</div>
<div class="container">
<div class="logo-text">
<div class="block logo">Logo</div>
<div class="block text">This title is slightly longer than the other one. This title is longer than the other one...</div>
</div>
<div class="block right-block">right-btn</div>
</div>
There is an issue to achieve this via Pure CSS. The div is already having a float and you want to have a "long title" to accommodate that float and at the same time, you want the other right float to jump and become center. This is currently not possible. I believe, you need to consider media queries, but again, that will be a dependent solution, but your title looks like independent of expanding/contracting.
is it ok for you if the title will just fit depending on what width u want?.. for example:
{Logo}Title is toooooooooooooooooooooooooooooooooolong {btn}
it will become like this:
{Logo}Title is tooo... {btn}
it will be cut, then only ". . ." will continue
Flexbox is the most suitable for this task:
<div class="container">
<div class="block logo">Logo</div>
<div class="block title">Title that is too long Title that is too long</div>
<div class="block right-block">right-btn</div>
<div style="clear: both"></div>
</div>
.container {
display: flex;
flex-wrap: wrap;
width: 100%
border: 1px solid grey;
}
.block.logo {
flex-grow: 1;
border: 1px solid orange;
}
.block.title{
flex-grow: 10;
border: 1px solid orange;
}
.right-block {
flex-grow: 1;
border: 1px solid orange;
text-align: center;
}
http://jsfiddle.net/gmrash/7b8w982t/
.container {
width: 100%;
border: 1px solid grey;
padding: 5px;
}
.block {
padding: 5px;
border: 1px solid orange;
float: left;
}
.ellipsis{
text-overflow: ellipsis;
/* Required for text-overflow to do anything */
white-space: nowrap;
overflow: hidden; width: 75%;
}
.right-block {
float: right;
}
<div class="container">
<div class="block">Logo</div>
<div class="block ellipsis">Title that is too long Title that is too long Title that is too long that is too long Title that is too long</div>
<div class="block right-block">right-btn</div>
<div style="clear: both"></div>
</div>
jsFiddle