html – How to animate display of dynamic size elements with CSS only?

Question:

I'm building a site that has some state transitions using CSS only. In one of them, the user clicks on the header and the div below shows or hides. On the other there is a sequence of images and when you click on the current image, it moves to the next one. The technique for both is similar: a hidden input with one or more label s attached to it, and the CSS "brothers" selectors ( + and ~ ). Examples:

  1. Sections (uses checkboxes to hide/show each section)
.escondido { display: none; }
.box { display: none; width: 200px; height: 100px; }
.escondido:checked + .box { display: block; }

h2 { width: 200px; background-color: lightgray; cursor: pointer; }
.a { background-color: red; }
.b { background-color: blue; }
<label for="aba1"><h2>Seção 1</h2></label>
<input id="aba1" class="escondido" type="checkbox">
<div class="box a"></div>

<label for="aba2"><h2>Seção 2</h2></label>
<input id="aba2" class="escondido" type="checkbox">
<div class="box b"></div>
  1. Images (uses radio buttons to cycle through images)
.escondido { display: none; }
.imagem { display:none; width: 200px; height: 100px; cursor: pointer; }
.escondido:checked + label .imagem { display: block; }

.a { background-color: red; }
.b { background-color: blue; }
.c { background-color: green; }
.d { background-color: yellow; }

.mini { display: inline-block; width: 10px; height: 10px; border-radius: 5px; }

.escondido.a:checked ~ label .mini.a { border: 2px solid black; }
.escondido.b:checked ~ label .mini.b { border: 2px solid black; }
.escondido.c:checked ~ label .mini.c { border: 2px solid black; }
.escondido.d:checked ~ label .mini.d { border: 2px solid black; }
<!-- Imagens -->
<input id="img1" class="escondido a" type="radio" name="imgs" checked>
<label for="img2"><div class="imagem a"></div></label>

<input id="img2" class="escondido b" type="radio" name="imgs">
<label for="img3"><div class="imagem b"></div></label>

<input id="img3" class="escondido c" type="radio" name="imgs">
<label for="img4"><div class="imagem c"></div></label>

<input id="img4" class="escondido d" type="radio" name="imgs">
<label for="img1"><div class="imagem d"></div></label>

<!-- Miniaturas -->
<label for="img1"><div class="imagem mini a"></div></label>
<label for="img2"><div class="imagem mini b"></div></label>
<label for="img3"><div class="imagem mini c"></div></label>
<label for="img4"><div class="imagem mini d"></div></label>

I would now like to animate the transition between "displayed" and "hidden" states. I know it's not possible to animate the display property directly: jQuery for example when displaying first reduces the element's size to zero, changes the display from "hidden" to "displayed", then animates the element's size from zero to its real size. I can't do something similar with CSS alone, because you can't say "first do this, then do that"…

I tried to avoid the display and simply set the total height of the div to zero. It worked fine if the div has a fixed size, but not if the size is variable (it "jumped" straight between zero and maximum sizes):

.escondido { display: none; }
.box { height: 0; width: 200px; overflow: hidden; transition: height 2s; }

h2 { width: 200px; background-color: lightgray; cursor: pointer; }
.a { background-color: red; }
.b { background-color: lightgray; }

.escondido:checked + .a { display: block; height: 100px; }
.escondido:checked + .b { display: block; height: auto; }
<label for="aba1"><h2>funciona</h2></label>
<input id="aba1" class="escondido" type="checkbox">
<div class="box a"></div>

<label for="aba2"><h2>não funciona</h2></label>
<input id="aba2" class="escondido" type="checkbox">
<div class="box b">Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</div>

(I also tried with max-height , and it worked just as well on the fixed-size div , but in this case the variable-size div wasn't even displayed…)

Is it possible to do this with CSS only, without having to specify an absolute size? (and without compromising on responsiveness, ie if adjusting the window width the div height changes, it still works) What properties could I try to animate to create the "hidden/shown" illusion with smooth transition?

Note: in the case of images, the exchange would be horizontal and not vertical, but as it is easier to deal with images (as their size is usually known) this case may be left out of the question (but suggestions for this case would also be very welcome ).

Answer:

Some time ago I created an article on this same subject on my Blog.
You can do this using max-height as follows:

.box { max-height: 0; transition: max-height 2s;}
.escondido:checked + .b { max-height:100px; }

Here's an example below:

.escondido { display: none; }
.box { max-height: 0; width: 200px; overflow: hidden; transition: max-height 2s; }

h2 { width: 200px; background-color: lightgray; cursor: pointer; }
.b { background-color: lightgray; }

.escondido:checked + .b { display: block; max-height:100px; }
<label for="aba2"><h2>Seção 2</h2></label>
<input id="aba2" class="escondido" type="checkbox">
<div class="box b">Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</div>
Scroll to Top