Nested Flexbox Wrapping [duplicate] - css

This question already has answers here:
When flexbox items wrap in column mode, container does not grow its width
(9 answers)
Closed 1 year ago.
I am trying to create a flexbox container that contains a list of items in a row format and then each of those items will be a flexbox with items in a wrapping column format. However, it seems that the first containers rows do not expand to fit the contents of the wrapping columns and end up overlapping each other.
Demo
I want the end result to look like this:
.flex-group {
display: flex;
}
.flex-container {
padding: 0;
margin: 0;
list-style: none;
border: 1px solid silver;
display: flex;
flex-direction: column;
flex-wrap: wrap;
height: 500px;
}
.red li {
background: red;
}
.gold li {
background: gold;
}
.blue li {
background: deepskyblue;
}
.flex-item {
padding: 5px;
width: 100px;
height: 100px;
margin: 10px;
line-height: 100px;
color: white;
font-weight: bold;
font-size: 2em;
text-align: center;
}
<div class="flex-group">
<ul class="flex-container blue">
<li class="flex-item">1</li>
<li class="flex-item">2</li>
<li class="flex-item">3</li>
<li class="flex-item">4</li>
<li class="flex-item">5</li>
<li class="flex-item">6</li>
<li class="flex-item">7</li>
<li class="flex-item">8</li>
</ul>
<ul class="flex-container red">
<li class="flex-item">1</li>
<li class="flex-item">2</li>
<li class="flex-item">3</li>
</ul>
<ul class="flex-container gold">
<li class="flex-item">1</li>
<li class="flex-item">2</li>
<li class="flex-item">3</li>
<li class="flex-item">4</li>
<li class="flex-item">5</li>
</ul>
<div>
So at the end of the day, I'm looking to have a non-wrapping row where each of the child elements (dynamic amount) can contain a set of column wrapping elements (dynamic amount). Note: You can almost get the solution if you make the .flex-container have flex-direction: row but I need flex-direction: column since order does matter in this scenario. The main container needs to have a fixed height and each child container can have a dynamic width (due to wrapping elements causing them to grow horizontally).

If you will use grid, you can use this:
.flex-group {
display: flex;
}
.flex-container {
padding: 0;
margin: 0;
list-style: none;
border: 1px solid silver;
display: grid;
grid-template-rows: repeat(3, auto);
gap: 10px;
grid-auto-flow: column;
height: 500px;
}
.red li {
background: red;
}
.gold li {
background: gold;
}
.blue li {
background: deepskyblue;
}
.flex-item {
padding: 5px;
width: 100px;
height: 100px;
margin: 10px;
line-height: 100px;
color: white;
font-weight: bold;
font-size: 2em;
text-align: center;
}
<div class="flex-group">
<ul class="flex-container blue">
<li class="flex-item">1</li>
<li class="flex-item">2</li>
<li class="flex-item">3</li>
<li class="flex-item">4</li>
<li class="flex-item">5</li>
<li class="flex-item">6</li>
<li class="flex-item">7</li>
<li class="flex-item">8</li>
</ul>
<ul class="flex-container red">
<li class="flex-item">1</li>
<li class="flex-item">2</li>
<li class="flex-item">3</li>
</ul>
<ul class="flex-container gold">
<li class="flex-item">1</li>
<li class="flex-item">2</li>
<li class="flex-item">3</li>
<li class="flex-item">4</li>
<li class="flex-item">5</li>
</ul>
<div>

There are a lot of similar question but no answers. I think a workaround can satisfy your needs. Include a script to calculate the width depending on the height you assign to each flex-container and the flex-item height:
check it out here
I had to fix the height to 400px to get the same output as yours but this script will calculate number of cols and lines needed. Couldn't get the padding properly though so I set a variable that will get me the desired output
document.querySelectorAll('.flex-container').forEach((e)=>{
let p = 10 ;
let childCount = e.childElementCount;
let childHeight = e.children[0].clientHeight ;
let childWidth = e.children[0].clientWidth ;
let lines = Math.round((e.clientHeight / (e.children[0].clientHeight + 2*p))) ;
let cols = Math.round(childCount / lines) ;
let width = cols * ( 2*p + childWidth );
e.style.width = width+"px";
});
Still if you want a column based display for your items similar to Pinterest then you need to specify in advance the number of columns and use Masonry Layout :
.masonry-container {
column-count: 3;
column-gap: 15px;
}
.masonry-item {
display: inline-block;
width: 100%;
}

I'm not sure I got this, but it sounds like you don't want your columns to be in 'wrap' mode.
You may try to change those values:
.flex-container {
/* leave the rest of what was here*/
flex-wrap: nowrap;
height: 100%;
}
This is what I thought you want to achieve:

Related

Flexbox justify-content: space-around clickable area is content width only. Could it expand?

I want to distribute menu items evenly, so use justify-content space-around. But clickable area is content width only.
If use pure CSS can expand clickable area? (Project will change menu content in the future.)
.menu {
margin: 0;
padding: 0;
list-style: none;
display: flex;
justify-content: space-around;
}
.menu__link {
display: block;
}
<ul class="menu">
<li class="menu__item"><a class="menu__link" href="#">ABC</a></li>
<li class="menu__item"><a class="menu__link" href="#">DEFGHI</a></li>
<li class="menu__item"><a class="menu__link" href="#">JKLMNOPQ</a></li>
<li class="menu__item"><a class="menu__link" href="#">RSTUV</a></li>
<li class="menu__item"><a class="menu__link" href="#">WXYZ</a></li>
</ul>
Yet another example.
.menu {
margin: 0;
padding: 0;
list-style: none;
display: flex;
justify-content: space-between;
}
.menu__link {
display: block;
border-bottom: 2px solid transparent;
color: blue;
text-align: center;
text-decoration: none;
}
.menu__link:hover {
border-bottom: 2px solid blue;
}
.menu__item {
flex: 1;
}
<ul class="menu">
<li class="menu__item"><a class="menu__link" href="#">ABC</a></li>
<li class="menu__item"><a class="menu__link" href="#">DEFGHI</a></li>
<li class="menu__item"><a class="menu__link" href="#">JKLMNOPQ</a></li>
<li class="menu__item"><a class="menu__link" href="#">RSTUV</a></li>
<li class="menu__item"><a class="menu__link" href="#">WXYZ</a></li>
</ul>
The issue with the code is that, youe li items are not fitting to the space of your ul
Just add flex: 1; text-align: center; to your li items to make the li items grow to the container dimension.
.menu {
margin: 0;
padding: 0;
list-style: none;
display: flex;
justify-content: space-around;
}
.menu__link {
display: block;
}
.menu__item {
flex: 1;
text-align: center;
}
<ul class="menu">
<li class="menu__item"><a class="menu__link" href="#">ABC</a></li>
<li class="menu__item"><a class="menu__link" href="#">DEFGHI</a></li>
<li class="menu__item"><a class="menu__link" href="#">JKLMNOPQ</a></li>
<li class="menu__item"><a class="menu__link" href="#">RSTUV</a></li>
<li class="menu__item"><a class="menu__link" href="#">WXYZ</a></li>
</ul>
You can add a padding to both right and left area of your a tag to expand it. I used padding-inline to add 2rem to both. Or you can do it manually by using padding: 0 2rem;, either works. See the snippet below for your reference (added a background-color for you to see the area expanded clearly).
.menu {
margin: 0;
padding: 0;
list-style: none;
display: flex;
justify-content: space-around;
}
.menu__link {
display: block;
padding-inline: 2rem;
background: grey;
}
<ul class="menu">
<li class="menu__item"><a class="menu__link" href="#">ABC</a></li>
<li class="menu__item"><a class="menu__link" href="#">DEFGHI</a></li>
<li class="menu__item"><a class="menu__link" href="#">JKLMNOPQ</a></li>
<li class="menu__item"><a class="menu__link" href="#">RSTUV</a></li>
<li class="menu__item"><a class="menu__link" href="#">WXYZ</a></li>
</ul>
Or as #Nitheesh answered, you can use flex-grow: 1; or flex: 1; for short to expand the menu__item to the available space equally, then add a gap property to the parent container if you want space in-between items. The advantage of this is that you'll have n equal containers.

Flexbox wrongly calculating width of items with text

Here is my code https://jsfiddle.net/n4qpv91t/4/
HTML
<nav class="m-nav-main">
<ul class="m-nav-main__menu">
<li class="m-nav-main__item">
PLATFORM OF JOYSSS SAMPLETEXT
</li>
<li class="m-nav-main__item">
LOREM DIMTURAGUA
</li>
<li class="m-nav-main__item">
WORDS
</li>
<li class="m-nav-main__item">
OFFRES SPECIALS OF WORLD
</li>
<li class="m-nav-main__item">
LEARN FROM HOME
</li>
</ul>
</nav>
CSS
.m-nav-main {
width: 1000px;
}
.m-nav-main__menu {
list-style: none;
display: inline-flex;
justify-content: flex-end;
padding: 0;
margin: 0;
}
.m-nav-main__item {
display: inline-block;
border: solid 1px red;
}
.m-nav-main__link {
display: flex;
height: 50px;
padding: 0 1rem;
color: inherit;
border: solid 1px green;
align-items: center;
}
I have menu with text that breaks to 2nd line. Flexbox desnt get proper width of this text resulting in big empty spaces between text. I want those menu items to be as narrow as possible. I use flex on links to have centered vertically text. Changing it to inline or anything doesnt make a change.
Try adding flex: 1; to .m-nav-main__item.

equidistant delimiter in between flex items with variable width

I need to design a navigation rendered dynamically by a CMS (so I have no control over HTML markup). The menu has a unknown, variable number of items, and all items have a variable, unknown width. I need to layout those menu items in one line with an equidistant spacing in between (easily done with flexbox) and with a visual separator exactly in the middle of the spacing (this is my unsolved problem).
Below is the code I've got so far. The HTML is just an example output, and I can't modify it. I'm also not allowed to use JS. The CSS is from myself and I can fully control it.
.mainnav {
width: 100%;
display: flex;
justify-content: space-between;
list-style-type: none;
margin: 0;
padding: 0;
border: 1px solid black;
}
.mainnav__item {
flex: 0 0 auto;
background-color: yellow;
position: relative;
white-space: nowrap;
}
.mainnav__item + .mainnav__item::before {
content: '';
width: 1px;
height: 100%;
background-color: red;
position: absolute;
left: -50%;
top: 0;
}
<ul class="mainnav">
<li class="mainnav__item">
<a class="mainnav__link" href="#">Short</a>
</li>
<li class="mainnav__item">
<a class="mainnav__link" href="#">Looooooooooooooong</a>
</li>
<li class="mainnav__item">
<a class="mainnav__link" href="#">Mediuuum</a>
</li>
<li class="mainnav__item">
<a class="mainnav__link" href="#">whatever else</a>
</li>
</ul>
My problem is the red separator line. It should be exactly in the middle, but I don't know how to calculate the horizontal position.
Can anybody tell me a CSS only solution for the delimiter placement?
The solution should work in common, up-to-date browsers (current version of [Android|Win] Chrome, [macOs|iOs] Safari, Firefox, Edge), but also in IE11
One idea is to consider display:contents;1 within the li element and keep the pseudo element in-flow (remove position:absolute). This will make the pseudo element and the a to be the flex items instead of the li element thus space-between will do the job.
Simply pay attention to the browser support since it's a new feature.
.mainnav {
width: 100%;
display: flex;
justify-content: space-between;
list-style-type: none;
margin: 0;
padding: 0;
border: 1px solid black;
}
.mainnav__item {
flex: 0 0 auto;
position: relative;
white-space: nowrap;
display:contents;
}
.mainnav__item a {
background:yellow;
}
.mainnav__item + .mainnav__item::before {
content: '';
width: 1px;
display:block;
background-color: red;
}
<ul class="mainnav">
<li class="mainnav__item">
<a class="mainnav__link" href="#">Short</a>
</li>
<li class="mainnav__item">
<a class="mainnav__link" href="#">Looooooooooooooong</a>
</li>
<li class="mainnav__item">
<a class="mainnav__link" href="#">Mediuuum</a>
</li>
<li class="mainnav__item">
<a class="mainnav__link" href="#">whatever else</a>
</li>
</ul>
1 The element itself does not generate any boxes, but its children and
pseudo-elements still generate boxes and text runs as normal. For the
purposes of box generation and layout, the element must be treated as
if it had been replaced in the element tree by its contents (including
both its source-document children and its pseudo-elements, such as
::before and ::after pseudo-elements, which are generated before/after
the element’s children as normal).ref
Another idea is to adjust flex-grow and use border instead of relying on space-between:
.mainnav {
display: flex;
list-style-type: none;
margin: 0;
padding: 0;
border: 1px solid black;
}
.mainnav__item {
flex: 0 0 auto;
position: relative;
white-space: nowrap;
flex-grow:2; /*middle elements need to grow twice that edge element*/
text-align:center;
border-left:1px solid red;
border-right:1px solid red;
}
.mainnav__item a {
background:yellow;
}
.mainnav__item:first-child {
flex-grow:1;
text-align:left;
border-left:none;
}
.mainnav__item:last-child {
flex-grow:1;
text-align:right;
border-right:none;
}
<ul class="mainnav">
<li class="mainnav__item">
<a class="mainnav__link" href="#">Short</a>
</li>
<li class="mainnav__item">
<a class="mainnav__link" href="#">Looooooooooooooong</a>
</li>
<li class="mainnav__item">
<a class="mainnav__link" href="#">Mediuuum</a>
</li>
<li class="mainnav__item">
<a class="mainnav__link" href="#">whatever else</a>
</li>
</ul>

How can I convert Css to React-native

I want to do the exact same thing of what this CSS styling suggests in react native
So how can I convert this CSS to React -native
.grid {
display: flex;
flex-direction: row;
list-style: none;
padding-left: 0;
flex-wrap: wrap;
margin-top: 0;
margin-bottom: 20px;
width: 400px;
}
.grid-item {
flex-grow: 0;
border-right: 1px solid #000;
border-bottom: 1px solid #000;
height: 100px;
background: rgba(0,0,0,0.1);
width: 33%;
}
.grid-item:nth-last-child(-n+3) {
border-bottom: none;
}
.grid-item:nth-child(3n+0) {
border-right: none;
}
.list {
display: flex;
flex-direction: column;
list-style: none;
padding-left: 0;
width: 400px;
}
.list-item {
flex-grow: 0;
border-bottom: 1px solid #000;
height: 60px;
background: rgba(0,0,0,0.1);
flex: 1;
}
.list-item:last-child {
border-bottom: none;
}
<ul class="grid">
<li class="grid-item">
</li>
<li class="grid-item">
</li>
<li class="grid-item">
</li>
<li class="grid-item">
</li>
<li class="grid-item">
</li>
<li class="grid-item">
</li>
<li class="grid-item">
</li>
<li class="grid-item">
</li>
<li class="grid-item">
</li>
</ul>
<ul class="list">
<li class="list-item">
</li>
<li class="list-item">
</li>
<li class="list-item">
</li>
<li class="list-item">
</li>
</ul>
I want to make a Modal which looks like this:
<Modal>
<BrandsGrid />
</Modal>
<Modal>
<ModelsList />
</Modal>
I need to define BrandsGrid and ModelsList and do something exactly similar to that CSS styling in React-native
So example codes will be more helpful for understanding I have referred the docs but couldn't get much help from that
You can use different modules for converting css components to react native. For example:
https://www.npmjs.com/package/css-to-react-native-transform
Another great example:
https://github.com/kristerkari/react-native-css-transformer

how do I stack unordered list into 2 separate rows

I'm completely stuck and have been struggling with this for days because I'm not a developer and just learn from forums.
I cannot modify the li classes with the price and table, restriction on code blocks to generate this from my ecommerce platform. I would like to get the results displayed in two rows, qty on top and price on bottom.
96 150 300 450 600
8.06 7.66 7.26 6.86 5.97
li.QtyTabQty {
display: inline-block;
/* text-align: right; */
border-right: 1px solid #fff;
/* width: 100%; */
/* float: right; */
/* width: 100%; */
}
li.QtyTabPrc {
display: inline-block;
text-align: right;
border-right: 1px solid #fff;
/* width: 100%; */
float: right;
}
<ul class="none">
<li class="QtyTabQty">96</li>
<li class="QtyTabPrc">$8.06</li>
<li class="QtyTabQty">150</li>
<li class="QtyTabPrc">$7.66</li>
<li class="QtyTabQty">300</li>
<li class="QtyTabPrc">$7.26</li>
<li class="QtyTabQty">450</li>
<li class="QtyTabPrc">$6.86</li>
<li class="QtyTabQty">600</li>
<li class="QtyTabPrc">$5.97</li>
</ul>
if you want use lists you can do with flexbox:
.none {
display: flex;
flex-flow: column wrap;
/* height is required */
height: 50px;
}
.none li {
list-style: none;
flex: 1;
/* Modify padding as required */
padding: 0 7px;
}
<ul class="none">
<li class="QtyTabQty">96</li>
<li class="QtyTabPrc">$8.06</li>
<li class="QtyTabQty">150</li>
<li class="QtyTabPrc">$7.66</li>
<li class="QtyTabQty">300</li>
<li class="QtyTabPrc">$7.26</li>
<li class="QtyTabQty">450</li>
<li class="QtyTabPrc">$6.86</li>
<li class="QtyTabQty">600</li>
<li class="QtyTabPrc">$5.97</li>
</ul>
Another option...pretty close to what you already have.
li.QtyTabQty {
display: inline-block;
position:absolute;
}
li.QtyTabPrc {
display: inline-block;
float:left;
margin-top:30px;
margin-right:10px;
}
<ul class="none">
<li class="QtyTabQty">96</li>
<li class="QtyTabPrc">$8.06</li>
<li class="QtyTabQty">150</li>
<li class="QtyTabPrc">$7.66</li>
<li class="QtyTabQty">300</li>
<li class="QtyTabPrc">$7.26</li>
<li class="QtyTabQty">450</li>
<li class="QtyTabPrc">$6.86</li>
<li class="QtyTabQty">600</li>
<li class="QtyTabPrc">$5.97</li>
</ul>

Resources