7

I have a series of images that are fetched from a database, and when three or more images are added it visually shows the three columns.

When less than three images are present, because I'm using display: grid; it is currently justified to the left of the parent container (in the code example I've just used red boxes to represent the images).

Is there anyway of having it so that when one or two images are present these are justified to the centre of the parent element. I appreciate I could use javascript to detect how many images are present and if it is less than three, add a class and change the wrapper to display: flex, but I wondered if such a layout was possible with CSS only?

Due to the nature of the layout I do need to use CSS Grid when more than three images are present.

Note: I've commented out two of the red boxes in the HTML to show the initial issue when only one red box is present.

Codepen: https://codepen.io/anna_paul/pen/xxXrVJQ

body {
  display: flex;
  justify-content: center;
  margin: 0
  width: 100%;
  height: 100vh;
}

.wrapper {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  grid-gap: 1rem;
  max-width: 1250px;
}

.box {
  width: 200px;
  height: 200px;
  background: red;
}
<div class="wrapper">
  <div class="box"></div>
<!--   <div class="box"></div>
  <div class="box"></div> -->
</div>
Paulie_D
  • 107,962
  • 13
  • 142
  • 161
pjk_ok
  • 618
  • 7
  • 35
  • 90
  • Could you explain why due to the nature of your layout it has to be grid not flex box? Does the most recent answer on https://stackoverflow.com/questions/46276793/how-to-center-elements-on-the-last-row-in-css-grid help? – A Haworth Dec 19 '21 at 07:24
  • @AHaworth because of the nature of the image grid, and how much easier it is to do responsively with grid instead of flex. – pjk_ok Dec 20 '21 at 00:52
  • @paulo_cam so when 1 or 2 images are there you need them to be centered. And when 3 or more are there you want them left aligned? Can you show required outputs for each use case in OP? and add border to container so we'll understand free space in each case. – the Hutt Dec 23 '21 at 01:49
  • try this `.wrapper { display: grid; grid-template-columns: auto 1fr; grid-template-rows: auto 1fr auto; grid-gap: 1rem; max-width: 1250px; justify-content: center; }` – Monika Virmani Dec 23 '21 at 13:00

3 Answers3

7

Do it like below:

.wrapper {
  display: grid;
  grid-auto-flow:column; /* column flow */
  justify-content:center; /* center everything */
  grid-gap: 1rem;
  max-width: 600px;
  border:1px solid;
  margin:10px auto;
}
/* make sure you only have 3 columns*/
.box:nth-child(3n + 1) {grid-column:1}
.box:nth-child(3n + 2) {grid-column:2}
.box:nth-child(3n + 3) {grid-column:3}
/**/
.box {
  width: 100px;
  height: 100px;
  background: red;
}
<div class="wrapper">
  <div class="box"></div>
</div>
<div class="wrapper">
  <div class="box"></div>
  <div class="box"></div>
</div>
<div class="wrapper">
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
</div>
<div class="wrapper">
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
</div>
<div class="wrapper">
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
</div>
<div class="wrapper">
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
</div>
Temani Afif
  • 245,468
  • 26
  • 309
  • 415
  • +1, this is the right answer but careful is you copy and paste,`max-width: 600px;` is incorrect for a square of 200px. Since we can have two gap of `1rem` you need to set `max-width: calc(600px + 2rem);`. – Ben Souchet Dec 28 '21 at 19:50
  • @BenSouchet what copy/past? 600px is a random big value used for the sake of the demo. It's irrelevant and can be removed btw. It has no relation with the boxes width. – Temani Afif Dec 28 '21 at 19:58
0

Because you are using 1fr for each column, even if a column has no content it is taking 33% of the free space. You need to specify units other than fr(fraction of the available space) unit:

grid-template-columns: auto auto auto;
grid-template-columns: repeat(3, auto);

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

Use any of the above. There is a small difference between auto and minmax(min-content, max-content).

Following is the demo with 3 containers with 1, 2 and >3 items respectively:

body {
  margin: 0;
  width: 100%;
  height: 100vh;
}

.demo {
  display: flex;
  justify-content: center;
}

.wrapper {
  display: grid;
  grid-template-columns: repeat(3, minmax(min-content, max-content));
  
  grid-gap: 1rem;
  width: auto;
  max-width: 1250px;
}

.box {
  width: 200px;
  height: 200px;
  background: red;
  border: 1px solid;
}
<p>Grid with one item</p>
<div class="demo">
  <div class="wrapper">
    <div class="box">1</div>
  </div>
</div>
<hr>
<p>Grid with two items</p>
<div class="demo">
  <div class="wrapper">
    <div class="box">1</div>
    <div class="box">2</div>
  </div>
</div>
<hr>
<p>Grid with >3 items</p>
<div class="demo">
  <div class="wrapper">
    <div class="box">1</div>
    <div class="box">2</div>
    <div class="box">3</div>
    <div class="box">4</div>
  </div>
</div>

The 1rem grid-gap will remain even if the column has 0 width. So in your setup, grid inside flex, the item in one item grid will be off by 2rem(2grid-gaps) from the center. If this is not a big deal then no worries.
But if you want exact center then you need to make grid-gap:0. And use spacing in side grid items(.box) like margin: 0.5rem; or padding:0.5rem to make artificial grid-gap.

body {
  margin: 0;
  width: 100%;
  height: 100vh;
}

.demo {
  display: flex;
  justify-content: center;
}

.wrapper {
  display: grid;
  grid-template-columns: repeat(3, minmax(min-content, max-content));
  
  width: auto;
  max-width: 1250px;
}

.box {
  width: 200px;
  height: 200px;
  background: red;
  border: 1px solid;
  
  margin: 0.5rem;
}
<p>Grid with one item</p>
<div class="demo">
  <div class="wrapper">
    <div class="box">1</div>
  </div>
</div>
<hr>
<p>Grid with two items</p>
<div class="demo">
  <div class="wrapper">
    <div class="box">1</div>
    <div class="box">2</div>
  </div>
</div>
<hr>
<p>Grid with >3 items</p>
<div class="demo">
  <div class="wrapper">
    <div class="box">1</div>
    <div class="box">2</div>
    <div class="box">3</div>
    <div class="box">4</div>
  </div>
</div>
the Hutt
  • 16,980
  • 2
  • 14
  • 44
  • Thanks Onkar. In the second example with two boxes, the grid isn't centred - if you click on it with the dev tools it's offset by 1rem caused by the grip gap property. Is there anyway of preventing that? – pjk_ok Dec 23 '21 at 11:29
  • I've explained that in the answer. Added second code snippet demonstrating the solution. – the Hutt Dec 23 '21 at 12:06
-2

using auto instead of fr and using align-content solve your problem.

body {
  display: flex;
  justify-content: center;
  margin: 0
  width: 100%;
  height: 100vh;
}

.wrapper {
  display: grid;
  grid-template-columns: auto auto auto;
  align-content : start;
  /*  grid-gap: 1rem;  */ 
  max-width: 1250px;
}

.box {
  width: 200px;
  height: 200px;
  background: red;
  margin: 1rem ; 
}
<div class="wrapper">
  <div class="box"></div>
<!--   <div class="box"></div>
  <div class="box"></div> -->
</div>
Ahmad MRF
  • 1,346
  • 1
  • 6
  • 16
  • That doesn't align it to the centre. If you bring up the developer tools it offsets it to the left by 2rem, caused by the grid gap property. – pjk_ok Dec 20 '21 at 00:50
  • it's true . You are right. using `margin` located it exactly in the center. – Ahmad MRF Dec 20 '21 at 07:20
  • I can't use that solution because when there are two images I need the grid gap and when there are 3 or more I'll then have extra margin I don't need. – pjk_ok Dec 21 '21 at 01:19