Horizontal center for flex items [duplicate] - css

I want the flex items to be centered but when we have a second line, to have 5 (from image below) under 1 and not centered in the parent.
Here's an example of what I have:
ul {
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: center;
margin: 0;
padding: 0;
}
li {
list-style-type: none;
border: 1px solid gray;
margin: 15px;
padding: 5px;
width: 200px;
}
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
</ul>
http://jsfiddle.net/8jqbjese/2/

Flexbox Challenge & Limitation
The challenge is to center a group of flex items and left-align them on wrap. But unless there is a fixed number of boxes per row, and each box is fixed-width, this is currently not possible with flexbox.
Using the code posted in the question, we could create a new flex container that wraps the current flex container (ul), which would allow us to center the ul with justify-content: center.
Then the flex items of the ul could be left-aligned with justify-content: flex-start.
#container {
display: flex;
justify-content: center;
}
ul {
display: flex;
justify-content: flex-start;
}
This creates a centered group of left-aligned flex items.
The problem with this method is that at certain screen sizes there will be a gap on the right of the ul, making it no longer appear centered.
This happens because in flex layout (and, actually, CSS in general) the container:
doesn't know when an element wraps;
doesn't know that a previously occupied space is now empty, and
doesn't recalculate its width to shrink-wrap the narrower layout.
The maximum length of the whitespace on the right is the length of the flex item that the container was expecting to be there.
In the following demo, by re-sizing the window horizontally, you can see the whitespace come and go.
DEMO
A More Practical Approach
The desired layout can be achieved without flexbox using inline-block and media queries.
HTML
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
</ul>
CSS
ul {
margin: 0 auto; /* center container */
width: 1200px;
padding-left: 0; /* remove list padding */
font-size: 0; /* remove inline-block white space;
see https://stackoverflow.com/a/32801275/3597276 */
}
li {
display: inline-block;
font-size: 18px; /* restore font size removed in container */
list-style-type: none;
width: 150px;
height: 50px;
line-height: 50px;
margin: 15px 25px;
box-sizing: border-box;
text-align: center;
}
#media screen and (max-width: 430px) { ul { width: 200px; } }
#media screen and (min-width: 431px) and (max-width: 630px) { ul { width: 400px; } }
#media screen and (min-width: 631px) and (max-width: 830px) { ul { width:600px; } }
#media screen and (min-width: 831px) and (max-width: 1030px) { ul { width: 800px; } }
#media screen and (min-width: 1031px) and (max-width: 1230px) { ul { width: 1000px; } }
The above code renders a horizontally-centered container with left-aligned child elements like this:
DEMO
Other Options
Properly sizing and aligning the flex item(s) on the last row
Desandro Masonry
Masonry is a JavaScript grid layout library. It
works by placing elements in optimal position based on available
vertical space, sort of like a mason fitting stones in a wall. You’ve
probably seen it in use all over the Internet.
source: http://masonry.desandro.com/
CSS Grid Layout Module Level 1
This CSS module defines a two-dimensional grid-based layout system, optimized for user interface design. In the grid layout model, the children of a grid container can be positioned into arbitrary slots in a predefined flexible or fixed-size layout grid.
source: https://drafts.csswg.org/css-grid/

You can achieve it with CSS Grid, just use repeat(autofit, minmax(width-of-the-element, max-content))
ul {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(210px, max-content));
grid-gap: 16px;
justify-content: center;
padding: initial;
}
li {
list-style-type: none;
border: 1px solid gray;
padding: 5px;
width: 210px;
}
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
</ul>
http://jsfiddle.net/rwa20jkh/

Somehow, #Joe82 answer did not work for me. However, I found it to be the right approach. After reading this article about auto-fit and auto-fill I found out that auto-fit creates new columns when possible; however, it collapses them, so that the grid-items fill out the whole available space, if their max-width allows them this.
For those interested: auto-fill also creates new columns when possible, but does not let them collapse, so it creates empty visible columns, which will take up space.
You can see this in the following image:
Because of this, I used repeat(auto-fit, minmax(10rem, 1fr) for `grid-template-columns.
Then I set justify-items to center, this aligns the items inside their grid areas on the inline axis.
I also wanted some "margins" between the columns and rows, so I added a row-gap and a column-gap of 1rem with the shorthand.
As a result I added the following CSS to my div with the grid items inside it:
.card-section {
width: 100%;
display: grid;
justify-items: center;
gap: 1rem;
grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
}
I know this is not exactly what OP wanted to achieve, but maybe it helps someone, who has the same problem as me and stumbles upon this question.

You can place invisible elements with the same class as the others (removed on example for exibition purposes) and height set to 0. With that, you will be able to justify the items to the very start of the grid.
Example
<div class="table-container">
<div class="table-content">
<p class="table-title">Table 1</p>
<p class="mesa-price">$ 20</p>
</div>
<!-- Make stuff justified start -->
<div class="table-content" style="opacity: 0; cursor: default; height: 0; margin-bottom: 0;"></div>
<div class="table-content" style="opacity: 0; cursor: default; height: 0; margin-bottom: 0;"></div>
<div class="table-content" style="opacity: 0; cursor: default; height: 0; margin-bottom: 0;"></div>
<div class="table-content" style="opacity: 0; cursor: default; height: 0; margin-bottom: 0;"></div>
</div>
Result

As #michael suggested, this is a limitation with current flexbox. But if you want to still use flex and justify-content: center;, then we can workaround this by adding a dummy li element and assign margin-left.
const handleResize = () => {
const item_box = document.getElementById('parentId')
const list_length = item_box.clientWidth
const product_card_length = 200 // length of your child element
const item_in_a_row = Math.round(list_length/product_card_length)
const to_be_added = item_in_a_row - parseInt(listObject.length % item_in_a_row) // listObject is the total number items
const left_to_set = (to_be_added - 1 ) * product_card_length // -1 : dummy item has width set, so exclude it when calculating the left margin
const dummy_product = document.querySelectorAll('.product-card.dummy')[0]
dummy_product.style.marginLeft = `${left_to_set}px`
}
handleResize() // Call it first time component mount
window.addEventListener("resize", handleResize);
Check this fiddle (resize and see ) or video for reference

One way to get the desired style with margins is to do the following:
#container {
display: flex;
justify-content: center;
}
#innercontainer {
display: flex;
flex: 0.9; -> add desired % of margin
justify-content: flex-start;
}

I ran into this problem while coding with React Native. There's an elegant solution that you can have using FlexBox. In my particular situation, I was trying to center three flex boxes (Flex: 2) inside another using alignItems. The solution I came up with was using two empty s, each with Flex: 1.
<View style={{alignItems: 'center', flexWrap: 'wrap', flexDirection: 'row'}}>
<View style={{flex: 1}} />
// Content here
<View style={{flex: 1}} />
</View>
Easy enough to convert to web / CSS.

The easiest way I've found to fix this is just simply add some place holders with visibility: hidden. That way it maintains the correct spacing as it wraps.

TL;DR
You can stuff some filler elements to the end of your container, and set visibility: hidden to make it invisible, and remember to set height: 0px to prevent the height be taken.
Demo
In the example below, you can click the button to watch the changes.
const container = document.getElementsByClassName('container')[0];
const item = document.createElement('div');
item.classList.add("item");
const filler = document.createElement('div')
filler.classList.add("filler");
item.appendChild(filler);
Array.from(Array(5).keys()).forEach(() => {
container.appendChild(item.cloneNode(true));
});
function onShowClick() {
const filler = document.getElementsByClassName('filler')
for (let i = 0; i < filler.length; i++) {
filler[i].style.border = "1px dashed #686868"
filler[i].style.visibility = "visible"
filler[i].style.height = "100px"
}
};
function onHideClick() {
const filler = document.getElementsByClassName('filler')
for (let i = 0; i < filler.length; i++) {
filler[i].style.border = "none"
filler[i].style.visibility = "hidden"
filler[i].style.height = "0px"
}
};
* {
box-sizing: border-box;
}
#root {
height: 400px;
width: 500px;
border: 1px solid #ff955a;
}
.container {
display: flex;
flex-wrap: wrap;
justify-content: center;
}
.item {
padding: 5px;
}
.content-box {
height: 100px;
width: 100px;
padding: 10px;
background-color: lightblue;
border-radius: 10px;
}
.filler {
visibility: hidden;
height: 0px;
width: 100px;
}
<div id="root">
<button onclick="onShowClick()">Show</button>
<button onclick="onHideClick()">Hide</button>
<div class="container">
<div class="item">
<div class="content-box">1</div>
</div>
<div class="item">
<div class="content-box">2</div>
</div>
<div class="item">
<div class="content-box">3</div>
</div>
<div class="item">
<div class="content-box">4</div>
</div>
<div class="item">
<div class="content-box">5</div>
</div>
<div class="item">
<div class="content-box">6</div>
</div>
<div class="item">
<div class="content-box">7</div>
</div>
<div class="item">
<div class="content-box">8</div>
</div>
<div class="item">
<div class="content-box">9</div>
</div>
</div>
</div>

Related

Vertically aligning the button with the TextField in React Material-UI

I am using the Material-UI library for React.
I am trying to make a simple form that looks like:
However, I can't figure out how to align the button with the TextField.
I tried changing the margin-top but it increases the margin of the entire wrapper.
Below is the code sandbox for it.
Any tips on getting this fixed?
https://codesandbox.io/embed/material-demo-y5eg7?fontsize=14&hidenavigation=1&theme=dark
In your styles.css file you can add {position: relative; top: 10px} to the small-button className then adjust the top value until you are happy with the position alternatively you might be able to wrap the row in a div and use {display:flex; flex-direction:row; justify-content:center;} to align them all.
Change the below styles in styles.css
.horizontal-form { /* This is newly added style */
display: flex;
align-items: center;
}
.input-text-wrapper {
/* margin-bottom: 1.2em; */ /* comment these styles */
}
.input-text-wrapper-small {
width: 33%;
/* margin-bottom: 1.2em; */
display: inline-block;
}
.small-button {
width: 10%;
/* display: inline-flex;
align-items: center; */
}
jsx
Remove the small-button div from inside the input-text-wrapper div and Then Enclose the input-text-wrapper div and small-button div inside a newly created horizontal-form div
...
</Typography>
<div className="horizontal-form">
<div className="input-text-wrapper">
<div className="input-text-wrapper-small">
...
</div>
<div className="input-text-wrapper-small">
...
</div>
<div className="input-text-wrapper-small">
...
</div>
</div>
<div className="small-button">
<Button variant="contained" color="primary">
Add
</Button>
</div>
</div>
</CardContent>
....
Just replace this line
<div className="input-text-wrapper">
with
<div className="input-text-wrapper" style={{display:"flex", alignItems:"center"}} >
AND remove margin-bottom from your style.css
.input-text-wrapper-small {
width: 30%;
/*margin-bottom: 1.2em;*/
display: inline-block;
}

Angular GoogleMaps Marker InfoWindow scrollbar not getting hidden

I'm trying to customise the popup info window that appears when you click on a marker, but I can't get rid of the scrollbar that appears on the right in case the content overflows.
https://pasteboard.co/Ith8X2v.png (image was not loading when used the image template)
I've tried adding overflow: scroll too all the parent containers as it seems that's the only thing the was different (see this).
I've made a little clip with what kinda worked but not entirely.
https://streamable.com/guoei
Markers code:
<agm-marker *ngFor="let m of markers; let i = index"
(markerClick)="clickedMarker(m.label, i)"
[latitude]="m.lat"
[longitude]="m.lng"
[label]="m.label"
[markerDraggable]="m.draggable">
<agm-info-window>
<div class="popup-info-container">
<div class="popup-header-container">
<strong>InfoWindow content</strong>
</div>
<div class="popup-body-container">
<strong>InfoWindow content</strong>
</div>
</div>
</agm-info-window>
</agm-marker>
CSS code:
.popup-info-container {
height: 400px;
width: 300px;
background-color: red;
display: flex;
flex-flow: column;
justify-content: center;
align-items: center;
&::-webkit-scrollbar {
display: none;
}
}
.agm-info-window-content {
overflow: scroll;
}
.popup-header-container {
height: 20%;
width: 95%;
background-color: blue;
}
.popup-body-container {
height: 75%;
width: 95%;
background-color:whitesmoke;
}
I want to get something like this:
where the scrollbar fadesout.
I've found a similar thing here How to edit css of child component imported from other module Angular 2+
Basically I had to override classes that angular was generating with ::ng-deep
::ng-deep .gm-style {
.gm-style-iw-d::-webkit-scrollbar {
display: none !important;
}
}

&. doesn't work in SCSS... why not?

I'm writing some basic SCSS. But I've noticed appending & before a class, only works in certain circumstances. For example, before elements like "section" or before ":hover, active".
But this never works for me before ".class". Why not?
For example, in the below code, .flex-item styles only apply, if I remove the &. But look at docs/internet, it should work with & in front, no?
section {
padding: 20px;
margin: 0 auto;
border: 1px solid red;
position: relative;
width: 95%;
list-style: none;
top: 100px;
display: -webkit-box;
display: -moz-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
-webkit-flex-flow: row wrap;
justify-content: center;
&.flex-item {
border: 1px solid green;
padding: 5px;
width: 50%;
height: 150px;
margin-top: 10px;
line-height: 150px;
color: $white;
font-weight: bold;
font-size: 3em;
text-align: center;
}
}
AND HERE'S THE JSX:
I basically want a section, (as that has high applied). And then two flex items, which sit side by side in a row, with the flex container...
<section className="flex-container">
<div className="flex-item">
<h1>A cashback credit card for holiday and home</h1>
<ul className="pros">
<li>No fees for making purchases abroad</li>
<li>Nothing added on top of the Mastercard exchange rate</li>
<li>Manage your holiday spending with realtime in-app notifications</li>
<li>0.5% cashback on all purchases above £1</li>
<li>Friendly customer support from anywhere with with in-app chat</li>
</ul>
<p>Great the same great rewards on holiday and at home with the Travel Cashback Credit Card.</p>
<p>See full information</p>
<Link to="/page-2/">Go to page 2</Link>
</div>
<div className="flex-item">
<h1>Hi people</h1>
<p>Welcome to your new Gatsby site.</p>
<p>Now go build something great.</p>
<Link to="/page-2/">Go to page 2</Link>
</div>
</section>
);
export default IndexPage;
Just remove the & before the .flex-item:
section {
// your section rules
.flex-item {
// your .flex-item rules
}
}
You only need the & (parent element reference) in cases where you want to use a pseudo selector, adding classes to the current selector (or partial class names), link a :hover or doing some other parent selector usage:
a {
// your link styles
&:hover {
// your hover styles
}
}
.button {
// .button styles
&.colored {
// .button.colored styles
}
&-large {
// .button-large styles
}
}
Or for some other parent selector appliances:
section {
// some styles
.parentclass & {
// this will match .parentclass section
}
}
This are just a few examples.

CSS Flex - nested flex list won't expand parent width [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 have a few items for a megamenu that are display:flex; and I have adapted the lists inside each flexed div to be flex column.
Problem is that sometimes the lists will have too many items, and I need them to start again in the same line.
Example on codepen: https://codepen.io/james_zedd/pen/KRyQao
I have modified the height of the first ul to be 100px as an example. The container div has not adapted to the new width of the ul.
What am I doing wrong here?
/* -- Mega MEnu -- */
.megamenu {
display: flex;
background-color: #f5f5f5;
opacity: 0;
visibility: hidden;
max-height: 430px;
}
.megamenu.first {
opacity: 1;
visibility: visible;
}
.megamenu__linklist {
padding: 30px 0 26px 40px;
}
.megamenu__linklist h4 {
margin-top: 0;
margin-bottom: 12px;
}
.megamenu__linklist ul {
margin: 0;
padding: 0;
list-style: none;
display: flex;
flex-direction: column;
flex-wrap: wrap;
}
.megamenu__linklist a:hover {
color: red;
}
<div id="mm01" class="megamenu first">
<div class="megamenu__img">
<img src="//cdn.shopify.com/s/files/1/0023/6516/1525/files/mm_01_330x430.jpg?v=1525703183" alt="Custom Printing Tshirts">
</div>
<div class="megamenu__linklist">
<h4>T-Shirts and Clothing</h4>
<ul class="mm_links" style="height:100px">
<li>T-Shirts</li>
<li>Hoodies/Sweatshirts</li>
<li>Performance</li>
<li>Golf Shirts/Polos</li>
<li>Woven Shirts</li>
<li>Hats and Toques</li>
<li>Outerwear</li>
<li>Pants/Shorts</li>
<li>Ladies</li>
<li>Youth</li>
<li>Infants/Toddlers</li>
</ul>
</div>
<div class="megamenu__linklist">
<h4>Sports and Teams</h4>
<ul class="mm_links">
<li>Hockey</li>
<li>Soccer</li>
<li>Basketball</li>
<li>Baseball</li>
<li>Football</li>
<li>Lacrosse</li>
<li>Volleyball</li>
<li>Track and Field</li>
<li>Rugby</li>
<li>Cycling</li>
</ul>
</div>
<div class="megamenu__linklist">
<h4>Signs and Displays</h4>
<ul class="mm_links">
<li>Adhesive Decals</li>
<li>Backdrops</li>
<li>Banners</li>
<li>Signs</li>
</ul>
</div>
<div class="megamenu__linklist">
<h4>PRINTD</h4>
<ul class="mm_links">
<li>About</li>
<li>FAQ</li>
<li>Contact Us</li>
<li>Privacy Policy</li>
<li>Terms and Conditions</li>
</ul>
</div>
</div>
I've noticed that sometimes, flexbox columns inside of flexbox rows (or vice versa) don't do the rendering math in the order I expect. That seems to be happening here, too.
Consider using flex-direction:row instead of column for the sub-elements, and give them a specific width or flex-basis. Something like this appears to solve your problem:
.megamenu .megamenu__img+.megamenu__linklist ul {
/* height: auto; */
flex-direction: row;
}
.megamenu .megamenu__img+.megamenu__linklist ul li {
flex: 0 0 33.33%;
}
https://codepen.io/mblase75/pen/MGOVoW

Flexbox quirks, centering of grid [duplicate]

I want the flex items to be centered but when we have a second line, to have 5 (from image below) under 1 and not centered in the parent.
Here's an example of what I have:
ul {
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: center;
margin: 0;
padding: 0;
}
li {
list-style-type: none;
border: 1px solid gray;
margin: 15px;
padding: 5px;
width: 200px;
}
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
</ul>
http://jsfiddle.net/8jqbjese/2/
Flexbox Challenge & Limitation
The challenge is to center a group of flex items and left-align them on wrap. But unless there is a fixed number of boxes per row, and each box is fixed-width, this is currently not possible with flexbox.
Using the code posted in the question, we could create a new flex container that wraps the current flex container (ul), which would allow us to center the ul with justify-content: center.
Then the flex items of the ul could be left-aligned with justify-content: flex-start.
#container {
display: flex;
justify-content: center;
}
ul {
display: flex;
justify-content: flex-start;
}
This creates a centered group of left-aligned flex items.
The problem with this method is that at certain screen sizes there will be a gap on the right of the ul, making it no longer appear centered.
This happens because in flex layout (and, actually, CSS in general) the container:
doesn't know when an element wraps;
doesn't know that a previously occupied space is now empty, and
doesn't recalculate its width to shrink-wrap the narrower layout.
The maximum length of the whitespace on the right is the length of the flex item that the container was expecting to be there.
In the following demo, by re-sizing the window horizontally, you can see the whitespace come and go.
DEMO
A More Practical Approach
The desired layout can be achieved without flexbox using inline-block and media queries.
HTML
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
</ul>
CSS
ul {
margin: 0 auto; /* center container */
width: 1200px;
padding-left: 0; /* remove list padding */
font-size: 0; /* remove inline-block white space;
see https://stackoverflow.com/a/32801275/3597276 */
}
li {
display: inline-block;
font-size: 18px; /* restore font size removed in container */
list-style-type: none;
width: 150px;
height: 50px;
line-height: 50px;
margin: 15px 25px;
box-sizing: border-box;
text-align: center;
}
#media screen and (max-width: 430px) { ul { width: 200px; } }
#media screen and (min-width: 431px) and (max-width: 630px) { ul { width: 400px; } }
#media screen and (min-width: 631px) and (max-width: 830px) { ul { width:600px; } }
#media screen and (min-width: 831px) and (max-width: 1030px) { ul { width: 800px; } }
#media screen and (min-width: 1031px) and (max-width: 1230px) { ul { width: 1000px; } }
The above code renders a horizontally-centered container with left-aligned child elements like this:
DEMO
Other Options
Properly sizing and aligning the flex item(s) on the last row
Desandro Masonry
Masonry is a JavaScript grid layout library. It
works by placing elements in optimal position based on available
vertical space, sort of like a mason fitting stones in a wall. You’ve
probably seen it in use all over the Internet.
source: http://masonry.desandro.com/
CSS Grid Layout Module Level 1
This CSS module defines a two-dimensional grid-based layout system, optimized for user interface design. In the grid layout model, the children of a grid container can be positioned into arbitrary slots in a predefined flexible or fixed-size layout grid.
source: https://drafts.csswg.org/css-grid/
You can achieve it with CSS Grid, just use repeat(autofit, minmax(width-of-the-element, max-content))
ul {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(210px, max-content));
grid-gap: 16px;
justify-content: center;
padding: initial;
}
li {
list-style-type: none;
border: 1px solid gray;
padding: 5px;
width: 210px;
}
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
</ul>
http://jsfiddle.net/rwa20jkh/
Somehow, #Joe82 answer did not work for me. However, I found it to be the right approach. After reading this article about auto-fit and auto-fill I found out that auto-fit creates new columns when possible; however, it collapses them, so that the grid-items fill out the whole available space, if their max-width allows them this.
For those interested: auto-fill also creates new columns when possible, but does not let them collapse, so it creates empty visible columns, which will take up space.
You can see this in the following image:
Because of this, I used repeat(auto-fit, minmax(10rem, 1fr) for `grid-template-columns.
Then I set justify-items to center, this aligns the items inside their grid areas on the inline axis.
I also wanted some "margins" between the columns and rows, so I added a row-gap and a column-gap of 1rem with the shorthand.
As a result I added the following CSS to my div with the grid items inside it:
.card-section {
width: 100%;
display: grid;
justify-items: center;
gap: 1rem;
grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
}
I know this is not exactly what OP wanted to achieve, but maybe it helps someone, who has the same problem as me and stumbles upon this question.
You can place invisible elements with the same class as the others (removed on example for exibition purposes) and height set to 0. With that, you will be able to justify the items to the very start of the grid.
Example
<div class="table-container">
<div class="table-content">
<p class="table-title">Table 1</p>
<p class="mesa-price">$ 20</p>
</div>
<!-- Make stuff justified start -->
<div class="table-content" style="opacity: 0; cursor: default; height: 0; margin-bottom: 0;"></div>
<div class="table-content" style="opacity: 0; cursor: default; height: 0; margin-bottom: 0;"></div>
<div class="table-content" style="opacity: 0; cursor: default; height: 0; margin-bottom: 0;"></div>
<div class="table-content" style="opacity: 0; cursor: default; height: 0; margin-bottom: 0;"></div>
</div>
Result
As #michael suggested, this is a limitation with current flexbox. But if you want to still use flex and justify-content: center;, then we can workaround this by adding a dummy li element and assign margin-left.
const handleResize = () => {
const item_box = document.getElementById('parentId')
const list_length = item_box.clientWidth
const product_card_length = 200 // length of your child element
const item_in_a_row = Math.round(list_length/product_card_length)
const to_be_added = item_in_a_row - parseInt(listObject.length % item_in_a_row) // listObject is the total number items
const left_to_set = (to_be_added - 1 ) * product_card_length // -1 : dummy item has width set, so exclude it when calculating the left margin
const dummy_product = document.querySelectorAll('.product-card.dummy')[0]
dummy_product.style.marginLeft = `${left_to_set}px`
}
handleResize() // Call it first time component mount
window.addEventListener("resize", handleResize);
Check this fiddle (resize and see ) or video for reference
One way to get the desired style with margins is to do the following:
#container {
display: flex;
justify-content: center;
}
#innercontainer {
display: flex;
flex: 0.9; -> add desired % of margin
justify-content: flex-start;
}
I ran into this problem while coding with React Native. There's an elegant solution that you can have using FlexBox. In my particular situation, I was trying to center three flex boxes (Flex: 2) inside another using alignItems. The solution I came up with was using two empty s, each with Flex: 1.
<View style={{alignItems: 'center', flexWrap: 'wrap', flexDirection: 'row'}}>
<View style={{flex: 1}} />
// Content here
<View style={{flex: 1}} />
</View>
Easy enough to convert to web / CSS.
The easiest way I've found to fix this is just simply add some place holders with visibility: hidden. That way it maintains the correct spacing as it wraps.
TL;DR
You can stuff some filler elements to the end of your container, and set visibility: hidden to make it invisible, and remember to set height: 0px to prevent the height be taken.
Demo
In the example below, you can click the button to watch the changes.
const container = document.getElementsByClassName('container')[0];
const item = document.createElement('div');
item.classList.add("item");
const filler = document.createElement('div')
filler.classList.add("filler");
item.appendChild(filler);
Array.from(Array(5).keys()).forEach(() => {
container.appendChild(item.cloneNode(true));
});
function onShowClick() {
const filler = document.getElementsByClassName('filler')
for (let i = 0; i < filler.length; i++) {
filler[i].style.border = "1px dashed #686868"
filler[i].style.visibility = "visible"
filler[i].style.height = "100px"
}
};
function onHideClick() {
const filler = document.getElementsByClassName('filler')
for (let i = 0; i < filler.length; i++) {
filler[i].style.border = "none"
filler[i].style.visibility = "hidden"
filler[i].style.height = "0px"
}
};
* {
box-sizing: border-box;
}
#root {
height: 400px;
width: 500px;
border: 1px solid #ff955a;
}
.container {
display: flex;
flex-wrap: wrap;
justify-content: center;
}
.item {
padding: 5px;
}
.content-box {
height: 100px;
width: 100px;
padding: 10px;
background-color: lightblue;
border-radius: 10px;
}
.filler {
visibility: hidden;
height: 0px;
width: 100px;
}
<div id="root">
<button onclick="onShowClick()">Show</button>
<button onclick="onHideClick()">Hide</button>
<div class="container">
<div class="item">
<div class="content-box">1</div>
</div>
<div class="item">
<div class="content-box">2</div>
</div>
<div class="item">
<div class="content-box">3</div>
</div>
<div class="item">
<div class="content-box">4</div>
</div>
<div class="item">
<div class="content-box">5</div>
</div>
<div class="item">
<div class="content-box">6</div>
</div>
<div class="item">
<div class="content-box">7</div>
</div>
<div class="item">
<div class="content-box">8</div>
</div>
<div class="item">
<div class="content-box">9</div>
</div>
</div>
</div>

Resources