Toggla show/hide med CSS

Flex

.wrapper {
  display: flex;
}

.inner {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.5s ease-out;
}

.wrapper.is-open .inner {
  max-height: 100%;
}

Just be sure there’s an extra div between the wrapper and the inner element:

<div class="wrapper">
  <div>
    <div class="inner">Expandable content</div>
  </div>
</div>

Grid

This one is a bit simpler, and probably a little more understandable. Make a CSS grid with a single grid item. All you have to do is transition grid-template-rows from 0fr to 1fr, so the grid item transitions to its auto height:

.wrapper {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 0.5s ease-out;
}

.wrapper.is-open {
  grid-template-rows: 1fr;
}

.inner {
  overflow: hidden;
}
<div class="wrapper">
  <div class="inner">Expandable content</div>
</div>

The one caveat to both of these is you can’t add any padding to the inner element. If you need padding, you have to add one more extra element inside the collapsed element and put the padding on that.

Max-height

.section {
  overflow:hidden;
  transition:max-height 0.3s ease-out; // note that we're transitioning max-height, not height!
  height:auto;
  max-height:600px; // still have to hard-code a value!
}
.section.collapsed {
  max-height:0;
}

There are two crucial downsides to this

One is obvious, and one is subtle. The obvious disadvantage is that we still have to hard-code a maximum height for the element, even if we don’t have to hard-code the height itself. Depending on your situation, maybe you can guarantee that you won’t need more height than that. But if not, it’s a pretty big compromise. The second, less obvious downside, is that the transition length will not actually be what you specify unless the content height works out to be exactly the same as max-height. For example, say your content is 600px tall, and your max-height is transitioning from 0px to 1000px with a duration of 1 second. How long will it take the element to get to 600px? 0.6 seconds! The max-height will continue transitioning, but the real height will stop changing once it reaches the end of its content. This will be even more pronounced if your transition is using a nonlinear timing function. If the transition is fast at the beginning and slow at the end, your section will expand quickly and collapse slowly. Not ideal. Still, transitions are relatively subjective, so in cases where this technique is otherwise appropriate, it could be an acceptable tradeoff.

Technique 2: transform: scaleY()

It’s important to note a couple of things about the nature of these transformations:

  1. They operate on the element’s visual representation as if it were simply an image, rather than a DOM element. This means, for example, that an element scaled up too far will look pixellated, since its DOM was originally rendered onto fewer pixels than it now spans.
  2. They do not trigger reflows. Again, the transform doesn’t know or care about the element’s DOM structure, only about the “picture” the browser drew of it. This is both the reason this technique works and its biggest downside.
.section {
  overflow:hidden;
  transition:transform 0.3s ease-out; // note that we're transitioning transform, not height!
  height:auto;
  transform:scaleY(1); // implicit, but good to specify explicitly
  transform-origin:top; // keep the top of the element in the same place. this is optional.
}
.section.collapsed {
  transform:scaleY(0); // *squish*
}

Författare: Erik

Erik har jobbat med webb professionellt sedan 2008. Från 2005 till 2008 studerades webb på ING/JTH och dessförinnan skapades webb på all fritid. Första sajten byggdes någon gång mellan 1996-1998.