1

I would like to, once having an HTML table, be able to take a group of cells and write a text (in this case, a single character) centered both vertically and horizontally across that group of cells, just as in the image below.

HTML table centered text

I have explored the possibility of writing the text in the first (top-left) td and then use the overflow CSS property over that td element in order for the text to go over the limits of the td. However, this would not work for centering the text vertically (across tr).

Is there any way to do this just using a simple HTML table and CSS, or should I consider using a canvas in order to overlap a text over the table?

dsesto
  • 7,864
  • 2
  • 33
  • 50
  • 2
    Can you provide what code you've already written, please? – KidBilly Dec 21 '18 at 15:07
  • A few questions. #1 Does the text need to live inside the table, semantically? #2 will the group of cells always be the entire table or always just a portion of the table or either is possible? #3 will the table have content in it and the text will be superimposed on top of it? – T Nguyen Dec 21 '18 at 15:27
  • #1 no need for the text to be part of the table, it can be a different element (I've though of using two overlapped tables and play with `position`) #2 the group of cells can be just a portion of the table. – dsesto Dec 21 '18 at 15:32
  • To provide a proper answer we need to know any edge case were e.g. the cells might be unequal sized, dynamic amount of cells/rows etc. Provide a [mcve] to make it all more clear. – Asons Dec 21 '18 at 16:52
  • @LG. I just realized your answer ***was correct***. And it has ***nothing*** to do with tables. Change the `` with an `` and this question was asked 1000 times. It's not about centering over a group of cells (which is what I answered), but centering over the entire `
    `. Therefore closing as duplicate.
    – tao Dec 21 '18 at 19:16
  • @AndreiGheorghiu Read the 3rd comment, p. 2#, written by OP saying otherwise :) ... still, in #1 they say _"using two overlapped tables and play with position"_, which make the dupe fine too. – Asons Dec 22 '18 at 08:11

2 Answers2

4

Solution 1:
Use rowspan and colspan, together with valign and align (which are specific <table> centering attributes):

td {
  border: 1px solid #eee;
  padding: 1rem;
}
td[rowspan] {
  background-color: rgba(255,0,0,.07);
  border: 1px solid red;
}
<table>
   <tr>
     <td rowspan="2" colspan="2" valign="center" align="center">
     A
     </td>
     <td>x</td>
   </tr>
   <tr>
    <td>x</td>
  </tr>
  <tr>
    <td>x</td>
    <td>x</td>
    <td>x</td>
  </tr>

Solution 2:
The hacky way I was describing in the comment:

td {
  border: 1px solid #eee;
  padding: 1rem;
}
.hacky-td {
  position: relative;
  overflow: visible;
}
.hacky-content {
  font-size: 3rem;
  position: absolute;
  transform: translate(-50%,-50%);
  border: 1px solid red;
  padding: 1rem;
  background-color: rgba(255,0,0,.07);
  left: -1px; /* should be 0, it's 1 because of the border */
  top: -1px; /* should be 0, it's 1 because of the border */
}
<table>
   <tr>
     <td></td>
     <td></td>
     <td>x</td>
   </tr>
   <tr>
     <td></td>
     <td class="hacky-td"><div class="hacky-content">A</div></td>
     <td>Lorem<br>ipsum,<br>dolor<br>sit<br>amet</td>
  </tr>
  <tr>
    <td>x</td>
    <td>Lorem ipsum, dolor sit amet</td>
    <td>x</td>
  </tr>

You'll notice the A will remain centered on the junction regardless of the size of each of the 4 cells.


Solution 3: - CSS Grid
If you want to center across the entire area, you'll have to use CSS grid, which makes it kind of trivial:

.grid {
  display: grid;
  grid-template: 
    "a b c" auto
    "d e f" auto
    "g h i" auto
    /1fr 2fr 1fr;
    grid-gap: 2px;
}
.grid > *:not(.overlay) {
  padding: 1rem;
  content: 'x';
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid #eee;
}
.a { grid-area: a;}
.b { grid-area: b;}
.c { grid-area: c;}
.d { grid-area: d;}
.e { grid-area: e;}
.f { grid-area: f;}
.g { grid-area: g;}
.h { grid-area: h;}
.i { grid-area: i;}
.overlay {
  grid-area: 1/1/3/3;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: .5rem;
}
.overlay span {
  border: 1px solid red;
  font-size: 3rem;
  font-weight: bold;
  background-color: rgba(255,0,0,.07);
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}
<div class="grid">
  <div class="a">x</div>
  <div class="b">Lorem<br>ipsum<br>dolor<br>sit<br>amet</div>
  <div class="c">x</div>
  <div class="d">x</div>
  <div class="e">x</div>
  <div class="f">x</div>
  <div class="g">x</div>
  <div class="h">Amet sit door ipsum lorem, ipsum dolor sit amet.</div>
  <div class="i">x</div>
  <div class="overlay"><span>A</span></div>
</div>

Solution 4: - Centering across the entire table

This one's a general centering method and it works with anything (you could put any other element instead of the <table>):

.relative {
  position: relative;
  display: inline-block;
}
.overlay {
  position: absolute;
  top: 0.5rem;
  bottom: 0.5rem;
  left: 0.5rem;
  right: 0.5rem;
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: rgba(255,0,0,.07);
  font-size: 2.4rem;
  border: 1px solid red;
}
td {
  padding: 1rem;
  border: 1px solid #eee;
}
<div class="relative">
  <table>
    <tr>
      <td>x</td>
      <td>x</td>
      <td>x</td>
    </tr>
    <tr>
      <td>x</td>
      <td>x</td>
      <td>x</td>
    </tr>
    <tr>
      <td>x</td>
      <td>x</td>
      <td>x</td>
    </tr>
  </table>
  <div class="overlay">
    A
  </div>
</div>
tao
  • 82,996
  • 16
  • 114
  • 150
  • The thing is, I would like to keep the cells as they are, i.e. in my left image keep a total of 4 `td`. I would like this for two reasons: 1) I need all the borders (including internal borders) to be displayed; 2) I need to have the 4 `td` because they have unique IDs and I need to operate with them. – dsesto Dec 21 '18 at 15:20
  • You can't have the cake and eat it, too, @dsesto. There is no way to achieve that with CSS and HTML alone. One way or another you'll need JavaScript (either to get size of and mimic the "cells" inside the rowspan/colspan element or to use one of the cells and overflow its contents above the others. Actually, there would be a hacky way to do it. Place content in a cell near the middle and using `transform: translate(-50%, -50%)` make it shift let and top by half of its size. You'll also need to give it a wrapper with negative left and top margin according to td's padding and margin. Would work. – tao Dec 21 '18 at 15:25
  • @AndreiGheorghiu It is as simple a position it absolute with the table as relative ancestor and then transform it into the center...posted an answer: https://stackoverflow.com/a/53887567/2827823 – Asons Dec 21 '18 at 16:08
  • @LGSon, not if you want it centered across unequally sized rows/columns. Which is where CSS grid comes in handy. – tao Dec 21 '18 at 16:09
  • Well, now we are not talking about that, as OP asked about HTML Table, and with images showed they are equally sized, but of course, one can also twist anything into not work if one want to. – Asons Dec 21 '18 at 16:13
  • @LGSon, I took it as an exercise and wanted to provide solution(s) that would work in as many cases as possible. Not for OP, but for future users, with similar issue/request. Do you really believe the assumption rows and columns might have various size depending on content and/or device is such an edge case it shouldn't have been considered? – tao Dec 21 '18 at 16:18
  • I believe to not answer questions not asked, and in this case OP haven't shown any info saying anything but an equal grid. Still, this can be easily done with HTML Table/CSS, so I updated my answer to show that, and here's the fiddle: https://jsfiddle.net/o83kz46f/ – Asons Dec 21 '18 at 16:44
  • I decided to delete my answer as the question is too unclear when it comes to how the markup actually looks like, and if there are any constraint etc. Posted a comment at the question asking the OP to be more clear. – Asons Dec 21 '18 at 16:54
1

There may be a better way to do this. But when you're overlaying elements, things get messy because you need to use absolute positioning. Anyway, here's some code and an example to get you started.

I don't know what your exact situation is, but you can dynamically get the dimensions you need with JavaScript to set the CSS on the fly.

https://codepen.io/anon/pen/xmqPbo

HTML

<span id="table-overlay-text-2">B</span> 
<span id="table-overlay-text-1">A</span> 
<table id="table1">
  <tr>
    <td></td>
    <td></td>
  </tr>
  <tr>
    <td></td>
    <td></td>
  </tr>
</table>
<br />

<table id="table1">
  <tr>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
  </tr>
  <tr>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
  </tr>
  <tr>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
  </tr>
</table>

CSS

#table1 td, #table2 td{
  border: 1px solid black;
  height: 75px;
  width: 75px;
}

#table-overlay-text-1{
    font-size:50px;
    position: absolute;
    z-index:2;
    margin-top: 50px;
    margin-left: 65px;
}

#table-overlay-text-2{
    font-size:50px;
    position: absolute;
    z-index:2;
    margin-top: 275px;
    margin-left: 140px;
}
KidBilly
  • 3,408
  • 1
  • 26
  • 40
  • 1
    Don't use hard-coded margins. The point is: you don't know the height or the width of the columns or rows. They could contain nothing or they could contain a whole paragraph. You don't want to have to modify the CSS when the content changes. You need to separate the concerns. – tao Dec 21 '18 at 15:41
  • There's no information in the post about that. Maybe he will always know the size of the cells. We don't know why he needs this or where he'll use it. There's no context to the question. If he wants better answers, need to include more context in the question. – KidBilly Dec 21 '18 at 15:45
  • 1
    I'm saying: designing *any* element in terms of hard-coded size in pixels is generally regarded as a poor coding decision. Chances are there will be devices out there which won't render it correctly. One should strive to provide solutions as flexible as possible. – tao Dec 21 '18 at 16:06
  • No I totally agree with you. Which is why I mentioned at the top that there's a better way to do it. – KidBilly Dec 21 '18 at 17:08