0

I'm try to build a table such that

  • All cells have the same size and square shape.
  • Cell size is independent from the cell content.
  • Cell content is horizontally and vertically centered in the cell.

For example, see the following image

enter image description here

I edited the code found here Make table cells square to obtain an output similar to the previous image.

body { font-size: 1.5em; }
table {
    width: 180px; /* fixed table width */
    margin: auto;
    border-collapse: collapse;
}
td, th {
    width: 33%; /* each cell has 1/3 of the total width */
    position: relative;
    border: 1px solid;
    text-align: center; /* content is horizontally centered */
}
th { background: yellow; }
td:before, th:before {
    content: '';
    display: block;
    margin-top: 30%; /* attempt to center the content vertically */
}
td:after, th:after {
    content: '';
    display: block;
    margin-top: 100%; /* set the height of the cell */
}
td div, th div {
    position: absolute;
    left: 0;
    right: 0;
}
th div { color: red; }
<table>
    <tr>
        <th><div>+</div></th>
        <th><div>0</div></th>
        <th><div>1</div></th>
    </tr><tr>
        <th><div>0</div></th>
        <td><div>0</div></td>
        <td><div>1</div></td>
    </tr><tr>
        <th><div>1</div></th>
        <td><div>1</div></td>
        <td><div>10</div></td>
    </tr>
</table>

The result is quite similar to the previous image, but if the either the table width or the font-size are changed, then the vertical centering is messed up.

I think the only problem is the verical centering. As you can see from the code I made an attempt to center the content vertically by manually setting margin-top: 30%. But this value needs to be changed accordingly to the table width and the font-size.

Is it possible to automatically center the content vertically?

sound wave
  • 390
  • 2
  • 13
  • 2
    There's a [`vertical-align`](https://developer.mozilla.org/en-US/docs/Web/CSS/vertical-align) property you can use on table cells... I would remove all of the positioning code in there though. – Heretic Monkey Dec 02 '19 at 18:43

2 Answers2

1

Use css3 flexbox

body {
  font-size: 1.5em;
}

table {
  width: 180px;
  margin: auto;
  border-collapse: collapse;
}

td,
th {
  width: 33%;
  height: 100px;
  border: 1px solid;
}

th div,
td div {
  display: flex;
  align-items: center;
  justify-content: center;
}

th {
  background: yellow;
}

th div {
  color: red;
}
<table>
  <tr>
    <th>
      <div>+</div>
    </th>
    <th>
      <div>0</div>
    </th>
    <th>
      <div>1</div>
    </th>
  </tr>
  <tr>
    <th>
      <div>0</div>
    </th>
    <td>
      <div>0</div>
    </td>
    <td>
      <div>1</div>
    </td>
  </tr>
  <tr>
    <th>
      <div>1</div>
    </th>
    <td>
      <div>1</div>
    </td>
    <td>
      <div>10</div>
    </td>
  </tr>
</table>
Naresh
  • 810
  • 1
  • 12
  • 31
1

I'd simplify the code. I've removed a lot the positioning code and other stuff in favor of simple table properties. I'm using CSS Variables here so that it's easier to demonstrate changing the values, but you needn't use them if you need to support Internet Explorer, for instance.

I also added some code that increases the size of the table and its font when you click to show the centering works at a variety of sizes.

var fontSize = '1.5';
document.body.addEventListener('click', () => {
  var css = fontSize === '1.5' ?
    '--table-size: 300px; --font-size: 4rem;' :
    '--table-size: 180px; --font-size: 1.5rem;';
  fontSize = fontSize === '1.5' ? '4' : '1.5';
  document.documentElement.style.cssText = css;
});
:root {
  --table-size: 180px;
  --font-size: 1.5rem;
}

table {
  width: var(--table-size);
  height: var(--table-size);
  margin: auto;
  border-collapse: collapse;
  font-size: var(--font-size);
}

td,
th {
  border: 1px solid;
  text-align: center;
  vertical-align: middle;
  white-space: nowrap;
  width: calc(var(--table-size) / 3);
  max-width: calc(var(--table-size) / 3);
  max-height: calc(var(--table-size) / 3);
  overflow: hidden;
}

th {
  background: yellow;
}

th div {
  color: red;
}
<table>
  <tr>
    <th>
      <div>+</div>
    </th>
    <th>
      <div>0</div>
    </th>
    <th>
      <div>1</div>
    </th>
  </tr>
  <tr>
    <th>
      <div>0</div>
    </th>
    <td>
      <div>0</div>
    </td>
    <td>
      <div>1</div>
    </td>
  </tr>
  <tr>
    <th>
      <div>1</div>
    </th>
    <td>
      <div>1</div>
    </td>
    <td>
      <div>10</div>
    </td>
  </tr>
</table>
Heretic Monkey
  • 10,498
  • 6
  • 45
  • 102
  • Your code is simpler and clear to understand, thank you very much! – sound wave Dec 02 '19 at 22:38
  • If I need to place several of these square tables in a single page but each table has different sizes, what is the best way to do it? The first thing that comes to mind, is to create a class for each table, such as `.table130`, `.table150`, etc. (where 130 and 150 are the sizes of the tables), but this seems a bad practice to me. How to do it properly? Thanks – sound wave Dec 03 '19 at 08:50
  • p.s. I think it is better to remove `width: 180px` and `height: 180px` from the `table`, and add `height: calc(180px / 3)` to `td, th` – sound wave Dec 03 '19 at 09:19
  • What do you think about the third comment? – sound wave Dec 03 '19 at 21:22
  • 1
    Sorry, busy with paying work ;). I prefer naming classes more organically, so if there's a reason one table is smaller than another (it's less important, or it represents a different set of data), I'd use that information to name it. Even `table-sm`, `table-md`, etc. make more sense to me. That said, I'm in the minority in that opinion, and many developers use classes like `table130`, `pd-5`, etc., with no compunctions (you see this in Bootstrap's utility classes for instance). It's really up to you. I don't think it's a bad practice, just a different one. – Heretic Monkey Dec 04 '19 at 14:02