2

I want to do animation of opening two (top and bottom) 'shutters', behind which I want to show some data (eg. number).

I am using z-index, because I want the number behind this curtain (opening shutters) to be there before curtain is open.

Animation need to be that upper stripe will shrink to the top edge and lower striper will shrink to the bottom edge. Shrink should be visible as making height of each strip lower - so from original height of 13px to 0px. At the same time upper's stripe CSS top attribute should be +=1px and lower's stripe top should be -=1px, to mimic that they are opening.

For now i have problem with making each stripe height from original value to 0px (only one of them is 'opening'). And i don't know how to change their top attributes at the same time.

When in middle of animation time, it should like below:

enter image description here

CSS and HTML

#wrapper {
  width: 100px;
  height: 30px;
  border: 2px solid black;
  position: relative;
  top: 50px;
  z-index: 2;
}
.stripe {
  position: relative;
  width: 98px;
  height: 13px;
  background: green;
  z-index: 1;
  border: 1px solid red;
  transition: height 500ms ease-in-out;
}
.stripe:hover {
  height: 0;
}
#money {
  position: relative;
  top: -25px;
  width: 90%;
  display: block;
  margin: 0 auto;
  z-index: 0;
  text-align: center;
}
<div id="wrapper">
  <div class="stripe"></div>
  <div class="stripe"></div>
  <input type="text" id="money" value="1200">
</div>
ScriptyChris
  • 639
  • 4
  • 16
  • 48

1 Answers1

3

You should really be using position:absolute for this and relative widths and heights (percentage values). A few tricks thrown in and I think this is closer to what you were trying to achieve.

#wrapper {
  width: 100px;
  height: 30px;
  border: 2px solid black;
  position: relative;
  top: 50px;
  z-index: 2;
}
.stripe {
  position: absolute;
  width: 100%;
  height: 50%;
  background: green;
  z-index: 1;
  transition: height 500ms ease-in-out;
}
.stripe:first-child {
  border-bottom: 1px solid transparent;
  top: 0;
}
.stripe + .stripe {
  border-top: 1px solid transparent;
  bottom: 0;
}

#wrapper:hover .stripe {
  height: 0;
}
#money {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  width: 90%;
  display: block;
  margin: auto;
  z-index: 0;
  text-align: center;
  height: 1.2em;
  line-height: 1.2em;
}
<div id="wrapper">
  <div class="stripe"></div>
  <div class="stripe"></div>
  <input type="text" id="money" value="1200">
</div>

To clarify what I mean by a few tricks, I used a transparent 1px border on the bottom and top of the top and bottom shutters (respectively); I used a set width and height on the input box with margin: auto to both vertically and horizontally center it; and I used the <selector> + <selector> selector (adjacent sibling selector) to differentiate between either stripe (this is fully CSS2.1 compliant and will work pretty far back for browser compatibility).

Edit:

As requested, to convert this solution to a javascript one, just replace all occurrences of :hover (there's only one in this situation) with a class (e.g. .hover-state); and toggle the class with your favorite goto event listener format. No need for more than one class in this case.

var wrapper = document.getElementById('wrapper');

wrapper.addEventListener('mouseenter', function(){
  this.classList.toggle('hover-state');
});
#wrapper {
  width: 100px;
  height: 30px;
  border: 2px solid black;
  position: relative;
  top: 50px;
  z-index: 2;
  cursor: text;
  display: block;
}
.stripe {
  position: absolute;
  width: 100%;
  height: 50%;
  background: green;
  z-index: 1;
  transition: height 500ms ease-in-out;
}
.stripe:first-of-type {
  border-bottom: 1px solid transparent;
  top: 0;
}
.stripe + .stripe {
  border-top: 1px solid transparent;
  bottom: 0;
}

#wrapper.hover-state .stripe, input:focus ~ .stripe {
  height: 0;
}
#money {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  width: 90%;
  display: block;
  margin: auto;
  z-index: 0;
  text-align: center;
  height: 1.2em;
  line-height: 1.2em;
  outline: none!important;
  border: none;
  background: transparent;
}
<label id="wrapper">
  <input type="text" id="money" value="1200">
  <div class="stripe"></div>
  <div class="stripe"></div>
</label>
Joseph Marikle
  • 76,418
  • 17
  • 112
  • 129
  • Thank You! Could explain, what this CSS does? `.stripe:first-child { border-bottom: 1px solid transparent; top: 0; } .stripe + .stripe { border-top: 1px solid transparent; bottom: 0; }` – ScriptyChris Mar 01 '16 at 14:49
  • Could you show, how to make first `hover` to open the 'curtain' and only after second `hover`, close it (return to beginning)? – ScriptyChris Mar 01 '16 at 14:53
  • 1
    `.stripe:first-child` will select a `.stripe` if it is the first child element of its parent. In this case, that parent would be `#wrapper`. I also edited my answer to explain the `.stripe + .stripe` selector. It's the adjacent sibling selector. It specifies that a `.stipe` should be targeted if it is followed by another `.stripe`. In this case, because the second `.stripe` comes immediately after the first, it is selected. – Joseph Marikle Mar 01 '16 at 14:53
  • @Chris92 So, you want it to toggle on hover? That's not CSS functionality. It would require javascript to work. Are you perhaps wanting it to stay open when someone has clicked into it instead? – Joseph Marikle Mar 01 '16 at 14:55
  • in fact I do want to use JS to activate it, but first i needed to make standalone animation. Eventually I want this animation to start when i click some button - I assume it's by `element.classList.add()` - and after another button clicked I want it to be closed - `element.classList.remove()`. Like that? – ScriptyChris Mar 01 '16 at 14:59
  • 1
    @Chris92 Ah! that makes sense. You need it to trigger on a class instead. That's pretty easy to pull off. This is what I was talking about with the my previous comment: https://jsfiddle.net/7hnvs10x/ (if you click in the box it stays open all with CSS). I can throw together a javascript solution to add a class on mouseenter or whatever event. – Joseph Marikle Mar 01 '16 at 15:00
  • I know how to trigger things by JS, but in this case i don't know which class add to start animation and later, which class remove to make it back to beginning. So could you add this to you answer post, please? – ScriptyChris Mar 01 '16 at 15:06
  • 1
    @Chris92 in that case, it's really easy. You just have to substitute a class wherever `:hover` occurs in the CSS. I like to use something like `hover-state`. Simplified example: https://jsfiddle.net/7hnvs10x/1/ – Joseph Marikle Mar 01 '16 at 15:12
  • Ok. Thank you once again! – ScriptyChris Mar 01 '16 at 15:17
  • Hi again. Could you tell me how to do: **Slow opening** animation (it may be as it is now) BUT **Fast closing** animation? I tried it: `transition: height 3000ms ease-in; transition: height 100ms ease-out;` but second line overrides first - so it both opens and closes with 100ms. – ScriptyChris Mar 06 '16 at 20:53
  • 1
    @Chris92 Sure. Just add a transition for the `:hover`/`.hover-state` rule. When the class or pseudo-class is active, it will override the initial `transition` rule: https://jsfiddle.net/7hnvs10x/2/. – Joseph Marikle Mar 06 '16 at 21:09
  • Great! I thought that `ease-in` is for opening and `ease-out` is for closing. Thank You again. – ScriptyChris Mar 06 '16 at 21:49