skip to Main Content

I’m trying to make a CSS based expandable box with arbitrary content. My approach is this:

input {
  display: none;
}

label {
  display: block;
  border: 1px solid;
}

.expandContainer {
  overflow: hidden;
}

.expandContents {
  margin-top: -100%;
}

input[type="checkbox"]:checked~label~.expandContainer .expandContents {
  margin-top: 0;
}
<input type="checkbox" id="expandme" />
<label for="expandme">Expand this content</label>

<div class="expandContainer">
  <div class="expandContents">
    <p>Expanded Content</p>
  </div>
</div>

When the label is clicked, the hidden input is checked and the style of .expandContents goes from margin-top: -100% to margin-top: 0.

I can’t use display: none because I’d like to have the action be animated a little bit with a transition property, which I didn’t include in the example for simplicity.

The problem I discovered is that margin-top is based on the width of the element, rather than the height, so if the contents are too tall or the container too narrow, then the bottom of the contents are visible when collapsed.

Is there a way to approach this or is this impossible without using a JavaScript calculation somewhere?

3

Answers


  1. I think it’s kinda weird to use a checkbox for this, there are models now, so it’s a lot less annoying to work with then it used to be, I’d recommend doing it that way.

    Login or Signup to reply.
  2. Change the aproach, instead of margin try playing with a position: relative; parent(your .expandContainer) and a position:absolute; on your .expandContents then use left: -100%; and left: 0; respectively on your css, and then you can add an animation to that transition. Hope this helps.

    Login or Signup to reply.
  3. You could use an opacity:0 for the content instead of display:none. In that way, you could use a @keyframe animation that takes care both of making the content visible and translated. Try adding this tp your code. You may need to fix some timing, but it should make the trick

    input {
      display: none;
    }
    
    label {
      display: block;
      border: 1px solid;
    }
    
    .expandContainer {
      overflow: hidden;
    }
    
    .expandContents {
      margin-top: -100%;
    }
    
    input[type="checkbox"]:checked~label~.expandContainer .expandContents {
      animation: slideDown .3s forwards
    }
    
    
    
    @keyframes slideDown {
      0% {
        opacity: 0;
        margin-top: -100%;
      }
      10% {
        opacity:1
      }
      100% {
        opacity: 1;
        margin-top: 0;
      }
    }
    <input type="checkbox" id="expandme" />
    <label for="expandme">Expand this content</label>
    
    <div class="expandContainer">
      <div class="expandContents">
        <p>Expanded Content</p>
      </div>
    </div>

    Hope this helps

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search