0

I have 3 <div> columns using flexbox or grid.

How to make, with CSS, that:

  • if all columns have inner HTML content, they share 33% / 33% / 33% width

  • if one column's inner HTML content is empty, the other two columns automatically take 50% / 50% width

  • if two column's inner HTML content is empty, the only non-empty column takes 100% width

Is this possible like this, and a specific flex or grid option?

.container {
 display: flex;
 width: 500px;
 background-color: green;
}

.col {
 border: 1px solid black;
 padding: 1em;
}
<div class="container">
<div class="col">
Automatic use of 2 columns
</div>
<div class="col">
(50% / 50%) because 3rd col has empty content
</div>
<div class="col">
</div>
</div>

Another:

<div class="container">
<div class="col">
Automatic use of
</div>
<div class="col">
3 columns (33% / 33% / 33%) because 3rd 
</div>
<div class="col">
col is not empty
</div>
</div>
Paulie_D
  • 107,962
  • 13
  • 142
  • 161
Basj
  • 41,386
  • 99
  • 383
  • 673
  • Basically, not with flexbox, no. Pretty sure not with CSS-Grid either but I'd have to think on it. – Paulie_D Feb 04 '22 at 12:49
  • You can leverage `:empty` to override the width but it does require there to be no whitespace etc. in the "empty" div, at lease until :blank` gets proper support - https://codepen.io/Paulie-D/pen/RwjGgJG – Paulie_D Feb 04 '22 at 12:58

1 Answers1

1

One possible approach, if you can rely upon the empty <div class="col"> being empty (containing nothing, including white-space), is below:

/* a simple, generic reset to apply a consistent
   baseline to all elements, and the listed
   pseudo-elements, on the page: */
*,
 ::before,
 ::after {
  box-sizing: border-box;
  font: normal 1rem / 1.5 sans-serif;
  margin: 0;
  padding: 0;
}

/* generic wrapper for the content, entirely irrelevant
   to the demo's functionality; this is just to give
   a consistent visual look: */
.wrap {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 2em;
  margin-block: 2em;
  margin-inline: auto;
  width: 500px;
  height: 100vh;
}

/* I've switched your background-color to a lighter one
   to allow visibility of the .container element, and to
   improve visibility of the child .col elements: */
.container {
  display: flex;
  width: 500px;
  background-color: #ffa9;
}

/* I added the 'flex-grow' property to allow the
   .col elements to expan to fill the available
   space: */
.col {
  padding: 1em;
  flex-grow: 1;
}

/* different background-colours for the elements: */
.col:nth-child(1) {
  background-color: red;
}

.col:nth-child(2) {
  background-color: green;
}

.col:nth-child(3) {
  background-color: blue;
}

/* hiding any empty .col elements; note that these
   elements must have no content at all, this
   includes white-space (unfortunately): */
.col:empty {
  display: none;
}
<div class="wrap">
  <div class="container">
    <div class="col">
      50%
    </div>
    <div class="col">
      50%
    </div>
    <div class="col"></div>
  </div>

  <div class="container">
    <div class="col">
      33.3%
    </div>
    <div class="col">
      33.3%
    </div>
    <div class="col">
      33.3%
    </div>
  </div>

  <div class="container">
    <div class="col">
      100%
    </div>
    <div class="col"></div>
    <div class="col"></div>
  </div>
</div>

JS Fiddle demo.

It's worth noting that the same is possible with CSS Grid, with the same requirement of the :empty selector:

*, ::before, ::after {
  box-sizing: border-box;
  font: normal 1rem / 1.5 sans-serif;
  margin: 0;
  padding: 0;
}

.wrap {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 2em;
  margin-block: 2em;
  margin-inline: auto;
  width: 500px;
  height: 100vh;
}

.container {
/* here we use display: grid: */
 display: grid;
/* specify that the grid-items should flow into
   columns rather than their default (rows): */
 grid-auto-flow: column;
 width: 500px;
 background-color: #ffa9;
}

.col {
/* and we remove the 'flex-grow' property, as it
   doesn't affect CSS grid layout: */
 padding: 1em;
}

.col:nth-child(1) {
  background-color: red;
}

.col:nth-child(2) {
  background-color: green;
}

.col:nth-child(3) {
  background-color: blue;
}

.col:empty {
   display: none;
}
<div class="wrap">
  <div class="container">
    <div class="col">
      50%
    </div>
    <div class="col">
      50%
    </div>
    <div class="col"></div>
  </div>

  <div class="container">
    <div class="col">
      33.3%
    </div>
    <div class="col">
      33.3%
    </div>
    <div class="col">
      33.3%
    </div>
  </div>

  <div class="container">
    <div class="col">
      100%
    </div>
    <div class="col"></div>
    <div class="col"></div>
  </div>
</div>

JS Fiddle demo.

Note that, in [Selectors Level 4] the behaviour of :empty will be changed to select elements that contain only white-space:

The :empty pseudo-class represents an element that has no children except, optionally, document white space characters. In terms of the document tree, only element nodes and content nodes (such as [DOM] text nodes, and entity references) whose data has a non-zero length must be considered as affecting emptiness; comments, processing instructions, and other nodes must not affect whether an element is considered empty or not.

Examples: p:empty is a valid representation of the p elements in the following HTML fragment:

<p></p>
<p>
<p> </p>
<p></p>

References:

Bibliography:

David Thomas
  • 249,100
  • 51
  • 377
  • 410
  • Wonderful! Side-remark: is there also a way to use `:empty` to apply a rule for a `
    ` if and only if a given grand-child is empty?
    – Basj Feb 04 '22 at 13:23
  • There is no parent selector (as yet), so no, not with CSS alone. If you have access to JavaScript then sure, but that's another question. And I can almost guarantee it's a duplicate of an existing question since people have wanted to style ancestor elements based on a descendant state since the internet has existed (a duplicate of this one, probably: https://stackoverflow.com/questions/1014861/is-there-a-css-parent-selector). If you find it doesn't answer your question, do a thorough search and be prepared to argue why your question is different, or why and how existing solutions fail. – David Thomas Feb 04 '22 at 13:27
  • You're very welcome indeed, I hope it's of use to you. – David Thomas Feb 04 '22 at 13:37