Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Centering grid content while left-aligning each row's content, with arbitrary item/column widths

I have a row of items of arbitrary width. They are centered within the container (note white space on the left and right sides of the red container):

enter image description here

Sometimes the container gets smaller than the width of all items:

enter image description here

When this happens, I want the items in the end to wrap to the next row like this:

enter image description here

It is very imporant for me that each row's content must be left-aligned, but the grid as a whole must be centered:

enter image description here

Initially, I tried implementing it with FlexBox. After a lot of frustration and hair pulling, I've learned that this is impossible witn FlexBox: https://stackoverflow.com/a/32811002/901944

Another answer on the same page suggests using CSS grid instead of flexbox.

CSS grid produces a slightly different result, but that also suits me:

enter image description here

Here's the code that makes it work:

.red-container {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(210px, max-content));
  justify-content: center;
}

This code contains a lot of keywords that I don't understand: grid-template-columns, repeat, auto-fit, minmax and max-content. I tried reading up on them and failed. None of guides and API docs explicitly explain how this particualr combination works. MDN docs are way too short and cryptic.

What I specifically struggle with is this 210px magic number. Why is it necessary? (Erm, I know it's necessary because how the spec is designed, but this does not help me understand.)

The sizes of items in my grid are arbitrary, so I can't use a fixed value. Also, setting this fixed value makes the result slightly off: small items grow and large items overflow the container.

What I essentially want is:

  grid-template-columns: repeat(auto-fit, minmax(min-content, max-content));

but that rule is recognized by browsers as faulty.

I've stumbled upon this answer that explains that using both min-content and max-content together is forbidden by the spec in this context. The answer's suggested solution is... to use Flexbox!

The loop has closed. I'm back to where I started, expect that I'm now lacking hair on my head for another round.

How to do I center my grid while left-aligning each row's content, with items having arbitrary widths?

Here's a boilerplate to fiddle with for your convenience: https://jsbin.com/vuguhoj/edit?html,css,output

The container can be resized by dragging it by the bottom-right corner.

PS No display: inline and float: left please.

.page {
  border: 1px solid black;
  overflow: hidden;
  resize: horizontal;
  max-width: 500px;
}

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(max-content, 50px));
  justify-content: center;
}

.item {
  border: 1px solid black;
  margin: 1px;
}
<div class="page">
  <div class="grid">
    <div class="item">
      Foofoofoo
    </div>
    <div class="item">
      Bar
    </div>
    <div class="item">
      BazBaz
    </div>
    <div class="item">
      QuuxQuuxQuux
    </div>
  </div>
</div>
like image 349
Andrey Mikhaylov - lolmaus Avatar asked Jun 17 '20 16:06

Andrey Mikhaylov - lolmaus


People also ask

How do I center content in a grid column?

One of the easiest ways of centering the content of grid items is using Flexbox. Set the display to "grid" for the grid container, and "flex" for grid items. Then, add the align-items and justify-content properties, both with the "center" value, to grid items.

How do you make items of A columns align in the center?

To center the items within a column, we use align-items and justify-items instead of the align-content and justify-content in our previous example. Using the item properties, we can align our items just like we did with our columns.

How do you center align content in CSS?

To just center the text inside an element, use text-align: center; This text is centered.


1 Answers

CSS grid approach-
root answer - joe82

.container {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(179px, max-content));
  grid-gap: 10px;
  justify-content: center;
  background: #999;
  overflow: hidden;
  padding: 10px;
}

.background {
  width: 179px;
  height: 64px;
  background: #99d9ea;
}

.background .child {
  border: 2px solid #000;
}

.background:nth-child(1) .child {
  width: 110px;
  height: 50px;
}

.background:nth-child(2) .child {
  width: 120px;
  height: 60px;
}

.background:nth-child(3) .child {
  width: 50px;
  height: 55px;
}

.background:nth-child(4) .child {
  width: 175px;
  height: 40px;
}
<div class="container">
    <div class="background"><div class="child"></div></div>
    <div class="background"><div class="child"></div></div>
    <div class="background"><div class="child"></div></div>
    <div class="background"><div class="child"></div></div>
</div>

Newbie here!

I admit that the above one isn't the output you desired, but it is my best attempt towards it, with the use of CSS grids. Here, you can understand that if we want to make it responsive then a minimum width is required after which, the column(content) will get carried to the next line, and that width is defined here(grid-template-columns: repeat(auto-fit, minmax(204px, max-content));) 204px. But because of it each column will take that much width at least, that's why I represented the actual dimension of a column with blue background and the actual content within the border.I just post it for your acknowledgment and approach so that you can get closer to the actual answer.

By the way, Flex Approach-
root idea - random COSMOS

.container {
  min-width: 130px;
  max-width: 340px;
  overflow: auto;
  background: #999;
  padding: 10px 40px;
  resize: horizontal;
  border: 1px solid #000;
}

.main-content {
  display: flex;
  flex-wrap: wrap;
  background: #fff;
  max-width: 340px;
  overflow: hidden;
}

.child {
  margin: 5px;
  padding: 5px;
  background: #99d9ea;
  border: 1px solid black;
}
<div class="container">
  <div class="main-content">
    <div class="child">Foofoofoo</div>
    <div class="child">Bar</div>
    <div class="child">BazBaz</div>
    <div class="child">QuuxQuuxQuux</div>
  </div>
</div>
Resize the window or the above div to see the results 

The above tells that the div is centered and the content is at left but not resizing according to content.

My personal opinion -

You should use @media for making it responsize, just as the way you want it to be, It is just like coding a lot for a simple output but it can give you the best and satisfying results out of your hard work and time!

Kindly inform me if you want me to make it responsize for you, I mean just like a demo-

Regard,
Om Chaudhary

like image 162
Om_16 Avatar answered Sep 20 '22 15:09

Om_16