5

I'm trying to make a grid of resizable squares with some text inside them. Here's the code:

/* Dirty quick CSS reset */
*,
*::before,
*::after {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

.container {
  display: flex;
  flex-flow: column;
  flex: 1;
  background: aliceblue;
}

.row {
  display: flex;
  flex: 1;
}

.square {
  border: 1px solid black;
    
  width: 14.2857%; /* 100% / 7 */
  font-size: 18px;
  padding: 8px;
  
  /* square-width - font-size - padding-top */
  padding-bottom: calc(14.2857% - 18px - 8px);
}
<div class="container">
  <div class="row">
    <div class="square">1</div>
    <div class="square">2</div>
    <div class="square">3</div>
    <div class="square">4</div>
    <div class="square">5</div>
    <div class="square">6</div>
    <div class="square">7</div>
  </div>
</div>

As we can see, there's a row of squares that adapt to the size of the window. The problem is that if we inspect them, we see that they aren't totally squares (they are about 3px taller than wide). It gets worse if we increase the font-size, and as far as I know, the maths is correct.

What's going on here? Why am I getting those extra pixels?

amedina
  • 2,838
  • 3
  • 19
  • 40
  • I would expect it to be a rounding issue with the percentage based on the fact you say it gets worse as they get larger. – DrCord Aug 22 '18 at 18:44
  • Adding `line-height: 1` helps but not perfect – Huangism Aug 22 '18 at 18:48
  • 1
    I am not sure why yet but it seems to work at all sizes if you use `padding-bottom: calc(14.2857% - 18px - 10px);` – DrCord Aug 22 '18 at 18:51
  • Add `line-height` equal to the font size, subtract the top and the bottom border from `padding-bottom`. – Alexey Lebedev Aug 22 '18 at 18:55
  • border makes sense why adding 2 more pixels to the subtraction fixes it, as far as I can tell you don't need line height though, works without it fine for me. – DrCord Aug 22 '18 at 18:56
  • I tried adding the two pixels before, with different sizes but it doesn't always work. I tried specifying a bunch of decimals too, but it doesn't solve it. What drives me crazy is that I don't know why it happens. – amedina Aug 22 '18 at 18:59
  • `box-sizing: border-box` is defined for everything, so borders should of been included but apparently not – Huangism Aug 22 '18 at 19:00
  • @amedina because there is rounding – Huangism Aug 22 '18 at 19:00
  • If I change `box-sizing` to `content-box` happens the same. – amedina Aug 22 '18 at 19:03
  • @DrCord line-height is actually very important, because the height of the line is usually not equal to the font size. Example: http://jsfiddle.net/nr2oyfaL/ – Alexey Lebedev Aug 22 '18 at 19:03
  • @LGSon the duplicate provides good solution on how to obtain this but I don't think it provide the answer for the *why* here because it's important to understand the difference between the line-height and font-size [unless the OP only want the desired effect without explanation] – Temani Afif Aug 22 '18 at 19:23
  • @TemaniAfif The _why_ is given in below answer :) ...and the dupe's provide many _how-to_ – Asons Aug 22 '18 at 19:25

3 Answers3

3

I encountered this problem a while ago, and was able to solve it through this solution by using Pseudo element

/* Dirty quick CSS reset */

*,
*::before,
*::after {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

.container {
  display: flex;
  flex-flow: column;
  flex: 1;
  background: aliceblue;
}

.row {
  display: flex;
  flex: 1;
}

.square {
  border: 1px solid black;
  width: 14.2857%;
  /* 100% / 7 */
  font-size: 18px;
  padding: 8px;
}

.square:before {
  content: '';
  float: left;
  padding-top: 100%;
}
<div class="container">
  <div class="row">
    <div class="square">1</div>
    <div class="square">2</div>
    <div class="square">3</div>
    <div class="square">4</div>
    <div class="square">5</div>
    <div class="square">6</div>
    <div class="square">7</div>
  </div>
</div>
Dhaval Jardosh
  • 7,151
  • 5
  • 27
  • 69
  • Wow, can you explain why it works? – amedina Aug 22 '18 at 19:07
  • 1
    Self explanatory, the pseudo element set to 100% padding top which is the same as your width percentage without all the calculation. You could also just put an element in your square if you don't want to use pseudo element – Huangism Aug 22 '18 at 19:20
2

The exact calculation should be (14.2857% - 8px - 2px - Lpx) we remove the padding-top and the border and the line-height (not the font-size), so you should know the value of the line-height or you set it:

/* Dirty quick CSS reset */
*,
*::before,
*::after {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

.container {
  display: flex;
  flex-flow: column;
  flex: 1;
  background: aliceblue;
}

.row {
  display: flex;
  flex: 1;
}

.square {
  border: 1px solid black;
    
  width: 14.2857%; /* 100% / 7 */
  font-size: 18px; 
  line-height:1em; /*equal to font-size*/
  padding: 8px;
  
  /* square-width - font-size - padding-top */
  padding-bottom: calc(14.2857% - 8px - 2px - 18px);
}
<div class="container">
  <div class="row">
    <div class="square">1</div>
    <div class="square">2</div>
    <div class="square">3</div>
    <div class="square">4</div>
    <div class="square">5</div>
    <div class="square">6</div>
    <div class="square">7</div>
  </div>
</div>

If we refer to the documentation the line-height is the value that define the height of the lines and the default value is set to normal:

The line-height CSS property sets the amount of space used for lines, such as in text.

And

normal

Depends on the user agent. Desktop browsers (including Firefox) use a default value of roughly 1.2, depending on the element's font-family.

As you can see the line-height is not necessarily equal to font-size

Temani Afif
  • 245,468
  • 26
  • 309
  • 415
  • It's kind of equivalent to having into account the `font-size`, and the border shouldn't count anyway. Maybe part of the "secret" is establishing the `line-height` explicitly. – amedina Aug 22 '18 at 19:18
  • 1
    @amedina yes because font-size define the line-height but it doesn't make it equal and it will depend in the font-family ... so if you know the line-height you have the good calculation ... check my update, you can use 1em unit to make it more flexible ;) – Temani Afif Aug 22 '18 at 19:21
0

Accounting for the 2px from the border fixed it for me:

padding-bottom: calc(14.2857% - 18px - 10px);

/* Dirty quick CSS reset */
*,
*::before,
*::after {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

.container {
  display: flex;
  flex-flow: column;
  flex: 1;
  background: aliceblue;
}

.row {
  display: flex;
  flex: 1;
}

.square {
  border: 1px solid black;
    
  width: 14.2857%; /* 100% / 7 */
  font-size: 1em;
  padding: 8px;
  
  /* square-width - font-size - padding-top */
  padding-bottom: calc(14.2857% - 18px - 10px);
}
<div class="container">
  <div class="row">
    <div class="square">1</div>
    <div class="square">2</div>
    <div class="square">3</div>
    <div class="square">4</div>
    <div class="square">5</div>
    <div class="square">6</div>
    <div class="square">7</div>
  </div>
</div>
DrCord
  • 3,917
  • 3
  • 34
  • 47