How to create perfect css squares in flexbox without using :after

Viewed 60

There seems to be a problem in this next piece of code. Testing on Chrome, there is a difference of just .5 px between height and width, but when switching to device mode, the difference gets bigger (almost 10px). I do have a <meta name="viewport" content="width=device-width, initial-scale=1.0"> set.

What I need: perfect squares and perfect circles. Flexbox is used and I don't want this :after fix used to create perfect squares. What am I doing wrong?

body {
    max-inline-size: 1440px;
    margin: 0 auto;
}

.oc {
    display: flex;
    justify-content: flex-start;
}

.ic {
    display: flex;
    flex-direction: column;
    justify-content: flex-start;
    align-items: stretch;
    flex-grow: 1;
}

.lc {
    display: flex;
    justify-content: stretch;
    align-items: stretch;
    border-radius: 25%;
    border: solid 1px black;
    margin: 1px;
    padding: 20px;
    flex: 1;
    block-size: calc(50vw - 52px);
}

.abc {
    font-size:90px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    border: solid 1px black;
    flex-grow: 1;
}

@media screen and (min-width: 768px) {
    .abc {
        font-size: 180px;
    }
    
}

@media screen and (min-width: 1024px) {
    .oc {
        flex-wrap: wrap;
    }

    .ic {
        flex-direction: row;
        flex-basis: 100vw;
    }

    .lc {
        block-size: calc(33vw - 46px);
    }
}

@media screen and (min-width: 1440px) {
    .lc {
        block-size: calc((1440px / 3) - 46px);
    }
}
<div class="oc">
   <div class="ic">
      <div class="lc">
         <div class="abc">A</div>
      </div>
      <div class="lc">
         <div class="abc">B</div>
      </div>
      <div class="lc">
         <div class="abc">C</div>
      </div>
   </div>

   <div class="ic">
      <div class="lc">
         <div class="abc">A</div>
      </div>
      <div class="lc">
         <div class="abc">B</div>
      </div>
      <div class="lc">
         <div class="abc">C</div>
      </div>
   </div>
</div>

1 Answers

Not sure why you don't want to use the padding trick but it's the way to go. Your calculation won't be accurate using vw unit because you need to account for the scrollbar width

body {
  max-inline-size: 1440px;
  margin: 0 auto;
}

.oc {
  display: flex;
  justify-content: flex-start;
}

.ic {
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  align-items: stretch;
  flex-grow: 1;
}

.lc {
  display: flex;
  justify-content: stretch;
  align-items: stretch;
  border-radius: 25%;
  border: solid 1px black;
  margin: 1px;
  padding: 20px;
  flex: 1;
}
/* this will do the trick */
.lc .abc::before {
  content:"";
  padding-top:100%;
}
/**/
.abc {
  font-size: min(90px,18vw);
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  border: solid 1px black;
  flex-grow: 1;
}

@media screen and (min-width: 768px) {
  .abc {
    font-size: 180px;
  }
}

@media screen and (min-width: 1024px) {
  .oc {
    flex-wrap: wrap;
  }
  .ic {
    flex-direction: row;
    flex-basis: 100vw;
  }
}
<div class="oc">
  <div class="ic">
    <div class="lc">
      <div class="abc">A</div>
    </div>
    <div class="lc">
      <div class="abc">B</div>
    </div>
    <div class="lc">
      <div class="abc">C</div>
    </div>
  </div>

  <div class="ic">
    <div class="lc">
      <div class="abc">A</div>
    </div>
    <div class="lc">
      <div class="abc">B</div>
    </div>
    <div class="lc">
      <div class="abc">C</div>
    </div>
  </div>
</div>

If you insist on using vw you need to adjust the code like below. Notice how you will have perfect square but I had to hide the scrollbar to get the result:

body {
  max-inline-size: 1440px;
  margin: 0 auto;
  overflow:hidden;
}

.oc {
  display: flex;
  justify-content: flex-start;
}

.ic {
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  align-items: stretch;
  flex-grow: 1;
}

.lc {
  display: flex;
  justify-content: stretch;
  align-items: stretch;
  border-radius: 25%;
  border: solid 1px black;
  margin: 1px;
  padding: 20px;
  flex: 1;
  block-size: calc(50vw - 2px); /* remove only margin */
  box-sizing:border-box; /* you don't have to care about padding and border*/
}

.abc {
  font-size: 90px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  border: solid 1px black;
  flex: 1;
}

@media screen and (min-width: 768px) {
  .abc {
    font-size: 180px;
  }
}

@media screen and (min-width: 1024px) {
  .oc {
    flex-wrap: wrap;
  }
  .ic {
    flex-direction: row;
    flex-basis: 100vw;
  }
  .lc {
    block-size: calc(calc(100vw/3) - 2px);
  }
}

@media screen and (min-width: 1440px) {
  .lc {
    block-size: calc((1440px / 3) - 2px);
  }
}
<div class="oc">
  <div class="ic">
    <div class="lc">
      <div class="abc">A</div>
    </div>
    <div class="lc">
      <div class="abc">B</div>
    </div>
    <div class="lc">
      <div class="abc">C</div>
    </div>
  </div>

  <div class="ic">
    <div class="lc">
      <div class="abc">A</div>
    </div>
    <div class="lc">
      <div class="abc">B</div>
    </div>
    <div class="lc">
      <div class="abc">C</div>
    </div>
  </div>
</div>

Related