Adjust Last Row of LI (using Display: flex)

Is there a way to adjust the last row of display: flexed items so that they will adopt the same width as the other items?

To keek them the all the same width you would have to revert to set width. Probably the best way I can think of in this case is disable flex-grow which is what allows the items to expand to fill excess space. That will let the flex-basis define the width. If you are using flex-shrink that should still work to allow items to squeeze up on very small screens, using width rather than flex-basis won’t allow this flexibility.

I have said it before about flex, I like the way you can use shrink/grow to allow items expand and contract from the basis width according to available space, but I wish there was an option for a more intelligent mode of wrapping where the number of items per row gets evened to best effect, rather than having the in-line style wrapping that can result in orphaned items which with grow go full-width. Sadly there is no such option.

2 Likes

The CSS working group has noticed this and hopes to resolve it in a future draft of flexbox.

Solve the “items on the last line get way too big when you’re flexing” problem. More generally, “make items have a consistent flexed size, regardless of how much extra space is on each line”.
Possible solution - fill out the last line with “phantom copies” of the last item, flex with them in, then remove them.
Possible solution - calculate minimum values of 1fr and alignment free space across the entire flexbox (instead of per-line) and use that.

As a big hack you could add half a dozen empty dummy elements to the end of the list with zero height to make them space out properly. As long as you have more dummy elements than you will have in any one row then it will ensure that the orphaned items stay at the same width as everything else. Any invisible wrapped items will be zero height and thus not affect layout.

e.g.

.woocommerce-page ul.products li.product.dummy {
	border:none;
	background:transparent;
	padding-top:0;
	padding-bottom:0;
	min-height:0;
	height:0;
	box-shadow:none;
	visibility:hidden;
	position:relative;
	z-index:-1;
}
 <li class="product dummy"> <a href="#" class="woocommerce-LoopProduct-link woocommerce-loop-product__link"><img width="150" height="111" src="//23.235.209.135/~annebr5/newstdm/wp-content/uploads/2013/11/p-341-cover-sacred.jpg" class="attachment-shop_catalog size-shop_catalog wp-post-image" alt="I Stand All Amazed" srcset="//23.235.209.135/~annebr5/newstdm/wp-content/uploads/2013/11/p-341-cover-sacred.jpg 90w, //23.235.209.135/~annebr5/newstdm/wp-content/uploads/2013/11/p-341-cover-sacred.jpg 150w" sizes="(max-width: 150px) 100vw, 150px" itemprop="image">
          <h2 class="woocommerce-loop-product__title"></h2>
          <span class="price"></span> </a><a rel="nofollow" href="#" class="button product_type_simple add_to_cart_button ajax_add_to_cart">Add to cart</a> </li>
        <li class="product dummy"> <a href="#" class="woocommerce-LoopProduct-link woocommerce-loop-product__link"><img width="150" height="111" src="//23.235.209.135/~annebr5/newstdm/wp-content/uploads/2013/11/p-341-cover-sacred.jpg" class="attachment-shop_catalog size-shop_catalog wp-post-image" alt="I Stand All Amazed" srcset="//23.235.209.135/~annebr5/newstdm/wp-content/uploads/2013/11/p-341-cover-sacred.jpg 90w, //23.235.209.135/~annebr5/newstdm/wp-content/uploads/2013/11/p-341-cover-sacred.jpg 150w" sizes="(max-width: 150px) 100vw, 150px" itemprop="image">
          <h2 class="woocommerce-loop-product__title"></h2>
          <span class="price"></span> </a><a rel="nofollow" href="#" class="button product_type_simple add_to_cart_button ajax_add_to_cart">Add to cart</a> </li>
        <li class="product dummy"> <a href="#" class="woocommerce-LoopProduct-link woocommerce-loop-product__link"><img width="150" height="111" src="//23.235.209.135/~annebr5/newstdm/wp-content/uploads/2013/11/p-341-cover-sacred.jpg" class="attachment-shop_catalog size-shop_catalog wp-post-image" alt="I Stand All Amazed" srcset="//23.235.209.135/~annebr5/newstdm/wp-content/uploads/2013/11/p-341-cover-sacred.jpg 90w, //23.235.209.135/~annebr5/newstdm/wp-content/uploads/2013/11/p-341-cover-sacred.jpg 150w" sizes="(max-width: 150px) 100vw, 150px" itemprop="image">
          <h2 class="woocommerce-loop-product__title"></h2>
          <span class="price"></span> </a><a rel="nofollow" href="#" class="button product_type_simple add_to_cart_button ajax_add_to_cart">Add to cart</a> </li>
        <li class="product dummy"> <a href="#" class="woocommerce-LoopProduct-link woocommerce-loop-product__link"><img width="150" height="111" src="//23.235.209.135/~annebr5/newstdm/wp-content/uploads/2013/11/p-341-cover-sacred.jpg" class="attachment-shop_catalog size-shop_catalog wp-post-image" alt="I Stand All Amazed" srcset="//23.235.209.135/~annebr5/newstdm/wp-content/uploads/2013/11/p-341-cover-sacred.jpg 90w, //23.235.209.135/~annebr5/newstdm/wp-content/uploads/2013/11/p-341-cover-sacred.jpg 150w" sizes="(max-width: 150px) 100vw, 150px" itemprop="image">
          <h2 class="woocommerce-loop-product__title"></h2>
          <span class="price"></span> </a><a rel="nofollow" href="#" class="button product_type_simple add_to_cart_button ajax_add_to_cart">Add to cart</a> </li>

      </ul>

It’s a bit of a big hack though and perhaps something that could be added width js instead of harming the page. Probably easier just to go with percentage width for now :slight_smile:

Just thinking out loud. Would it work to pad out the numbers with pseudo elements to preserve the integrity of the html? Probably not, but I never tried using them a flex items.

The new feature I think I would like is to have something like a wrap-type property that could be in-line (as per current behaviour) and evened which would try to distribute items as evenly evenly as possible give the number of items and how many will fit on a row.
For example if you had 10 items and three will fit on a row at the current width and a basis set in em units.
Currently or with in-line wrapping you get rows of 3, 3, 3 and 1.
But with evened wrapping you would get rows of 3, 3, 2 and 2.
Maybe add an option to reverse things so you get big ones first, 2, 2, 3 and 3.
Yes the 2s will be bigger, but I’m OK with that in many cases. If you want a fixed uniform size, then use a fixed size and be done with it.
But what I love about flex is the ability to make things flexible and adapt to available space using an em basis which is only an inferred non rigid width when shrink and grow are enabled. This can make a design fluid enough to work without the need for any media queries.

1 Like

You could probably add one of the dummies with pseudo elements but you need as many as the max number that fit in a row and of course the most pseudo elements you can finagle is 2. Also you need to ensure that the last extra items are much the same as the ones before or they may shrink and grow at a different rate (that’s why I added the internal elements in the demo above instead of just 4 empty list items). A JS solution to clone the last list element, add a new class and then repeat enough elements to always fill the line would be a better solution I think.

Flex shrink and flex grow were built and resolve on a line by line basis and were never really meant to be a grid as such. Hopefully latter version will address this problem because as of yet none of my clients have liked the orphaned items not being the same size as the rest of them. It seems to indicate that the last items are more important because they are bigger.

1 Like

@toad78,

I just wrote a “working page” demo for another member that gives the items the same widths, including the item(s) in the last row; however, it does so using media queries to assign widths to the flex children as needed. Not the most desirable technique, but it solves the problem.

You might want to try the last (second) example and see if the concept works in your situation.

1 Like

Where is it :slight_smile:

1 Like

I believe this is @ronpat’s “missing link”:

No Leading or Trailing Padding And No Combining Of Adjacent Paddings - #14 by ronpat

3 Likes

One quite obvious fix would be to give items a max-width value to stop them expanding too too wide, but I think Safari has a bug with with that.

1 Like

That will stop the elements getting bigger than a max-width but it won’t keep the elements the same size as the line before. It still results in orphans not matching the rest of the content although it may be better than them stretching full-width.

Flex shrink and flex grow resolve on a line by line basis and the line before bears no relationship to the current line,

I think for now the best solution would be to use JavaScript to get the width of a previous element and set the width of the orphan based on that value.

It could be less than ideal if the page gets redrawn. And of course being reliant on JavaScript it would be an enhancement.

While I wouldn’t mind using ghosts to fill in the gaps and force the last line of elements to be the same width, the data that is being populated is dynamic. I think it would be more work to go that route than if I worked with flex-shrink and flex-grow or try the recommendation of “…calculate minimum values of 1fr and alignment free space across the entire flexbox (instead of per-line) and use that.”

What I wound up doing was this:


.woocommerce .products ul, .woocommerce ul.products {
    display: grid;
    margin: 0;
    grid-template-columns: 1fr 1fr 1fr 1fr 1fr;
    grid-column-gap: 25px;
    grid-row-gap: 50px;
}

.woocommerce ul.products li.product, .woocommerce-page ul.products li.product {
    float: none;
    min-height: 300px;
    text-align: center;
    display: flex;
    justify-content: center;
    align-items: center;
    border-radius: 5px;
    background: rgba(255,255,255,0.1);
    padding: 30px 25px 25px 25px;
    box-shadow: 0 0 18px 0 rgba(0,0,0,0.2);
    margin: 0;
    width: auto;
    flex-flow: row wrap;
}

This seems to have fixed any orphans on the site and I made media query adjustments for responsiveness. Seems to work.

I’m not quite understanding what you are asking but assuming correct you claim that all your elements except the last element has the same measurements?

If so why not set measurements in % for example You have 5 elements setting each one to 20% would do the trick?

If you are worried that padding and margins have to play a role using box-sizing:border-box should fix that meaning that it calculates the width including the other measurements such as padding etc.

Otherwise I don’t quite get what you are asking?

We are talking about items that have wrapped on the last line (orphaned items) and flex box stretches these items to full width meaning they no longer match the row above. It has also been mentioned in a number of threads above that the only way to keep elements uniform would be to apply a width to them. However, that does defeat some of the usefulness of flex where elements can shrink and grow to fill the line and you don’t have to set a specific width or know how many elements there are as flex does it on a best fit approach.

The grid solution in toad78’s last post is actually not much difference to setting a width in flex because the 1fr is a fraction of the width and effectively a percentage width.

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.