Home > OS >  Flexbox - image columns with fixed margins: how to get even image widths
Flexbox - image columns with fixed margins: how to get even image widths

Time:10-06

I have a design with images in columns with a fixed margin (or gap) between them. Right now the columns have margins, and because the total margin is different for each column (since there is no left margin on the first column and no right margin on the last), the width of each column image becomes different, causing the height to be different on the middle images. enter image description here

I tried to divide the margin so that each column uses the same total amount of margin (which seems instinctively over complicated) . I can get that to work, but it doesn't work for 3 columns. You can't make three columns use the same amount of margin I think.

I know there is some "gap" property in css grid, but how do I solve it in flexbox?

See my example code here: example

<template>
  <div id="app">
    <div class="row">
      <div class="col-3">
        <div>
          <img
            src="https://images.unsplash.com/photo-1633357337538-83612701c7a9?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=1470&q=80"
          />
        </div>
      </div>
      <div class="col-3">
        <div>
          <img
            src="https://images.unsplash.com/photo-1633357337538-83612701c7a9?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=1470&q=80"
          />
        </div>
      </div>
      <div class="col-3">
        <div>
          <img
            src="https://images.unsplash.com/photo-1633357337538-83612701c7a9?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=1470&q=80"
          />
        </div>
      </div>
      <div class="col-3">
        <div>
          <img
            src="https://images.unsplash.com/photo-1633357337538-83612701c7a9?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=1470&q=80"
          />
        </div>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: "App",
  components: {},
};
</script>

<style lang="scss">
#app {
  margin: 0 auto;
  width: 800px;
  border: 3px solid orange;
}

.row {
  display: flex;
  box-sizing: border-box;
  display: flex;
  flex-grow: 0;
  flex-shrink: 1;
  flex-direction: row;
  flex-wrap: wrap; 
  img {
    width: 100%;
    object-fit: cover;
  }
}
.col-3 {
  flex: 0 1 25%;
  max-width: 25%;
  /* width:25%; */
  > div {
    /* margin-right:25px; */
  }
  &:first-child > div {
    margin-right: 12.5px;
  }
  &:nth-child(2) > div {
    margin-right: 12.5px;
    margin-left: 12.5px;
  }
  &:nth-child(3) > div {
    margin-right: 12.5px;
    margin-left: 12.5px;
  }
  &:last-child > div {
    margin-left: 12.5px;
  }
}
#app {
  font-family: "Avenir", Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

CodePudding user response:

Update: I realise now that you're looking for a solution using flex rather than css grid. The other answer provides some options there. If you do want to use grid though this approach is handy as your widths will be automatically calculated with whatever gap you choose.

Use display:grid, and set your container to have four columns with one fractional unit for each column, and a column-gap of the gap you want.

The gap below the image is caused because by default images are inline elements, so they sit with the baseline of text. If you set your images to display:block the gap will disappear.

.row {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-column-gap: 12px;
  column-gap: 12px;
  border:3px solid yellow;
}

.col-3 {
  width: 100%;
}

.col-3 img {
  display: block;
  width: 100%;
  object-fit: cover;
}
<div class="row">
  <div class="col-3">
    <img src="https://images.unsplash.com/photo-1633357337538-83612701c7a9?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=1470&q=80" />
  </div>
  <div class="col-3">
    <img src="https://images.unsplash.com/photo-1633357337538-83612701c7a9?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=1470&q=80" />
  </div>
  <div class="col-3">
    <img src="https://images.unsplash.com/photo-1633357337538-83612701c7a9?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=1470&q=80" />
  </div>
  <div class="col-3">
    <img src="https://images.unsplash.com/photo-1633357337538-83612701c7a9?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=1470&q=80" />
  </div>
</div>

CodePudding user response:

I have written the code using flexbox and made a little change to your HTML code

<template>
  <div id="app">
    <div class="row">
      <div>
        <img
          src="https://images.unsplash.com/photo-1633357337538-83612701c7a9?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=1470&q=80"
        />
      </div>

      <div>
        <img
          src="https://images.unsplash.com/photo-1633357337538-83612701c7a9?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=1470&q=80"
        />
      </div>

      <div>
        <img
          src="https://images.unsplash.com/photo-1633357337538-83612701c7a9?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=1470&q=80"
        />
      </div>

      <div>
        <img
          src="https://images.unsplash.com/photo-1633357337538-83612701c7a9?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=1470&q=80"
        />
      </div>
    </div>
  </div>
</template>

    <style lang="scss">
    body {
      margin: 0;
      .row {
        display: flex;
        width: 100%;
        justify-content: space-between;
        div {
          padding: 0 10px;
          &:nth-child(1) {
            padding-left: 0;
          }
          &:nth-last-child(1) {
            padding-right: 0;
          }
          img {
            width: 100%;
          }
        }
      }
    }
    </style>

CodePudding user response:

Flexbox does have a gap property that will space your items evenly and won't create empty spaces on the right or left. But, based on the code sample you shared, I think your issue is a combination of a couple of things:

  1. Your middle two containers are smaller than your outer two containers because of their extra margin
  2. Your images are set to take the full width of their containers

Because the middle two containers are smaller—and the images are preserving their aspect ratio—you get images that are both narrower and shorter.

If you strip everything down to just using gap, I think you'll be a lot closer to what you're trying to accomplish:

.flexbox {
  background-color: #ace;
  border: 3px solid orange;
  box-sizing: border-box;
  display: flex;
  flex-flow: row nowrap;
  gap: 8px;
  width: 800px;
}

.container {
  flex: 0 1 25%;
  margin: 0;
  max-width: 25%;
}

img.full-width {
  width: 100%
}
<div class="flexbox">
  <div class="container">
    <img class="full-width" src="https://picsum.photos/300/200" />
  </div>
  <div class="container">
    <img class="full-width" src="https://picsum.photos/300/200" />
  </div>
  <div class="container">
    <img class="full-width" src="https://picsum.photos/300/200" />
  </div>
  <div class="container">
    <img class="full-width" src="https://picsum.photos/300/200" />
  </div>
</div>

  • Related