8

I have a div at the top of my page, containing some header text, which, upon mouseenter, should expand (in height), to reveal some smaller text. Then, upon mouseleave, it should then retract. This is harder than it sounds...

The solution must:

  1. Go from a height to fit just the header, to a height to fit all the text.
  2. Transition from one to the other.
  3. Try to use pure CSS.
  4. Have the expanding animation pause if the mouse leaves, and visa versa (default in CSS, but not in jQuery).

I have tried:

  1. Using :hover in my stylesheet, to change from a set pixel value, to auto, as seen in this question (but in mine it is pure CSS). This did not transition.
  2. Using a set height upon expansion, which does not work on different viewport sizes.
  3. Using max-height, and expanding it to something larger than the actual expanded div would get, as seen in this question. This meant that the transitions don't work properly, and look different on different devices.
  4. Using jQuery .animate(), using the pixel value of auto, to then create a transition, as seen in this question, but the animation has to finish before starting the next one, meaning that a series of animations could continue for a long time after the user's mouse if far away from the div.

See all four above examples here.

As said, pure CSS would be ideal, but if not possible, I would be fine with JavaScript (and I prefer jQuery).

Thanks! :)

Community
  • 1
  • 1
Luke
  • 2,038
  • 3
  • 22
  • 46
  • 1
    Can you provide us some code – The Process Feb 13 '16 at 21:12
  • I actually have: "See all four above examples [here](https://jsfiddle.net/ypwu9n0g/2/)." – Luke Feb 13 '16 at 21:13
  • 2
    Questions seeking debugging help ("why isn't this code working?") must include the desired behavior, a specific problem or error and the shortest code necessary to reproduce it **in the question itself**. Questions without a clear problem statement are not useful to other readers. See: [How to create a Minimal, Complete, and Verifiable example](http://stackoverflow.com/help/mcve). – j08691 Feb 13 '16 at 21:19
  • 1
    I am not aware of any pure CSS solution for this; but for a “simple” jQuery solution, I’d just wrap the paragraph content inside an additional span, set the initial paragraph height to 0 and overflow:hidden, leave the transition for the height in place – and then let the jQuery only do one thing – read the height of the span element, set that height for the paragraph, and then set it to 0 again to fade the text out again. https://jsfiddle.net/ypwu9n0g/7/ (Please notice that in that example, the method is the same for all four items, and I did not bother to change the text content.) – CBroe Feb 13 '16 at 21:38
  • 1
    @CBroe, that is an ingenious solution, though I am not sure why you answered it as a comment. I would appreciate it if you put that as an answer... thanks so much! :) – Luke Feb 13 '16 at 21:41
  • Happy to add it as an answer; I just wasn’t sure if I understood your requirement number 4 correctly, so I made it a comment first. – CBroe Feb 13 '16 at 21:54
  • @CBroe Yes, that makes sense :). – Luke Feb 13 '16 at 22:02
  • @Mirabilis See `css` approach at second Answer utilizing `font-size` , `line-height` https://jsfiddle.net/ypwu9n0g/10/ – guest271314 Feb 13 '16 at 22:22

3 Answers3

3

I am not aware of any pure CSS solution for this – transitioning values to auto is something the specification did not include; I think that was even an explicit decision based on that there might be implementation problems.

But for a “simple” jQuery solution, I’d just wrap the paragraph content inside an additional span, set the initial paragraph height to 0 and overflow:hidden, leave the transition for the height in place – and then let jQuery only do one thing, read the height of the span element, set that height for the paragraph, and then set it to 0 again to fade the text out again.

.details {
  height: 0;
  margin: 0; 
  overflow: hidden;
  transition: height 1s;
}

 

$("div").mouseenter(function() {
  $(this).find('p').css('height', $(this).find('span').height());
})

$("div").mouseleave(function() {
  $(this).find('p').css('height', 0);
})

That way, CSS still does the “heavy lifting” of handling the height change via transition (that might should be optimized in browsers), and jQuery/JavaScript is only used to give it the little “nudge” it needs to know what to do. (Pretty sure jQuery is doing the same thing internally as well nowadays with animate(), if the browser supports it – added benefit there would be that jQuery takes care of a fallback implementation, should a really old browser not support transition; in my solution the height would just change instantly, without any transition.)

https://jsfiddle.net/ypwu9n0g/7/

Please notice that in that example, the method is the same for all four items, and I did not bother to change the text content ;-)

CBroe
  • 91,630
  • 14
  • 92
  • 150
  • Thank you so much! This is exactly what I need. I really don't know how you though of that ;). – Luke Feb 13 '16 at 21:53
  • @CBroe Yes, adjusted `font-size` minimally at https://jsfiddle.net/ypwu9n0g/10/ ; may require some fine tuning; though should be possible using only `css` . Good Question; would begin a bounty for pure `css` solution if knew how to phrase requirements properly if jsfiddle does not return expected results https://jsfiddle.net/ypwu9n0g/11/ – guest271314 Feb 13 '16 at 22:23
  • @guest271314: I don’t think that can be fine-tuned so that the jittering effect goes away; transitioning font-size is simply only possible in noticeable “steps” with the current font rendering implementations in browsers. Besides, as the font-size increases the text also grows “longer”, giving a bit of a snake-like effect – not a big fan of that either. – CBroe Feb 13 '16 at 22:27
  • @CBroe See updated post; removed `font-size` transition , adjusted `line-height` duration to `.1s` https://jsfiddle.net/ypwu9n0g/12/ – guest271314 Feb 13 '16 at 22:33
  • 1
    @guest271314: OK, I’ll grant you, that kinda works – as long as it is text content only; lets say some images inside the paragraph content come into play, then using the `line-height` won’t work any more I think. – CBroe Feb 13 '16 at 22:38
  • @CBroe _"lets say some images inside the paragraph content come into play"_ Set`width` to `0px` for `img` , set to `auto` at `:hover` https://jsfiddle.net/ypwu9n0g/15/ – guest271314 Feb 13 '16 at 23:02
2

Try using css :hover

[id^="title"] {
  height: 1em;
  overflow: hidden;
  -webkit-transition: height 1s;
  /* Transitions not working */
  transition: height 1s;
}

[id^=title]:hover {
  height: 10em;
}
guest271314
  • 1
  • 15
  • 104
  • 177
  • 1
    Sorry, but I have already tried this: "Using a set height upon expansion, which does **not work on different viewport sizes**." – Luke Feb 13 '16 at 21:22
  • @Mirabilis _"Using a set height upon expansion, which does not work on different viewport sizes."_ What is expected result for different viewport sizes ? – guest271314 Feb 13 '16 at 21:23
  • 2
    On smaller viewport sizes, a set pixel expansion will still cut off the text, while on larger viewport sizes, it will expand too much and leave too much white space. Try re-sizing the result box in the fiddle you edited. – Luke Feb 13 '16 at 21:26
  • @Mirabilis Set initial `height` to `1em`, `:hover` `height` to `100vh` https://jsfiddle.net/ypwu9n0g/5/ , with `text-overflow` set to `ellipsis` https://jsfiddle.net/ypwu9n0g/6/ – guest271314 Feb 13 '16 at 21:27
  • What is expected result ? For expanded element container to extend only to bottom of viewport ? – guest271314 Feb 13 '16 at 21:32
  • 1
    The expected result is for *all the content* to be shown, whatever the viewport size is. As the viewport size changes, the height that is needed will change. CSS solutions work best when they are flexible. This is not flexible, and will work only for *one* viewport size. – Luke Feb 13 '16 at 21:34
  • @Mirabilis _"The expected result is for all the content to be shown"_ If the viewport height is less than the total content height, how should all content be displayed ? Utilize `calc()` at `css` as it is flexible; not certain what expected result is when viewport is less than total content height ? – guest271314 Feb 13 '16 at 21:35
  • Sorry, I meant width. As the width of the viewport changes, the text will be compressed, wrap, and thus require more height, which is not accommodated for by a set height. – Luke Feb 13 '16 at 21:36
  • Yes, when viewport changes, what is expected result of displayed text content ? Ellipsis ? Clipped ? How does https://jsfiddle.net/ypwu9n0g/6/ not meet requirement ? – guest271314 Feb 13 '16 at 21:44
  • All I want is for the `div` to expand, on hover, to show more content (and enough to show that content, no more, no less). [This comment](http://stackoverflow.com/questions/35385356/expandable-div-with-transition-in-css?noredirect=1#comment58475666_35385356) has the desired solution. Thanks for the effort all the same :). – Luke Feb 13 '16 at 21:44
2

A css approach utilizing height , line-height , font-size , opacity

[id^="title"] p {
  overflow:hidden;
  font-size:0em;
  line-height:0em;
  /* height:0px; */
  opacity:0;
  -webkit-transition: height 1s;
  transition: /* height 1s,*/ opacity 1s, line-height 0.1s;
}

[id^="title"]:hover p {
  /* height:auto; */
  opacity:1;
  line-height:1em;
  font-size:1em;
  opacity:1;
  text-overflow: ellipsis;
}
<div id="title1">Title 1<p id="details">Height working, but not transition. Height working, but not transition. Height working, but not transition. Height working, but not transition. Height working, but not transition. Height working, but not transition. Height working, but not transition. Height working, but not transition.</p></div>
<div id="title2">Title 2<p id="details">Transition working, but only on one viewport size... Transition working, but only on one viewport size... Transition working, but only on one viewport size... Transition working, but only on one viewport size... Transition working, but only on one viewport size... Transition working, but only on one viewport size... Transition working, but only on one viewport size...</p></div>
<div id="title3">Title 3<p id="details">Height working, but transitions looking different on different viewport sizes. Height working, but transitions looking different on different viewport sizes. Height working, but transitions looking different on different viewport sizes. Height working, but transitions looking different on different viewport sizes. Height working, but transitions looking different on different viewport sizes. </p></div>
<div id="title4">Title 4<p id="details">Height and transition working - just one catch - the animation does not pause when a new one starts, creating a kind of animation stack that is annoying... Height and transition working - just one catch - the animation does not pause when a new one starts, creating a kind of animation stack that is annoying... Height and transition working - just one catch - the animation does not pause when a new one starts, creating a kind of animation stack that is annoying... </p></div>

jsfiddle https://jsfiddle.net/ypwu9n0g/17/

guest271314
  • 1
  • 15
  • 104
  • 177
  • 1. I am not looking for that transition, but more a simple reveal. 2. There is no transition when the `div` retracts. 3. The question has already been answered, so alternative approaches are likely not to be what I'm looking for. – Luke Feb 13 '16 at 22:36
  • @Mirabilis This is a good Question. Added second Answer due to this portion of original Question: _"3. Try to use pure CSS."_ – guest271314 Feb 13 '16 at 22:39
  • It's better now, although there is no transition when retracting... do you know why? @guest271314 – Luke Feb 13 '16 at 22:42
  • 1
    @Mirabilis: That’s because the height is switched from `auto` back to `0` instantly (as I said in my answer, transitioning to `auto` is not possible) – but removing the `height:0` in the original state would fix that, see https://jsfiddle.net/ypwu9n0g/13/ (The line-height being set to 0 is what effectively makes the height of the container element become 0 _implicitly_ as well. But as I said in another comment, that will only work as long as the content stays pure text – [bring an image into the mix](https://jsfiddle.net/ypwu9n0g/14/), and that won’t work any more.) – CBroe Feb 13 '16 at 22:47
  • 1
    This is not exactly what I'm looking for, so I can't accept it, but I do appreciate the effort you have put into these two answers :). I'll give you a vote ;). – Luke Feb 13 '16 at 22:50