Olivier Butler Olivier Butler - 3 months ago 27
CSS Question

Pure CSS3 animated slide-up caption on hover

The background is pretty simple, I wanted to have a small caption slide up from the bottom of an element when the user hovers/taps. See fig 1.

Figure 1, Text slides up on hover

A bit of digging said this couldn't be done using CSS, but I really don't see why. A few hours later, I think I'm very close to solving it, but I can't jump the final hurdle.

My logic was, if your parent element has

overflow: hidden
, and you absolutely position the caption off the bottom of the parent, you can just animate the position values using the transition attribute so it slides up. Pure CSS baby!

You can't animate height- the text is crushed, the element has to be moved as a block (though not necessarily rendered as display:block).

Here's where I've got to so far https://jsfiddle.net/zufwavpn/. The HTML,

<div class="item-wrapper">
<div class="content">
Hello I am content. All that matters for this method to work is that the item wrapper has a fixed size. In my working project, the width is set to a % value, and the height to rem.
</div>
<div class="popup-title">
<span>A title for my content</span>
</div>
</div>


And the CSS (I've converted to vanilla CSS here),

.item-wrapper{
height:22rem;
position:relative;
overflow:hidden;
color:white;
font-family:sans-serif;
}

.content{
height:100%;
background-color:red;
padding:10px;
}

.popup-title{
position:absolute;
top:100%;
bottom:0%;
width:100%;
transition: bottom 0.5s, top 0.5s;
vertical-align: bottom;
}

.popup-title span{
display:block;
margin:0;
background-color: black;
}

.item-wrapper:hover .popup-title{
bottom:0%;
top:0%;
}


The reason I feel close is that at this stage, the popup basically works, but the content inside it should be aligned to the bottom of the container. Essentially it's the age old trick of set an absolutely positioned element's top and bottom to '0' but used to animate something from below the container.

Why am I animating the top and bottom attributes? If you only work with the 'top' value, you can hide the element by setting
top:100%
, but you can't animate that so it'll rest on the bottom of the parent. You'd need a specific value for top to be set to (height of parent minus height of content of pop up), and the pop up content / parent could be any size. You could set
bottom:-100%
- and this actually works, you can animate to
bottom:0%
, and the pop up with rest at the bottom of the parent. All good and done with no need to set a top value. But, it's unsatisfactory, you're having to place the slider way way below the parent and animate it up, which for various reasons to do with the other animations, produces a badly timed effect.

So, here we have the pop up element positioned at the bottom of the parent, with no height since the top and bottom values coincide, and the content overflowing downwards. Perfect. Then the top value animates up, the pop up element now has
top:0; bottom:0
, filling the parent, and if only I could get the content to stick to the bottom all would be well.

This last bit isn't usually too difficult. We have vertical-align, and the whole world of flex, but they all seem to produce errors and bugs and lead me down holes. Any ideas anyone? At this point I have to move on and just use javascript, but I feel like it's a problem worth solving in its own right.

Answer

.item-wrapper {
  height:22rem;
  position:relative;
  overflow:hidden;
  color:white;
  font-family:sans-serif;
}

.content {
  height:100%;
  background-color:red;
  padding:10px;
}

.popup-title {
  position:absolute;
  top:100%;
  width:100%;
  transition: transform 250ms;
  vertical-align: bottom;
}
.popup-title span {
  display:block;
  margin:0;
  background-color: black;
}

.item-wrapper:hover .popup-title {
  transform:translateY(-100%);
}
<div class="item-wrapper">
  <div class="content">
    Hello I am content. All that matters for this method to work is that the item wrapper has a fixed size. In my working project, the width is set to a % value, and the height to rem.
  </div>
  <div class="popup-title">
    <span>A title for my content</span>
  </div>
</div>