admin管理员组

文章数量:1396739

I am working on an image gallery on a legacy site. I can't use anything other than regular old HTML/jQuery or JS/CSS. I know this would be a lot easier with Bootstrap or some grid library.

I'm building it with flexbox. There are four images in each row, with multiple rows. It looks great when each row has its four images. When it has 2 or 3, because I am using justify-content: space-between, it makes it look weird because of the big gap between the images.

The reason I'm using space-between is that I want the images to align to the left of the parent container, and also to the right.

Some notes:

  • Each flex item has a max-width of 150px
  • I want a margin between items, but I don't care if this margin changes as the viewport width changes
  • the flex container has a max width that only allows four 150px-wide items in a row

My question: if a row has less than a set # of elements (in this case four), can I change the justify-content to be something more appropriate, like flex-start?

Ideally, I want to do this without JavaScript/jQuery, but if that's impossible, I'm open to those solutions as well.

Also, feel free to let me know if I'm way overthinking this and don't even need to use justify-content: space-between. Here's a working example:

/* outer container */
.flex-container {
  padding: 24px 0;
  background: white;
  border: solid 1px rgba(0,0,0,.1);
  max-width: 700px; /* or whatever */
  
  /* flex props */
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
}

/* contains img block and title */
.thumb-grid {
  border: solid 1px rgba(0,0,0,.1);
  width: 150px;
  margin-bottom: 36px;
}

.thumb-grid:first-of-type { margin-left: 0; }
.thumb-grid:nth-of-type(4) { margin-right: 0; }

.thumb-grid p {
  text-align: center;
}

.img-block {
  background: black;
  height: 150px;
}

.img-block img {
  height: 150px;
  opacity: 1;
  transition: opacity 150ms;
}

.img-block:hover img {
  opacity: .9;
}
<div class="flex-container">
    
    <div class="thumb-grid">      
      <div class="img-block">        
        <a href=""><img src=".jpg" alt="example image"></a>        
      </div>      
      <p>Image 1</p>      
    </div>
    
    <div class="thumb-grid">      
      <div class="img-block">        
        <a href=""><img src=".jpg" alt="example image"></a>        
      </div>      
      <p>Image 2</p>      
    </div>
    
   <div class="thumb-grid">      
      <div class="img-block">        
        <a href=""><img src=".jpg" alt="example image"></a>        
      </div>      
      <p>Image 3</p>      
    </div>
    
    <div class="thumb-grid">
      <div class="img-block">       
        <a href=""><img src=".jpg" alt="example image"></a>        
      </div>      
      <p>Image 4</p>      
    </div>
    
    <div class="thumb-grid">      
      <div class="img-block">        
        <a href=""><img src=".jpg" alt="example image"></a>        
      </div>      
      <p>Image 5</p>      
    </div>
    
    <div class="thumb-grid">      
      <div class="img-block">        
        <a href=""><img src=".jpg" alt="example image"></a>        
      </div>      
      <p>Image 6</p>      
    </div>
    
   <div class="thumb-grid">      
      <div class="img-block">
        <a href=""><img src=".jpg" alt="example image"></a>        
      </div>      
      <p>Image 7</p>      
    </div>
    
  </div>

I am working on an image gallery on a legacy site. I can't use anything other than regular old HTML/jQuery or JS/CSS. I know this would be a lot easier with Bootstrap or some grid library.

I'm building it with flexbox. There are four images in each row, with multiple rows. It looks great when each row has its four images. When it has 2 or 3, because I am using justify-content: space-between, it makes it look weird because of the big gap between the images.

The reason I'm using space-between is that I want the images to align to the left of the parent container, and also to the right.

Some notes:

  • Each flex item has a max-width of 150px
  • I want a margin between items, but I don't care if this margin changes as the viewport width changes
  • the flex container has a max width that only allows four 150px-wide items in a row

My question: if a row has less than a set # of elements (in this case four), can I change the justify-content to be something more appropriate, like flex-start?

Ideally, I want to do this without JavaScript/jQuery, but if that's impossible, I'm open to those solutions as well.

Also, feel free to let me know if I'm way overthinking this and don't even need to use justify-content: space-between. Here's a working example:

/* outer container */
.flex-container {
  padding: 24px 0;
  background: white;
  border: solid 1px rgba(0,0,0,.1);
  max-width: 700px; /* or whatever */
  
  /* flex props */
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
}

/* contains img block and title */
.thumb-grid {
  border: solid 1px rgba(0,0,0,.1);
  width: 150px;
  margin-bottom: 36px;
}

.thumb-grid:first-of-type { margin-left: 0; }
.thumb-grid:nth-of-type(4) { margin-right: 0; }

.thumb-grid p {
  text-align: center;
}

.img-block {
  background: black;
  height: 150px;
}

.img-block img {
  height: 150px;
  opacity: 1;
  transition: opacity 150ms;
}

.img-block:hover img {
  opacity: .9;
}
<div class="flex-container">
    
    <div class="thumb-grid">      
      <div class="img-block">        
        <a href=""><img src="https://www.expedient./wp-content/uploads/2017/06/exp-mq-resouce-thumbnail-1-150x150.jpg" alt="example image"></a>        
      </div>      
      <p>Image 1</p>      
    </div>
    
    <div class="thumb-grid">      
      <div class="img-block">        
        <a href=""><img src="https://www.expedient./wp-content/uploads/2017/06/exp-mq-resouce-thumbnail-1-150x150.jpg" alt="example image"></a>        
      </div>      
      <p>Image 2</p>      
    </div>
    
   <div class="thumb-grid">      
      <div class="img-block">        
        <a href=""><img src="https://www.expedient./wp-content/uploads/2017/06/exp-mq-resouce-thumbnail-1-150x150.jpg" alt="example image"></a>        
      </div>      
      <p>Image 3</p>      
    </div>
    
    <div class="thumb-grid">
      <div class="img-block">       
        <a href=""><img src="https://www.expedient./wp-content/uploads/2017/06/exp-mq-resouce-thumbnail-1-150x150.jpg" alt="example image"></a>        
      </div>      
      <p>Image 4</p>      
    </div>
    
    <div class="thumb-grid">      
      <div class="img-block">        
        <a href=""><img src="https://www.expedient./wp-content/uploads/2017/06/exp-mq-resouce-thumbnail-1-150x150.jpg" alt="example image"></a>        
      </div>      
      <p>Image 5</p>      
    </div>
    
    <div class="thumb-grid">      
      <div class="img-block">        
        <a href=""><img src="https://www.expedient./wp-content/uploads/2017/06/exp-mq-resouce-thumbnail-1-150x150.jpg" alt="example image"></a>        
      </div>      
      <p>Image 6</p>      
    </div>
    
   <div class="thumb-grid">      
      <div class="img-block">
        <a href=""><img src="https://www.expedient./wp-content/uploads/2017/06/exp-mq-resouce-thumbnail-1-150x150.jpg" alt="example image"></a>        
      </div>      
      <p>Image 7</p>      
    </div>
    
  </div>

Share Improve this question edited Sep 7, 2017 at 14:15 kauffmanes asked Sep 6, 2017 at 21:07 kauffmaneskauffmanes 51810 silver badges29 bronze badges 7
  • If you can use JavaScript/jQuery, why can't you use Bootstrap or another library? – TylerH Commented Sep 6, 2017 at 21:36
  • @TylerH It's just overkill for what I need. This is one page in like 50+ on the site. – kauffmanes Commented Sep 6, 2017 at 21:43
  • 1 Possible duplicate of Flex-box: Align last row to grid – cjl750 Commented Sep 6, 2017 at 21:52
  • This answer seems to solve the problem. – cjl750 Commented Sep 6, 2017 at 21:53
  • 1 I updated my question. I don't care about the size of the margins, but I DO want margins. – kauffmanes Commented Sep 7, 2017 at 14:15
 |  Show 2 more ments

5 Answers 5

Reset to default 3

Depending on what you need to support, it might make more sense to use CSS grid layouts (as TylerH pointed out, CSS Grids do not have universal browser support). Check the documentation for further info: https://developer.mozilla/en-US/docs/Web/CSS/CSS_Grid_Layout

.flex-container {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-gap: 10px;
  grid-auto-rows: minmax(100px, auto);
}
<div class="flex-container">
    
    <div class="thumb-grid">      
      <div class="img-block">        
        <a href=""><img src="https://www.expedient./wp-content/uploads/2017/06/exp-mq-resouce-thumbnail-1-150x150.jpg" alt="example image"></a>        
      </div>      
      <p>Image 1</p>      
    </div>
    
    <div class="thumb-grid">      
      <div class="img-block">        
        <a href=""><img src="https://www.expedient./wp-content/uploads/2017/06/exp-mq-resouce-thumbnail-1-150x150.jpg" alt="example image"></a>        
      </div>      
      <p>Image 2</p>      
    </div>
    
   <div class="thumb-grid">      
      <div class="img-block">        
        <a href=""><img src="https://www.expedient./wp-content/uploads/2017/06/exp-mq-resouce-thumbnail-1-150x150.jpg" alt="example image"></a>        
      </div>      
      <p>Image 3</p>      
    </div>
    
    <div class="thumb-grid">
      <div class="img-block">       
        <a href=""><img src="https://www.expedient./wp-content/uploads/2017/06/exp-mq-resouce-thumbnail-1-150x150.jpg" alt="example image"></a>        
      </div>      
      <p>Image 4</p>      
    </div>
    
    <div class="thumb-grid">      
      <div class="img-block">        
        <a href=""><img src="https://www.expedient./wp-content/uploads/2017/06/exp-mq-resouce-thumbnail-1-150x150.jpg" alt="example image"></a>        
      </div>      
      <p>Image 5</p>      
    </div>
    
    <div class="thumb-grid">      
      <div class="img-block">        
        <a href=""><img src="https://www.expedient./wp-content/uploads/2017/06/exp-mq-resouce-thumbnail-1-150x150.jpg" alt="example image"></a>        
      </div>      
      <p>Image 6</p>      
    </div>
    
   <div class="thumb-grid">      
      <div class="img-block">
        <a href=""><img src="https://www.expedient./wp-content/uploads/2017/06/exp-mq-resouce-thumbnail-1-150x150.jpg" alt="example image"></a>        
      </div>      
      <p>Image 7</p>      
    </div>
    
  </div>

How about using margin instead of justify-content:space-between to get the spacing?

/* outer container */
.flex-container {
  padding: 24px 0;
  background: white;
  border: solid 1px rgba(0,0,0,.1);
  max-width: 700px; /* or whatever */
  
  /* flex props */
  display: flex;
  flex-wrap: wrap;
  justify-content:center;
}

/* contains img block and title */
.thumb-grid {
  border: solid 1px rgba(0,0,0,.1);
  width: 150px;
  margin: 0 12px 36px;
}

.thumb-grid:first-of-type { margin-left: 0; }
.thumb-grid:nth-of-type(4) { margin-right: 0; }

.thumb-grid p {
  text-align: center;
}

.img-block {
  background: black;
  height: 150px;
}

.img-block img {
  height: 150px;
  opacity: 1;
  transition: opacity 150ms;
}

.img-block:hover img {
  opacity: .9;
}
<div class="flex-container">
    
    <div class="thumb-grid">      
      <div class="img-block">        
        <a href=""><img src="https://www.expedient./wp-content/uploads/2017/06/exp-mq-resouce-thumbnail-1-150x150.jpg" alt="example image"></a>        
      </div>      
      <p>Image 1</p>      
    </div>
    
    <div class="thumb-grid">      
      <div class="img-block">        
        <a href=""><img src="https://www.expedient./wp-content/uploads/2017/06/exp-mq-resouce-thumbnail-1-150x150.jpg" alt="example image"></a>        
      </div>      
      <p>Image 2</p>      
    </div>
    
   <div class="thumb-grid">      
      <div class="img-block">        
        <a href=""><img src="https://www.expedient./wp-content/uploads/2017/06/exp-mq-resouce-thumbnail-1-150x150.jpg" alt="example image"></a>        
      </div>      
      <p>Image 3</p>      
    </div>
    
    <div class="thumb-grid">
      <div class="img-block">       
        <a href=""><img src="https://www.expedient./wp-content/uploads/2017/06/exp-mq-resouce-thumbnail-1-150x150.jpg" alt="example image"></a>        
      </div>      
      <p>Image 4</p>      
    </div>
    
    <div class="thumb-grid">      
      <div class="img-block">        
        <a href=""><img src="https://www.expedient./wp-content/uploads/2017/06/exp-mq-resouce-thumbnail-1-150x150.jpg" alt="example image"></a>        
      </div>      
      <p>Image 5</p>      
    </div>
    
    <div class="thumb-grid">      
      <div class="img-block">        
        <a href=""><img src="https://www.expedient./wp-content/uploads/2017/06/exp-mq-resouce-thumbnail-1-150x150.jpg" alt="example image"></a>        
      </div>      
      <p>Image 6</p>      
    </div>
    
   <div class="thumb-grid">      
      <div class="img-block">
        <a href=""><img src="https://www.expedient./wp-content/uploads/2017/06/exp-mq-resouce-thumbnail-1-150x150.jpg" alt="example image"></a>        
      </div>      
      <p>Image 7</p>      
    </div>
    
  </div>

For this layout use CSS grid. Your original problem won't even exist then. You won't need any workaround or hacks, JavaScript, or any weird stuff to make it work. With CSS grid layout you'll easily achieve what you need with elegant and maintainable code.

CSS grid layout is a kind of new CSS feature, and it's actually the first legit way of doing layout, which is awesome. Read about it:

  • https://developer.mozilla/en-US/docs/Web/CSS/CSS_Grid_Layout
  • https://css-tricks./snippets/css/plete-guide-grid/

For your case, especially take a look at the auto-fill or auto-fit properties. Here's another useful link: https://gridbyexample./examples/example37/.

And here's a quick example of what you want to achieve using CSS grid: https://codepen.io/anon/pen/YxbexQ?editors=1100. See how it react to different screen/container width. It just works.

Here is a solution you can use with Flexbox, which will provide a wider cross browser solution than CSS Grid can offer (today).

The main trick is to have ghost elements, 1 less than the amount of items per row.

They take up the same horizontal space as a regular item but have no height, and as such will push any number less than 4 to the left.

As we can use the pseudo elements, we in this case only need 1 extra element acting as a ghost

Stack snippet

/* outer container */
.flex-container {
  padding: 24px 0;
  background: white;
  border: solid 1px rgba(0,0,0,.1);
  max-width: 700px; /* or whatever */
  
  /* flex props */
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
}

/* contains img block and title */
.thumb-grid {
  border: solid 1px rgba(0,0,0,.1);
  width: 150px;
  margin-bottom: 36px;
}

.thumb-grid:empty,               /*  the ghost elements  */
.flex-container::before,
.flex-container::after {
  content: '';
  border: solid 1px rgba(0,0,0,0);
  width: 150px;
  margin-bottom: 36px;
  order: 1;
}

.thumb-grid:first-of-type { margin-left: 0; }
.thumb-grid:nth-of-type(4) { margin-right: 0; }

.thumb-grid p {
  text-align: center;
}

.img-block {
  background: black;
  height: 150px;
}

.img-block img {
  height: 150px;
  opacity: 1;
  transition: opacity 150ms;
}

.img-block:hover img {
  opacity: .9;
}
<div class="flex-container">
    
    <div class="thumb-grid">      
      <div class="img-block">        
        <a href=""><img src="https://www.expedient./wp-content/uploads/2017/06/exp-mq-resouce-thumbnail-1-150x150.jpg" alt="example image"></a>        
      </div>      
      <p>Image 1</p>      
    </div>
    
    <div class="thumb-grid">      
      <div class="img-block">        
        <a href=""><img src="https://www.expedient./wp-content/uploads/2017/06/exp-mq-resouce-thumbnail-1-150x150.jpg" alt="example image"></a>        
      </div>      
      <p>Image 2</p>      
    </div>
    
   <div class="thumb-grid">      
      <div class="img-block">        
        <a href=""><img src="https://www.expedient./wp-content/uploads/2017/06/exp-mq-resouce-thumbnail-1-150x150.jpg" alt="example image"></a>        
      </div>      
      <p>Image 3</p>      
    </div>
    
    <div class="thumb-grid">
      <div class="img-block">       
        <a href=""><img src="https://www.expedient./wp-content/uploads/2017/06/exp-mq-resouce-thumbnail-1-150x150.jpg" alt="example image"></a>        
      </div>      
      <p>Image 4</p>      
    </div>
    
    <div class="thumb-grid">      
      <div class="img-block">        
        <a href=""><img src="https://www.expedient./wp-content/uploads/2017/06/exp-mq-resouce-thumbnail-1-150x150.jpg" alt="example image"></a>        
      </div>      
      <p>Image 5</p>      
    </div>
    
    <div class="thumb-grid">      
      <div class="img-block">        
        <a href=""><img src="https://www.expedient./wp-content/uploads/2017/06/exp-mq-resouce-thumbnail-1-150x150.jpg" alt="example image"></a>        
      </div>      
      <p>Image 6</p>      
    </div>
    
   <div class="thumb-grid">      
      <div class="img-block">
        <a href=""><img src="https://www.expedient./wp-content/uploads/2017/06/exp-mq-resouce-thumbnail-1-150x150.jpg" alt="example image"></a>        
      </div>      
      <p>Image 7</p>      
    </div>


   <div class="thumb-grid"></div>

  </div>


If it is max 3 items per row, we only need the pseudo elements

/* outer container */
.flex-container {
  padding: 24px 0;
  background: white;
  border: solid 1px rgba(0,0,0,.1);
  max-width: 550px; /* or whatever */
  
  /* flex props */
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
}

/* contains img block and title */
.thumb-grid {
  border: solid 1px rgba(0,0,0,.1);
  width: 150px;
  margin-bottom: 36px;
}

.flex-container::before, .flex-container::after {
  content: '';
  border: solid 1px rgba(0,0,0,0);
  width: 150px;
  margin-bottom: 36px;
  order: 1;
}


.thumb-grid:first-of-type { margin-left: 0; }
.thumb-grid:nth-of-type(4) { margin-right: 0; }

.thumb-grid p {
  text-align: center;
}

.img-block {
  background: black;
  height: 150px;
}

.img-block img {
  height: 150px;
  opacity: 1;
  transition: opacity 150ms;
}

.img-block:hover img {
  opacity: .9;
}
<div class="flex-container">
    
    <div class="thumb-grid">      
      <div class="img-block">        
        <a href=""><img src="https://www.expedient./wp-content/uploads/2017/06/exp-mq-resouce-thumbnail-1-150x150.jpg" alt="example image"></a>        
      </div>      
      <p>Image 1</p>      
    </div>
    
    <div class="thumb-grid">      
      <div class="img-block">        
        <a href=""><img src="https://www.expedient./wp-content/uploads/2017/06/exp-mq-resouce-thumbnail-1-150x150.jpg" alt="example image"></a>        
      </div>      
      <p>Image 2</p>      
    </div>
    
   <div class="thumb-grid">      
      <div class="img-block">        
        <a href=""><img src="https://www.expedient./wp-content/uploads/2017/06/exp-mq-resouce-thumbnail-1-150x150.jpg" alt="example image"></a>        
      </div>      
      <p>Image 3</p>      
    </div>
    
    <div class="thumb-grid">
      <div class="img-block">       
        <a href=""><img src="https://www.expedient./wp-content/uploads/2017/06/exp-mq-resouce-thumbnail-1-150x150.jpg" alt="example image"></a>        
      </div>      
      <p>Image 4</p>      
    </div>
    
    <div class="thumb-grid">      
      <div class="img-block">        
        <a href=""><img src="https://www.expedient./wp-content/uploads/2017/06/exp-mq-resouce-thumbnail-1-150x150.jpg" alt="example image"></a>        
      </div>      
      <p>Image 5</p>      
    </div>    
    
  </div>


If it can be a dynamic amount of item, like between 3-5, as long as we don't use fewer than 1 less than the max amount, it will work fine.

/* outer container */
.flex-container {
  padding: 24px 0;
  background: white;
  border: solid 1px rgba(0,0,0,.1);
  max-width: 850px; /* or whatever */
  
  /* flex props */
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
}

/* contains img block and title */
.thumb-grid {
  border: solid 1px rgba(0,0,0,.1);
  width: 150px;
  margin-bottom: 36px;
}

.thumb-grid:empty,               /*  the ghost elements  */
.flex-container::before,
.flex-container::after {
  content: '';
  border: solid 1px rgba(0,0,0,0);
  width: 150px;
  margin-bottom: 36px;
  order: 1;
}

.thumb-grid:first-of-type { margin-left: 0; }
.thumb-grid:nth-of-type(4) { margin-right: 0; }

.thumb-grid p {
  text-align: center;
}

.img-block {
  background: black;
  height: 150px;
}

.img-block img {
  height: 150px;
  opacity: 1;
  transition: opacity 150ms;
}

.img-block:hover img {
  opacity: .9;
}
<div class="flex-container">
    
    <div class="thumb-grid">      
      <div class="img-block">        
        <a href=""><img src="https://www.expedient./wp-content/uploads/2017/06/exp-mq-resouce-thumbnail-1-150x150.jpg" alt="example image"></a>        
      </div>      
      <p>Image 1</p>      
    </div>
    
    <div class="thumb-grid">      
      <div class="img-block">        
        <a href=""><img src="https://www.expedient./wp-content/uploads/2017/06/exp-mq-resouce-thumbnail-1-150x150.jpg" alt="example image"></a>        
      </div>      
      <p>Image 2</p>      
    </div>
    
   <div class="thumb-grid">      
      <div class="img-block">        
        <a href=""><img src="https://www.expedient./wp-content/uploads/2017/06/exp-mq-resouce-thumbnail-1-150x150.jpg" alt="example image"></a>        
      </div>      
      <p>Image 3</p>      
    </div>
    
    <div class="thumb-grid">
      <div class="img-block">       
        <a href=""><img src="https://www.expedient./wp-content/uploads/2017/06/exp-mq-resouce-thumbnail-1-150x150.jpg" alt="example image"></a>        
      </div>      
      <p>Image 4</p>      
    </div>
    
    <div class="thumb-grid">      
      <div class="img-block">        
        <a href=""><img src="https://www.expedient./wp-content/uploads/2017/06/exp-mq-resouce-thumbnail-1-150x150.jpg" alt="example image"></a>        
      </div>      
      <p>Image 5</p>      
    </div>
    
    <div class="thumb-grid">      
      <div class="img-block">        
        <a href=""><img src="https://www.expedient./wp-content/uploads/2017/06/exp-mq-resouce-thumbnail-1-150x150.jpg" alt="example image"></a>        
      </div>      
      <p>Image 6</p>      
    </div>
    
   <div class="thumb-grid">      
      <div class="img-block">
        <a href=""><img src="https://www.expedient./wp-content/uploads/2017/06/exp-mq-resouce-thumbnail-1-150x150.jpg" alt="example image"></a>        
      </div>      
      <p>Image 7</p>      
    </div>


   <div class="thumb-grid"></div>
   <div class="thumb-grid"></div>

  </div>

This can be done now with CSS only using a base justify-content setting with overrides using nth-of-type() to manage the number of items, has() and not() to manage the number range to select. This could be used for dynamically populated flex containers where you don't know the number of items, but you do know that one or two items should be justify-center, but more than that should be space-between or other.

HTML:

<div class="flex-container">
    <div class="item">1</div>
    <div class="item">2</div>
    <div class="item">3</div>
    <div class="item">4</div>
    <div class="item">5</div>
<div>

CSS:

.flex-container {
    display: flex;
    justify-content: space-between;
}
.flex-container:has(.item:nth-of-type(3)):not(:has(.item:nth-of-type(4))) {
    justify-content: space-around;
}
.flex-container:has(.item:nth-of-type(2)):not(:has(.item:nth-of-type(3))) {
    justify-content: space-evenly;
}
.flex-container:has(.item:nth-of-type(1)):not(:has(.item:nth-of-type(2))) {
    justify-content: center;
}

This uses the :has() pseudo-class to check if the container has a certain number of items and then adjusts justify-content accordingly.

Uses :not() to ensure the correct number of items is matched without accidentally overlapping.

Browser Support The :has() and :not() pseudo-classes are supported in almost all major browsers at the time of this writing according to https://caniuse./css-has https://caniuse./css-not-sel-list

本文标签: