Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using CSS, how to create a two-column grid with equal-width columns that are "only as narrow as required"?

Tags:

css

Assuming I have a piece of HTML that is structured like this:

<!-- MY ACTUAL HTML -->

<div class="linkgrid">
  <div class="gridentry">
    <a href="#">Loooooooooooooong</a>
  </div>
  <div class="gridentry">
    <a href="#">Short</a>
  </div>
  <div class="gridentry">
    <a href="#">Meeeedium</a>
  </div>
</div>

...I'd like to make use of CSS to get a presentation that looks like this:

/* DEMONSTRATION-ONLY CSS */

table {
  table-layout: fixed;
}

td {
  width: 50%;
  padding: 1em;

  background-color: red;
  text-align: center;
}

td a {
  color: white;
}
<!-- DEMONSTRATION-ONLY HTML -->

<table>
  <tr>
    <td><a href="#">Loooooooooooooong</a></td>
    <td><a href="#">Short</a></td>
  </tr>
  <tr>
    <td><a href="#">Meeeedium</a></td>
  </tr>
</table>

Note that:

  1. The columns both have the same width.
  2. The table does not have a fixed width (e.g. like 100% or 300px), i.e. it is only as wide as required to make sure that the content fits into its cells. (Or to put it differently: If there is only little content, the whole table will also be pretty narrow.)
  3. The cell content will only wrap if it would make the whole grid too large to fit into the containing block (width-wise).
  4. We have to assume that rows cannot be introduced in the HTML code. The semantics require the HTML code to be structured in this linear fashion. (However, we still need a grid design.)1

I was able to reach my goal with an almost CSS-only solution. However, because there does not seem to be an answer to Using CSS, how to add a pseudo element before every odd child element that is "outside" of that child element? I hope to find a completely different approach to realize this with pure CSS.

So my question boils down to: Is there a CSS-only (= non-JavaScript) solution for my problem?


EDIT: 1 If it is required, we could add additional wrapping elements around each single element. However, we cannot wrap a group of elements.

So we could for example wrap each gridentry:

<div class="linkgrid">
  <div class="wrapper">
    <div class="gridentry">
      <a href="#">Loooooooooooooong</a>
    </div>
  </div>
  <div class="wrapper">
    <div class="gridentry">
      <a href="#">Short</a>
    </div>
  </div>
  <div class="wrapper">
    <div class="gridentry">
      <a href="#">Meeeedium</a>
    </div>
  </div>
</div>

But we cannot wrap groups of elements, so something like this would not be possible:

<div class="linkgrid">
  <div class="wrapper">
    <div class="gridentry">
      <a href="#">Loooooooooooooong</a>
    </div>
    <div class="gridentry">
      <a href="#">Short</a>
    </div>
  </div>
  <div class="wrapper">
    <div class="gridentry">
      <a href="#">Meeeedium</a>
    </div>
  </div>
</div>
like image 949
Hauke P. Avatar asked Sep 01 '25 16:09

Hauke P.


1 Answers

After fiddling around with this for quite a while and getting a very helpful answer to another question that was related to this one, I managed to finally find a solution:

.linkgrid {
  max-width: 50%;
  display: table;
}

.gridentry:nth-child(odd) {
  float: left;
  width: 100%;
}

.gridentry:nth-child(even) {
  width: 100%;
  margin-left: 100%;
  margin-right: -100%;
}

.gridentry:nth-child(even):after {
  content: '';
  display: block;
  clear: left;
}

.gridentry > * {
  display: block;
  
  margin-bottom: 10px;
  padding: 10px;

  background-color: red;
  text-align: center;

  /* This is helpful if the texts get too long to break them "naturally": */
  /* word-break: break-all; */
}

.gridentry:nth-child(odd) > * {
  margin-right: 5px;
}

.gridentry:nth-child(even) > * {
  margin-left: 5px;
}

.gridentry a {
  color: white;
}
<div class="linkgrid">
  <div class="gridentry">
    <a href="#">Loooooooooooooong</a>
  </div>
  <div class="gridentry">
    <a href="#">Short</a>
  </div>
  <div class="gridentry">
    <a href="#">Meeeedium</a>
  </div>
  <div class="gridentry">
    <a href="#">Short</a>
  </div>
  <div class="gridentry">
    <a href="#">Short</a>
  </div>
</div>
like image 82
Hauke P. Avatar answered Sep 04 '25 09:09

Hauke P.