Scroll Div with a Position Fixed child - javascript

I have a div that wraps some content. This div has its overflow-y set to scroll.
Inside the wrapper, are 2 more divs. The first has a height greater than the wrapper, the second contains some content and is absolutely positioned.
<div id="wrapper" style="overflow-y:scroll;height:500px">
<div id="setHeight" style="height:1000px"></div>
<div id="content" style="position:fixed">
Content Goes Here
</div>
</div>
The question is when the mouse is positioned over the #content div, the #wrapper will not scroll. However, when the mouse is positioned on some other part of the #wrapper div where the #content div doesn't fill it scrolls.
I tried to fix this in various ways:
First: set the z-index of #content to -1. This works (as in the #wrapper scrolls) but the content can no longer be interacted with.
Second:, apply the above fix, but use Javascript to listen for mouse clicks. When the user clicks, immediately change the #content's z-index to 1 allowing the user to interact.
The problem with this is even though it works (i.e. the z-index changes), the browser still won't interact with the #content unless you let go of the mouse and click again. Which by the time you let go of the mouse I would want the #wrapper to be scroll-able again.
Third: I tried to set the #content z-index to -1, and set the #wrapper's pointer-events to none. This however made both the scrolling and interaction stop.
Is there anyway to do this?

#wrapper {
background: red;
overflow-y: scroll;
height: 100px; border: solid 1px;}
#header {
background: lightblue;
height: 200px; overflow-y: none;}
#content {
background: green;}
#popup {
background: yellow;
position: fixed;
top: 0;
opacity: 0.5;
pointer-events: none;
}
<div id="wrapper">
<div id="header">Headerum textum</div>
<div id="content">
Contentum Textum
<div id="popup">
Popup textum, lorem ipsum dolor sit amet, consectetur adipiscing elit. ... Aenean ut orci vel massa suscipit pulvinar. Nulla sollicitudin. Fusce varius, ligula non tempus aliquam, nunc turpis ullamcorper nibh, in tempus sapien eros vitae ligula.
</div>
</div>
</div>
Please have a look... on this CodePen

Don't know why do you need the setHeight div. Did some change to your code. Don't know if this is what you want.
<div id="wrapper" style="overflow-y:scroll;height:500px;position:relative">
<div id="setHeight" style="height:1000px"></div>
<div id="content" style="position:absolute;top:0px;">
Content Goes Here
</div>
</div>

Related

Scrollable text in a DIV of unknown size?

I have this:
<section>
<div id="dont-scroll">
Unknown content!
</div>
<div>
<div id="scroll-this">
This part should be scrollable when
the total content overflows the SECTION
</div>
</div>
</section>
As you can see I want the user to be able to scroll the content in the lower half, but not the upper.
I can achieve this by using "resize" events, checking the size of SECTION and "dont-scroll", etc.
However, is there an easier way today, using only CSS?
A possible approach using Flexbox
body, html {
margin: 0;
padding: 0;
}
section {
height: 100vh;
display: flex;
flex-flow: column nowrap;
}
section > div {
padding: 20px;
}
div:not([id]) {
background: #d8d8dc;
flex: 1;
overflow: auto;
}
<section>
<div id="dont-scroll">
Unknown content! <br />
Lorem ipsum sit dolor amet
</div>
<div>
<div id="scroll-this">
This part should be scrollable when
the total content overflows the SECTION
<br /><br />
<p>Lorem ipsum dolor sit amet,
consectetuer adipiscing elit. Donec
odio. Quisque volutpat mattis eros.
Nullam malesuada erat ut turpis.
Suspendisse urna nibh, viverra non,
semper suscipit, posuere a, pede.</p>
...
</div>
</div>
</section>
Example on codepen
Defining height of scroll-this id and using overflow-y: scroll will make scroll-this id scroll able
#scroll-this {
height: 10px; //this can be as per your choice
overflow-y: scroll;
}
I used 10px because your content is too less.
"This part should be scrollable when the total content overflows the
SECTION".
Scroll will show only if line breaking content is greater then provided height.
#scroll-this {
height: 20px;
overflow-y: scroll;
}
<section style="width:200px">
<div id="dont-scroll">
Unknown content!
</div>
<div>
<div id="scroll-this">
This part should be scrollable when the total content overflows the SECTION
</div>
</div>
</section>

Prevent element width from shrinking

I have a tooltip with some text, and in order to control the tooltip's position relative to the cursor with CSS, I placed it inside a zero-sized div. Javascript moves the outer div, and the tooltip can be aligned via any of the top/right/left/bottom attributes, depending on which side it should be placed on.
However, this creates a new problem - the tooltip contents now tries to use as little width as possible. I can't disable wordwrap because it needs to fit on mobile screens. Without the outer container, it works perfectly, stretching up to the window edge. Is there a way to ignore the outer container while calculating the line breaks?
From what I can tell, the tooltip no longer 'sees' the body element so it can't know how much it can stretch. However, controlling the tooltip position directly via Javascript is more complicated if I need to align the bottom or right sides - I have to either consider tooltip size (which can change depending on its position), or set bottom/right properties and consider window size.
Here's an example: http://jsfiddle.net/03gdomLt/1/
The first tooltip works correctly, while the second one tries to shrink to zero width.
.tip-outer {
position: absolute;
top: 200px;
left: 100px;
}
.tooltip {
position: absolute;
left: 10px;
top: 10px;
border: 1px solid black;
}
<div class="tip-outer">
<div class="tooltip">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis pharetra feugiat augue, non pretium massa ultricies vel. In hendrerit tellus.
</div>
</div>
<div class="tooltip">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis pharetra feugiat augue, non pretium massa ultricies vel. In hendrerit tellus.
</div>
Looks only parent width shrinks to 0, the tooltip text are still there but are not able to fit on screen. That is because the parent div (tip-outer) is having left:100px which is forcing tooltip to shift towards right, hence not visible.
Try below css to fix it for small screen. Updated fiddle
#media only screen
and (max-width : 400px) {
.tip-outer .tooltip{
left: -90px;
}
}
I don't know if this can or can not work for your case, but positioning the element relative does enable the text to wrap correctly even if it is positioned left top bottom right.
http://jsfiddle.net/03gdomLt/3/
.tip-outer {
position: absolute;
top: 200px;
left: 100px;
}
.tooltip {
position: relative;
left: 10px;
top: 10px;
border: 1px solid black;
//white-space: pre-wrap;
}
<div class="tip-outer">
<div class="tooltip">Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Suspendisse accumsan lectus eget egestas fringilla.</div>
</div>
<div class="tooltip">Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Suspendisse accumsan lectus eget egestas fringilla.</div>

CSS transition not working with height : auto [duplicate]

I am trying to make a <ul> slide down using CSS transitions.
The <ul> starts off at height: 0;. On hover, the height is set to height:auto;. However, this is causing it to simply appear, not transition,
If I do it from height: 40px; to height: auto;, then it will slide up to height: 0;, and then suddenly jump to the correct height.
How else could I do this without using JavaScript?
#child0 {
height: 0;
overflow: hidden;
background-color: #dedede;
-moz-transition: height 1s ease;
-webkit-transition: height 1s ease;
-o-transition: height 1s ease;
transition: height 1s ease;
}
#parent0:hover #child0 {
height: auto;
}
#child40 {
height: 40px;
overflow: hidden;
background-color: #dedede;
-moz-transition: height 1s ease;
-webkit-transition: height 1s ease;
-o-transition: height 1s ease;
transition: height 1s ease;
}
#parent40:hover #child40 {
height: auto;
}
h1 {
font-weight: bold;
}
The only difference between the two snippets of CSS is one has height: 0, the other height: 40.
<hr>
<div id="parent0">
<h1>Hover me (height: 0)</h1>
<div id="child0">Some content
<br>Some content
<br>Some content
<br>Some content
<br>Some content
<br>Some content
<br>
</div>
</div>
<hr>
<div id="parent40">
<h1>Hover me (height: 40)</h1>
<div id="child40">Some content
<br>Some content
<br>Some content
<br>Some content
<br>Some content
<br>Some content
<br>
</div>
</div>
Use max-height in the transition and not height. And set a value on max-height to something bigger than your box will ever get.
See JSFiddle demo provided by Chris Jordan in another answer here.
#menu #list {
max-height: 0;
transition: max-height 0.15s ease-out;
overflow: hidden;
background: #d5d5d5;
}
#menu:hover #list {
max-height: 500px;
transition: max-height 0.25s ease-in;
}
<div id="menu">
<a>hover me</a>
<ul id="list">
<!-- Create a bunch, or not a bunch, of li's to see the timing. -->
<li>item</li>
<li>item</li>
<li>item</li>
<li>item</li>
<li>item</li>
</ul>
</div>
You should use scaleY instead.
ul {
background-color: #eee;
transform: scaleY(0);
transform-origin: top;
transition: transform 0.26s ease;
}
p:hover ~ ul {
transform: scaleY(1);
}
<p>Hover This</p>
<ul>
<li>Coffee</li>
<li>Tea</li>
<li>Milk</li>
</ul>
I've made a vendor prefixed version of the above code on jsfiddle, and changed your jsfiddle to use scaleY instead of height.
Edit
Some people do not like how scaleY transforms the content. If that is a problem then I suggest using clip instead.
ul {
clip: rect(auto, auto, 0, auto);
position: absolute;
margin: -1rem 0;
padding: .5rem;
color: white;
background-color: rgba(0, 0, 0, 0.8);
transition-property: clip;
transition-duration: 0.5s;
transition-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1.275);
}
h3:hover ~ ul,
h3:active ~ ul,
ul:hover {
clip: rect(auto, auto, 10rem, auto);
}
<h3>Hover here</h3>
<ul>
<li>This list</li>
<li>is clipped.</li>
<li>A clip transition</li>
<li>will show it</li>
</ul>
<p>
Some text...
</p>
You can't currently animate on height when one of the heights involved is auto, you have to set two explicit heights.
The solution that I've always used was to first fade out, then shrink the font-size, padding and margin values. It doesn't look the same as a wipe, but it works without a static height or max-height.
Working example:
/* final display */
#menu #list {
margin: .5em 1em;
padding: 1em;
}
/* hide */
#menu:not(:hover) #list {
font-size: 0;
margin: 0;
opacity: 0;
padding: 0;
/* fade out, then shrink */
transition: opacity .25s,
font-size .5s .25s,
margin .5s .25s,
padding .5s .25s;
}
/* reveal */
#menu:hover #list {
/* unshrink, then fade in */
transition: font-size .25s,
margin .25s,
padding .25s,
opacity .5s .25s;
}
<div id="menu">
<b>hover me</b>
<ul id="list">
<li>item</li>
<li>item</li>
<li>item</li>
<li>item</li>
<li>item</li>
</ul>
</div>
<p>Another paragraph...</p>
This is a CSS-only solution with the following properties:
There is no delay at the beginning, and the transition doesn't stop early. In both directions (expanding and collapsing), if you specify a transition duration of 300ms in your CSS, then the transition takes 300ms, period.
It's transitioning the actual height (unlike transform: scaleY(0)), so it does the right thing if there's content after the collapsible element.
While (like in other solutions) there are magic numbers (like "pick a length that is higher than your box is ever going to be"), it's not fatal if your assumption ends up being wrong. The transition may not look amazing in that case, but before and after the transition, this is not a problem: In the expanded (height: auto) state, the whole content always has the correct height (unlike e.g. if you pick a max-height that turns out to be too low). And in the collapsed state, the height is zero as it should.
Demo
Here's a demo with three collapsible elements, all of different heights, that all use the same CSS. You might want to click "full page" after clicking "run snippet". Note that the JavaScript only toggles the collapsed CSS class, there's no measuring involved. (You could do this exact demo without any JavaScript at all by using a checkbox or :target). Also note that the part of the CSS that's responsible for the transition is pretty short, and the HTML only requires a single additional wrapper element.
$(function () {
$(".toggler").click(function () {
$(this).next().toggleClass("collapsed");
$(this).toggleClass("toggled"); // this just rotates the expander arrow
});
});
.collapsible-wrapper {
display: flex;
overflow: hidden;
}
.collapsible-wrapper:after {
content: '';
height: 50px;
transition: height 0.3s linear, max-height 0s 0.3s linear;
max-height: 0px;
}
.collapsible {
transition: margin-bottom 0.3s cubic-bezier(0, 0, 0, 1);
margin-bottom: 0;
max-height: 1000000px;
}
.collapsible-wrapper.collapsed > .collapsible {
margin-bottom: -2000px;
transition: margin-bottom 0.3s cubic-bezier(1, 0, 1, 1),
visibility 0s 0.3s, max-height 0s 0.3s;
visibility: hidden;
max-height: 0;
}
.collapsible-wrapper.collapsed:after
{
height: 0;
transition: height 0.3s linear;
max-height: 50px;
}
/* END of the collapsible implementation; the stuff below
is just styling for this demo */
#container {
display: flex;
align-items: flex-start;
max-width: 1000px;
margin: 0 auto;
}
.menu {
border: 1px solid #ccc;
box-shadow: 0 1px 3px rgba(0,0,0,0.5);
margin: 20px;
}
.menu-item {
display: block;
background: linear-gradient(to bottom, #fff 0%,#eee 100%);
margin: 0;
padding: 1em;
line-height: 1.3;
}
.collapsible .menu-item {
border-left: 2px solid #888;
border-right: 2px solid #888;
background: linear-gradient(to bottom, #eee 0%,#ddd 100%);
}
.menu-item.toggler {
background: linear-gradient(to bottom, #aaa 0%,#888 100%);
color: white;
cursor: pointer;
}
.menu-item.toggler:before {
content: '';
display: block;
border-left: 8px solid white;
border-top: 8px solid transparent;
border-bottom: 8px solid transparent;
width: 0;
height: 0;
float: right;
transition: transform 0.3s ease-out;
}
.menu-item.toggler.toggled:before {
transform: rotate(90deg);
}
body { font-family: sans-serif; font-size: 14px; }
*, *:after {
box-sizing: border-box;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="container">
<div class="menu">
<div class="menu-item">Something involving a holodeck</div>
<div class="menu-item">Send an away team</div>
<div class="menu-item toggler">Advanced solutions</div>
<div class="collapsible-wrapper collapsed">
<div class="collapsible">
<div class="menu-item">Separate saucer</div>
<div class="menu-item">Send an away team that includes the captain (despite Riker's protest)</div>
<div class="menu-item">Ask Worf</div>
<div class="menu-item">Something involving Wesley, the 19th century, and a holodeck</div>
<div class="menu-item">Ask Q for help</div>
</div>
</div>
<div class="menu-item">Sweet-talk the alien aggressor</div>
<div class="menu-item">Re-route power from auxiliary systems</div>
</div>
<div class="menu">
<div class="menu-item">Something involving a holodeck</div>
<div class="menu-item">Send an away team</div>
<div class="menu-item toggler">Advanced solutions</div>
<div class="collapsible-wrapper collapsed">
<div class="collapsible">
<div class="menu-item">Separate saucer</div>
<div class="menu-item">Send an away team that includes the captain (despite Riker's protest)</div>
</div>
</div>
<div class="menu-item">Sweet-talk the alien aggressor</div>
<div class="menu-item">Re-route power from auxiliary systems</div>
</div>
<div class="menu">
<div class="menu-item">Something involving a holodeck</div>
<div class="menu-item">Send an away team</div>
<div class="menu-item toggler">Advanced solutions</div>
<div class="collapsible-wrapper collapsed">
<div class="collapsible">
<div class="menu-item">Separate saucer</div>
<div class="menu-item">Send an away team that includes the captain (despite Riker's protest)</div>
<div class="menu-item">Ask Worf</div>
<div class="menu-item">Something involving Wesley, the 19th century, and a holodeck</div>
<div class="menu-item">Ask Q for help</div>
<div class="menu-item">Separate saucer</div>
<div class="menu-item">Send an away team that includes the captain (despite Riker's protest)</div>
<div class="menu-item">Ask Worf</div>
<div class="menu-item">Something involving Wesley, the 19th century, and a holodeck</div>
<div class="menu-item">Ask Q for help</div>
</div>
</div>
<div class="menu-item">Sweet-talk the alien aggressor</div>
<div class="menu-item">Re-route power from auxiliary systems</div>
</div>
</div>
How does it work?
There are in fact two transitions involved in making this happen. One of them transitions the margin-bottom from 0px (in the expanded state) to -2000px in the collapsed state (similar to this answer). The 2000 here is the first magic number, it's based on the assumption that your box won't be higher than this (2000 pixels seems like a reasonable choice).
Using the margin-bottom transition alone by itself has two issues:
If you actually have a box that's higher than 2000 pixels, then a margin-bottom: -2000px won't hide everything -- there'll be visible stuff even in the collapsed case. This is a minor fix that we'll do later.
If the actual box is, say, 1000 pixels high, and your transition is 300ms long, then the visible transition is already over after about 150ms (or, in the opposite direction, starts 150ms late).
Fixing this second issue is where the second transition comes in, and this transition conceptually targets the wrapper's minimum height ("conceptually" because we're not actually using the min-height property for this; more on that later).
Here's an animation that shows how combining the bottom margin transition with the minimum height transition, both of equal duration, gives us a combined transition from full height to zero height that has the same duration.
The left bar shows how the negative bottom margin pushes the bottom upwards, reducing the visible height. The middle bar shows how the minimum height ensures that in the collapsing case, the transition doesn't end early, and in the expanding case, the transition doesn't start late. The right bar shows how the combination of the two causes the box to transition from full height to zero height in the correct amount of time.
For my demo I've settled on 50px as the upper minimum height value. This is the second magic number, and it should be lower than the box' height would ever be. 50px seems reasonable as well; it seems unlikely that you'd very often want to make an element collapsible that isn't even 50 pixels high in the first place.
As you can see in the animation, the resulting transition is continuous, but it is not differentiable -- at the moment when the minimum height is equal to the full height adjusted by the bottom margin, there is a sudden change in speed. This is very noticeable in the animation because it uses a linear timing function for both transitions, and because the whole transition is very slow. In the actual case (my demo at the top), the transition only takes 300ms, and the bottom margin transition is not linear. I've played around with a lot of different timing functions for both transitions, and the ones I ended up with felt like they worked best for the widest variety of cases.
Two problems remain to fix:
the point from above, where boxes of more than 2000 pixels height aren't completely hidden in the collapsed state,
and the reverse problem, where in the non-hidden case, boxes of less than 50 pixels height are too high even when the transition isn't running, because the minimum height keeps them at 50 pixels.
We solve the first problem by giving the container element a max-height: 0 in the collapsed case, with a 0s 0.3s transition. This means that it's not really a transition, but the max-height is applied with a delay; it only applies once the transition is over. For this to work correctly, we also need to pick a numerical max-height for the opposite, non-collapsed, state. But unlike in the 2000px case, where picking too large of a number affects the quality of the transition, in this case, it really doesn't matter. So we can just pick a number that is so high that we know that no height will ever come close to this. I picked a million pixels. If you feel you may need to support content of a height of more than a million pixels, then 1) I'm sorry, and 2) just add a couple of zeros.
The second problem is the reason why we're not actually using min-height for the minimum height transition. Instead, there is an ::after pseudo-element in the container with a height that transitions from 50px to zero. This has the same effect as a min-height: It won't let the container shrink below whatever height the pseudo-element currently has. But because we're using height, not min-height, we can now use max-height (once again applied with a delay) to set the pseudo-element's actual height to zero once the transition is over, ensuring that at least outside the transition, even small elements have the correct height. Because min-height is stronger than max-height, this wouldn't work if we used the container's min-height instead of the pseudo-element's height. Just like the max-height in the previous paragraph, this max-height also needs a value for the opposite end of the transition. But in this case we can just pick the 50px.
Tested in Chrome (Win, Mac, Android, iOS), Firefox (Win, Mac, Android), Edge, IE11 (except for a flexbox layout issue with my demo that I didn't bother debugging), and Safari (Mac, iOS). Speaking of flexbox, it should be possible to make this work without using any flexbox; in fact I think you could make almost everything work in IE7 – except for the fact that you won't have CSS transitions, making it a rather pointless exercise.
You can, with a little bit of non-semantic jiggery-pokery. My usual approach is to animate the height of an outer DIV which has a single child which is a style-less DIV used only for measuring the content height.
function growDiv() {
var growDiv = document.getElementById('grow');
if (growDiv.clientHeight) {
growDiv.style.height = 0;
} else {
var wrapper = document.querySelector('.measuringWrapper');
growDiv.style.height = wrapper.clientHeight + "px";
}
}
#grow {
-moz-transition: height .5s;
-ms-transition: height .5s;
-o-transition: height .5s;
-webkit-transition: height .5s;
transition: height .5s;
height: 0;
overflow: hidden;
outline: 1px solid red;
}
<input type="button" onclick="growDiv()" value="grow">
<div id='grow'>
<div class='measuringWrapper'>
<div>
The contents of my div.
</div>
<div>
The contents of my div.
</div>
<div>
The contents of my div.
</div>
<div>
The contents of my div.
</div>
<div>
The contents of my div.
</div>
<div>
The contents of my div.
</div>
</div>
</div>
One would like to just be able to dispense with the .measuringWrapper and just set the DIV's height to auto and have that animate, but that doesn't seem to work (the height gets set, but no animation occurs).
function growDiv() {
var growDiv = document.getElementById('grow');
if (growDiv.clientHeight) {
growDiv.style.height = 0;
} else {
growDiv.style.height = 'auto';
}
}
#grow {
-moz-transition: height .5s;
-ms-transition: height .5s;
-o-transition: height .5s;
-webkit-transition: height .5s;
transition: height .5s;
height: 0;
overflow: hidden;
outline: 1px solid red;
}
<input type="button" onclick="growDiv()" value="grow">
<div id='grow'>
<div>
The contents of my div.
</div>
<div>
The contents of my div.
</div>
<div>
The contents of my div.
</div>
<div>
The contents of my div.
</div>
<div>
The contents of my div.
</div>
<div>
The contents of my div.
</div>
</div>
My interpretation is that an explicit height is needed for the animation to run. You can't get an animation on height when either height (the start or end height) is auto.
The accepted answer works for most cases, but it doesn't work well when your div can vary greatly in height — the animation speed is not dependent on the actual height of the content, and it can look choppy.
You can still perform the actual animation with CSS, but you need to use JavaScript to compute the height of the items, instead of trying to use auto. No jQuery is required, although you may have to modify this a bit if you want compatibility (works in the latest version of Chrome :)).
window.toggleExpand = function(element) {
if (!element.style.height || element.style.height == '0px') {
element.style.height = Array.prototype.reduce.call(element.childNodes, function(p, c) {return p + (c.offsetHeight || 0);}, 0) + 'px';
} else {
element.style.height = '0px';
}
}
#menu #list {
height: 0px;
transition: height 0.3s ease;
background: #d5d5d5;
overflow: hidden;
}
<div id="menu">
<input value="Toggle list" type="button" onclick="toggleExpand(document.getElementById('list'));">
<ul id="list">
<!-- Works well with dynamically-sized content. -->
<li>item</li>
<li><div style="height: 100px; width: 100px; background: red;"></div></li>
<li>item</li>
<li>item</li>
<li>item</li>
</ul>
</div>
A visual workaround to animating height using CSS3 transitions is to animate the padding instead.
You don't quite get the full wipe effect, but playing around with the transition-duration and padding values should get you close enough. If you don't want to explicitly set height/max-height, this should be what you're looking for.
div {
height: 0;
overflow: hidden;
padding: 0 18px;
-webkit-transition: all .5s ease;
-moz-transition: all .5s ease;
transition: all .5s ease;
}
div.animated {
height: auto;
padding: 24px 18px;
}
http://jsfiddle.net/catharsis/n5XfG/17/ (riffed off stephband's above jsFiddle)
My workaround is to transition max-height to the exact content height for a nice smooth animation, then use a transitionEnd callback to set max-height to 9999px so the content can resize freely.
var content = $('#content');
content.inner = $('#content .inner'); // inner div needed to get size of content when closed
// css transition callback
content.on('transitionEnd webkitTransitionEnd transitionend oTransitionEnd msTransitionEnd', function(e){
if(content.hasClass('open')){
content.css('max-height', 9999); // try setting this to 'none'... I dare you!
}
});
$('#toggle').on('click', function(e){
content.toggleClass('open closed');
content.contentHeight = content.outerHeight();
if(content.hasClass('closed')){
// disable transitions & set max-height to content height
content.removeClass('transitions').css('max-height', content.contentHeight);
setTimeout(function(){
// enable & start transition
content.addClass('transitions').css({
'max-height': 0,
'opacity': 0
});
}, 10); // 10ms timeout is the secret ingredient for disabling/enabling transitions
// chrome only needs 1ms but FF needs ~10ms or it chokes on the first animation for some reason
}else if(content.hasClass('open')){
content.contentHeight += content.inner.outerHeight(); // if closed, add inner height to content height
content.css({
'max-height': content.contentHeight,
'opacity': 1
});
}
});
.transitions {
transition: all 0.5s ease-in-out;
-webkit-transition: all 0.5s ease-in-out;
-moz-transition: all 0.5s ease-in-out;
}
body {
font-family:Arial;
line-height: 3ex;
}
code {
display: inline-block;
background: #fafafa;
padding: 0 1ex;
}
#toggle {
display:block;
padding:10px;
margin:10px auto;
text-align:center;
width:30ex;
}
#content {
overflow:hidden;
margin:10px;
border:1px solid #666;
background:#efefef;
opacity:1;
}
#content .inner {
padding:10px;
overflow:auto;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<div id="content" class="open">
<div class="inner">
<h3>Smooth CSS Transitions Between <code>height: 0</code> and <code>height: auto</code></h3>
<p>A clever workaround is to use <code>max-height</code> instead of <code>height</code>, and set it to something bigger than your content. Problem is the browser uses this value to calculate transition duration. So if you set it to <code>max-height: 1000px</code> but the content is only 100px high, the animation will be 10x too fast.</p>
<p>Another option is to measure the content height with JS and transition to that fixed value, but then you have to keep track of the content and manually resize it if it changes.</p>
<p>This solution is a hybrid of the two - transition to the measured content height, then set it to <code>max-height: 9999px</code> after the transition for fluid content sizing.</p>
</div>
</div>
<br />
<button id="toggle">Challenge Accepted!</button>
Use max-height with different transition easing and delay for each state.
HTML:
Hover
<ul id="toggled">
<li>One</li>
<li>Two</li>
<li>Three</li>
<ul>
CSS:
#toggled{
max-height: 0px;
transition: max-height .8s cubic-bezier(0, 1, 0, 1) -.1s;
}
#trigger:hover + #toggled{
max-height: 9999px;
transition-timing-function: cubic-bezier(0.5, 0, 1, 0);
transition-delay: 0s;
}
See example: http://jsfiddle.net/0hnjehjc/1/
No hard coded values.
No JavaScript.
No approximations.
The trick is to use a hidden & duplicated div to get the browser to understand what 100% means.
This method is suitable whenever you're able to duplicate the DOM of the element you wish to animate.
.outer {
border: dashed red 1px;
position: relative;
}
.dummy {
visibility: hidden;
}
.real {
position: absolute;
background: yellow;
height: 0;
transition: height 0.5s;
overflow: hidden;
}
.outer:hover>.real {
height: 100%;
}
Hover over the box below:
<div class="outer">
<!-- The actual element that you'd like to animate -->
<div class="real">
unpredictable content unpredictable content unpredictable content unpredictable content unpredictable content unpredictable content unpredictable content unpredictable content unpredictable content unpredictable content unpredictable content unpredictable
content unpredictable content unpredictable content unpredictable content
</div>
<!-- An exact copy of the element you'd like to animate. -->
<div class="dummy" aria-hidden="true">
unpredictable content unpredictable content unpredictable content unpredictable content unpredictable content unpredictable content unpredictable content unpredictable content unpredictable content unpredictable content unpredictable content unpredictable
content unpredictable content unpredictable content unpredictable content
</div>
</div>
According to MDN Web Docs, auto values have been intentionally excluded from the CSS transitions spec, so instead of height: auto, use height: 100%, top, or the flex property in grid and flex layouts.
Expanding/collapsing an overlay
.grid-container {
display: grid;
position: absolute;
}
.content {
background: aqua;
height: 0;
overflow: hidden;
transition: 1s;
}
span:hover + .grid-container .content {
height: 100%;
}
<span>Hover over me!</span>
<div class="grid-container">
<div class="content">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</div>
</div>
<p>Rest of the page content...</p>
Expanding/collapsing a sliding overlay
.grid-container {
display: grid;
position: absolute;
overflow: hidden;
pointer-events: none; /* to enable interaction with elements below the container */
}
.content {
background: aqua;
pointer-events: auto;
position: relative;
top: -100%;
transition: 1s;
}
span:hover + .grid-container .content {
top: 0;
}
<span>Hover over me!</span>
<div class="grid-container">
<div class="content">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</div>
</div>
<p>Rest of the page content...</p>
Expanding/collapsing in the document flow
html {
display: grid;
}
body {
display: flex;
flex-direction: column;
}
.content {
background: aqua;
flex-basis: 0;
overflow: hidden;
transition: 1s;
}
span:hover + .content {
flex: 1;
}
<span>Hover over me!</span>
<div class="content">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</div>
<p>Rest of the page content...</p>
As I post this there are over 30 answers already, but I feel my answer improves on the already accepted answer by jake.
I was not content with the issue that arises from simply using max-height and CSS3 transitions, since as many commenters noted, you have to set your max-height value very close to the actual height or you'll get a delay. See this JSFiddle for an example of that problem.
To get around this (while still using no JavaScript), I added another HTML element that transitions the transform: translateY CSS value.
This means both max-height and translateY are used: max-height allows the element to push down elements below it, while translateY gives the "instant" effect we want. The issue with max-height still exists, but its effect is lessened.
This means you can set a much larger height for your max-height value and worry about it less.
The overall benefit is that on the transition back in (the collapse), the user sees the translateY animation immediately, so it doesn't really matter how long the max-height takes.
Solution as Fiddle
body {
font-family: sans-serif;
}
.toggle {
position: relative;
border: 2px solid #333;
border-radius: 3px;
margin: 5px;
width: 200px;
}
.toggle-header {
margin: 0;
padding: 10px;
background-color: #333;
color: white;
text-align: center;
cursor: pointer;
}
.toggle-height {
background-color: tomato;
overflow: hidden;
transition: max-height .6s ease;
max-height: 0;
}
.toggle:hover .toggle-height {
max-height: 1000px;
}
.toggle-transform {
padding: 5px;
color: white;
transition: transform .4s ease;
transform: translateY(-100%);
}
.toggle:hover .toggle-transform {
transform: translateY(0);
}
<div class="toggle">
<div class="toggle-header">
Toggle!
</div>
<div class="toggle-height">
<div class="toggle-transform">
<p>Content!</p>
<p>Content!</p>
<p>Content!</p>
<p>Content!</p>
</div>
</div>
</div>
<div class="toggle">
<div class="toggle-header">
Toggle!
</div>
<div class="toggle-height">
<div class="toggle-transform">
<p>Content!</p>
<p>Content!</p>
<p>Content!</p>
<p>Content!</p>
</div>
</div>
</div>
No max-height, uses relative positioning, works on li elements, & is pure CSS:
I have not tested in anything but Firefox, though judging by the CSS, it should work on all browsers.
FIDDLE: http://jsfiddle.net/n5XfG/2596/
CSS
.wrap { overflow:hidden; }
.inner {
margin-top:-100%;
-webkit-transition:margin-top 500ms;
transition:margin-top 500ms;
}
.inner.open { margin-top:0px; }
HTML
<div class="wrap">
<div class="inner">Some Cool Content</div>
</div>
EDIT: Scroll down for updated answer
I was making a drop down list and saw this Post ... many different answers but I decide to share my drop down list too, ... It's not perfect but at least it will using only css for drop down! I've been using transform:translateY(y) to transform the list to the view ...
You can see more in the test
http://jsfiddle.net/BVEpc/4/
I've placed div behind every li because my drop down list are coming from up and to show them properly this was needed, my div code is:
#menu div {
transition: 0.5s 1s;
z-index:-1;
-webkit-transform:translateY(-100%);
-webkit-transform-origin: top;
}
and hover is :
#menu > li:hover div {
transition: 0.5s;
-webkit-transform:translateY(0);
}
and because ul height is set to the content it can get over your body content that's why I did this for ul:
#menu ul {
transition: 0s 1.5s;
visibility:hidden;
overflow:hidden;
}
and hover:
#menu > li:hover ul {
transition:none;
visibility:visible;
}
the second time after transition is delay and it will get hidden after my drop down list has been closed animately ...
Hope later someone get benefit of this one.
EDIT: I just can't believe ppl actually using this prototype! this drop down menu is only for one sub menu and that's all!!
I've updated a better one that can have two sub menu for both ltr and rtl direction with IE 8 support.
Fiddle for LTR
Fiddle for RTL
hopefully someone find this useful in future.
You can transition from height:0 to height:auto providing that you also provide min-height and max-height.
div.stretchy{
transition: 1s linear;
}
div.stretchy.hidden{
height: 0;
}
div.stretchy.visible{
height: auto;
min-height:40px;
max-height:400px;
}
Flexbox Solution
Pros:
simple
no JS
smooth transition
Cons:
element needs to be put in a fixed height flex container
The way it works is by always having flex-basis: auto on the element with content, and transitioning flex-grow and flex-shrink instead.
Edit: Improved JS Fiddle inspired by the Xbox One interface.
* {
margin: 0;
padding: 0;
box-sizing: border-box;
transition: 0.25s;
font-family: monospace;
}
body {
margin: 10px 0 0 10px;
}
.box {
width: 150px;
height: 150px;
margin: 0 2px 10px 0;
background: #2d333b;
border: solid 10px #20262e;
overflow: hidden;
display: inline-flex;
flex-direction: column;
}
.space {
flex-basis: 100%;
flex-grow: 1;
flex-shrink: 0;
}
p {
flex-basis: auto;
flex-grow: 0;
flex-shrink: 1;
background: #20262e;
padding: 10px;
width: 100%;
text-align: left;
color: white;
}
.box:hover .space {
flex-grow: 0;
flex-shrink: 1;
}
.box:hover p {
flex-grow: 1;
flex-shrink: 0;
}
<div class="box">
<div class="space"></div>
<p>
Super Metroid Prime Fusion
</p>
</div>
<div class="box">
<div class="space"></div>
<p>
Resident Evil 2 Remake
</p>
</div>
<div class="box">
<div class="space"></div>
<p>
Yolo The Game
</p>
</div>
<div class="box">
<div class="space"></div>
<p>
Final Fantasy 7 Remake + All Additional DLC + Golden Tophat
</p>
</div>
<div class="box">
<div class="space"></div>
<p>
DerpVille
</p>
</div>
JS Fiddle
One sentence solution: Use padding transition. It's enough for most of cases such as accordion, and even better because it's fast due to that the padding value is often not big.
If you want the animation process to be better, just raise the padding value.
.parent{ border-top: #999 1px solid;}
h1{ margin: .5rem; font-size: 1.3rem}
.children {
height: 0;
overflow: hidden;
background-color: #dedede;
transition: padding .2s ease-in-out, opacity .2s ease-in-out;
padding: 0 .5rem;
opacity: 0;
}
.children::before, .children::after{ content: "";display: block;}
.children::before{ margin-top: -2rem;}
.children::after{ margin-bottom: -2rem;}
.parent:hover .children {
height: auto;
opacity: 1;
padding: 2.5rem .5rem;/* 0.5 + abs(-2), make sure it's less than expected min-height */
}
<div class="parent">
<h1>Hover me</h1>
<div class="children">Some content
<br>Some content
<br>Some content
<br>Some content
<br>Some content
<br>Some content
<br>
</div>
</div>
<div class="parent">
<h1>Hover me(long content)</h1>
<div class="children">Some content
<br>Some content<br>Some content
<br>Some content<br>Some content
<br>Some content<br>Some content
<br>Some content<br>Some content
<br>Some content<br>Some content
<br>
</div>
</div>
<div class="parent">
<h1>Hover me(short content)</h1>
<div class="children">Some content
<br>Some content
<br>Some content
<br>
</div>
</div>
Expanding on #jake's answer, the transition will go all the way to the max height value, causing an extremely fast animation - if you set the transitions for both :hover and off you can then control the crazy speed a little bit more.
So the li:hover is when the mouse enters the state and then the transition on the non-hovered property will be the mouse leave.
Hopefully this will be of some help.
e.g:
.sidemenu li ul {
max-height: 0px;
-webkit-transition: all .3s ease;
-moz-transition: all .3s ease;
-o-transition: all .3s ease;
-ms-transition: all .3s ease;
transition: all .3s ease;
}
.sidemenu li:hover ul {
max-height: 500px;
-webkit-transition: all 1s ease;
-moz-transition: all 1s ease;
-o-transition: all 1s ease;
-ms-transition: all 1s ease;
transition: all 1s ease;
}
/* Adjust speeds to the possible height of the list */
Here's a fiddle: http://jsfiddle.net/BukwJ/
This solution uses a few techniques:
padding-bottom:100% 'hack' where percentages are defined in terms of the current width of the element. More info on this technique.
float shrink-wrapping, (necessitating an extra div to apply the float clearing hack)
non-semantic use of https://caniuse.com/#feat=css-writing-mode and some transformations to undo it (this allows use of the padding hack above in a vertical context)
The upshot though is that we get performant transitioning using CSS only, and a single transition function to smoothly achieve the transition; the holy grail!
Of course, there's a downside! I can't work out how to control the width at which content gets cut off (overflow:hidden); because of the padding-bottom hack, the width and height are intimately related. There may be a way though, so will come back to it.
https://jsfiddle.net/EoghanM/n1rp3zb4/28/
body {
padding: 1em;
}
.trigger {
font-weight: bold;
}
/* .expander is there for float clearing purposes only */
.expander::after {
content: '';
display: table;
clear: both;
}
.outer {
float: left; /* purpose: shrink to fit content */
border: 1px solid green;
overflow: hidden;
}
.inner {
transition: padding-bottom 0.3s ease-in-out; /* or whatever crazy transition function you can come up with! */
padding-bottom: 0%; /* percentage padding is defined in terms of width. The width at this level is equal to the height of the content */
height: 0;
/* unfortunately, change of writing mode has other bad effects like orientation of cursor */
writing-mode: vertical-rl;
cursor: default; /* don't want the vertical-text (sideways I-beam) */
transform: rotate(-90deg) translateX(-100%); /* undo writing mode */
transform-origin: 0 0;
margin: 0; /* left/right margins here will add to height */
}
.inner > div { white-space: nowrap; }
.expander:hover .inner, /* to keep open when expanded */
.trigger:hover+.expander .inner {
padding-bottom: 100%;
}
<div class="trigger">HoverMe</div>
<div class="expander">
<div class="outer">
<div class="inner">
<div>First Item</div>
<div>Content</div>
<div>Content</div>
<div>Content</div>
<div>Long Content can't be wider than outer height unfortunately</div>
<div>Last Item</div>
</div>
</div>
</div>
<div>
after content</div>
</div>
A lot of answers, some better than other, most using JS. I believe I figured this out in two use-cases that are easy to understand.
Toggle an overlay
.demo01 {
overflow: hidden;
position: absolute;
pointer-events: none;
}
.demo01__content {
background: lightgray;
padding: 1rem;
pointer-events: all;
transform: translateY(-100%);
transition: transform 1s, visibility 1s;
visibility: hidden;
}
:checked ~ .demo01 .demo01__content {
transform: translateY(0);
visibility: visible;
}
<input type="checkbox" /> ⬅︎ Toggle
<div>Something before 🙃</div>
<div class="demo01">
<div class="demo01__content">
This content should…<br />
toggle! 👻
</div>
</div>
<div>Something after 🙂</div>
Toggle in the document flow
.demo02 {
display: grid;
grid-template-rows: 0fr;
overflow: hidden;
transition: grid-template-rows 1s;
}
.demo02__content {
align-self: end;
min-height: 0;
background: lightgray;
transition: visibility 1s;
visibility: hidden;
}
.demo02__padding {
padding: 1rem;
}
:checked ~ .demo02 {
grid-template-rows: 1fr;
}
:checked ~ .demo02 .demo02__content {
visibility: visible;
}
<input type="checkbox" /> ⬅︎ Toggle
<div>Something before 🙃</div>
<div class="demo02">
<div class="demo02__content">
<div class="demo02__padding">
This content should…<br />
toggle! 👻
</div>
</div>
</div>
<div>Something after 🙂</div>
I wrote a blog post about these techniques.
I've recently been transitioning the max-height on the li elements rather than the wrapping ul.
The reasoning is that the delay for small max-heights is far less noticeable (if at all) compared to large max-heights, and I can also set my max-height value relative to the font-size of the li rather than some arbitrary huge number by using ems or rems.
If my font size is 1rem, I'll set my max-height to something like 3rem (to accommodate wrapped text). You can see an example here:
http://codepen.io/mindfullsilence/pen/DtzjE
You could do this by creating a reverse (collapse) animation with clip-path.
#child0 {
display: none;
}
#parent0:hover #child0 {
display: block;
animation: height-animation;
animation-duration: 200ms;
animation-timing-function: linear;
animation-fill-mode: backwards;
animation-iteration-count: 1;
animation-delay: 200ms;
}
#keyframes height-animation {
0% {
clip-path: polygon(0% 0%, 100% 0.00%, 100% 0%, 0% 0%);
}
100% {
clip-path: polygon(0% 0%, 100% 0.00%, 100% 100%, 0% 100%);
}
}
<div id="parent0">
<h1>Hover me (height: 0)</h1>
<div id="child0">Some content
<br>Some content
<br>Some content
<br>Some content
<br>Some content
<br>Some content
<br>
</div>
</div>
Flexible Height CSS Only Solution
I've stumbled upon a quirky solution using flex behavior. It works in at least Chrome and Firefox.
First, the height transition only works between 0 and 100%, two
numeric values. Since "auto" is not a numeric value, fractional
increments don't exist between 0 and "auto". 100% is a flexible
value, so no specific height is required.
Second, both the outer container and the inner container of the hidden content must be set to display: flex with flex-direction: column.
Third, the outer container must have a height property. Setting it to 0 maintains a smooth transition only when everything is contained in the outer container because the flex behavior takes precedence over the height. Edit: Json suggested using height: fit-content, so that any content below the container is also pushed down.
.outer-container { height: 0; display: flex; flex-direction: column; }
.inner-container { display: flex; flex-direction: column; }
.hidden-content {
height: 0;
opacity: 0;
transition: height 1s 0.5s ease-in-out, opacity 0.5s ease-in-out;
/* transition out: first fade out opacity, then shrink height after a delay equal to the opacity duration */
}
.trigger:hover + .inner-container > .hidden-content {
height: 100%;
opacity: 1;
transition: height 1s ease-in-out, opacity 0.5s 1s ease-in-out;
/* transition in: first expand height, then fade in opacity after a delay equal to the height duration */
}
<div class="outer-container">
Hover to Reveal Inner Container's Hidden Content
<div class="inner-container">
<div class="hidden-content">This is hidden content. When triggered by hover, its height transitions from 0 to 100%, which pushes other content in the same container down gradually.</div>
<div>Within the same container, this other content is pushed down gradually as the hidden content's height transitions from 0 to 100%.</div>
</div>
</div>
Press the Run Code Snippet button to see the transition in action.
It's CSS only, with no specific height.
I understand the question asks for a solution without JavaScript. But for those interested here's my solution using just a little bit of JS.
ok, so the element's css whose height will change by default is set to height: 0; and when open height: auto;. It also has transition: height .25s ease-out;. But of course the problem is that it won't transition to or from height: auto;
So what i've done is when opening or closing set the height to the scrollHeight property of the element. This new inline style will have higher specificity and override both height: auto; and height: 0; and the transition runs.
When opening i add a transitionend event listener which will run just once then remove the inline style setting it back to height: auto; which will allow the element to resize if necessary, as in this more complex example with sub menus https://codepen.io/ninjabonsai/pen/GzYyVe
When closing i remove the inline style right after the next event loop cycle by using setTimeout with no delay. This means height: auto; is temporarily overridden which allows the transition back to height 0;
const showHideElement = (element, open) => {
element.style.height = element.scrollHeight + 'px';
element.classList.toggle('open', open);
if (open) {
element.addEventListener('transitionend', () => {
element.style.removeProperty('height');
}, {
once: true
});
} else {
window.setTimeout(() => {
element.style.removeProperty('height');
});
}
}
const menu = document.body.querySelector('#menu');
const list = document.body.querySelector('#menu > ul')
menu.addEventListener('mouseenter', () => showHideElement(list, true));
menu.addEventListener('mouseleave', () => showHideElement(list, false));
#menu > ul {
height: 0;
overflow: hidden;
background-color: #999;
transition: height .25s ease-out;
}
#menu > ul.open {
height: auto;
}
<div id="menu">
<a>hover me</a>
<ul>
<li>item</li>
<li>item</li>
<li>item</li>
<li>item</li>
<li>item</li>
</ul>
</div>
Alternate CSS-only solution with line-height, padding, opacity and margin:
body {
background-color: linen;
}
main {
background-color: white;
}
[id^="toggle_"] ~ .content {
line-height: 0;
opacity: 0;
padding: 0 .5rem;
transition: .2s ease-out;
}
[id^="toggle_"] ~ .content > p {
margin: 0;
transition: .2s ease-out;
}
[id^="toggle_"]:checked ~ .content {
opacity: 1;
padding: .5rem;
line-height: 1.5;
}
[id^="toggle_"]:checked ~ .content p {
margin-bottom: .75rem;
}
[id^="toggle_"] + label {
display: flex;
justify-content: space-between;
padding: 0.5em 1em;
background: lightsteelblue;
border-bottom: 1px solid gray;
cursor: pointer;
}
[id^="toggle_"] + label:before {
content: "Show";
}
[id^="toggle_"]:checked + label:before {
content: "Hide";
}
[id^="toggle_"] + label:after {
content: "\25BC";
}
[id^="toggle_"]:checked + label:after {
content: "\25B2";
}
<main>
<div>
<input type="checkbox" id="toggle_1" hidden>
<label for="toggle_1" hidden></label>
<div class="content">
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis dolor neque, commodo quis leo ut, auctor tincidunt mauris. Nunc fringilla tincidunt metus, non gravida lorem condimentum non. Duis ornare purus nisl, at porta arcu eleifend eget. Integer lorem ante, porta vulputate dui ut, blandit tempor tellus. Proin facilisis bibendum diam, sit amet rutrum est feugiat ut. Mauris rhoncus convallis arcu in condimentum. Donec volutpat dui eu mollis vulputate. Nunc commodo lobortis nunc at ultrices. Suspendisse in lobortis diam. Suspendisse eget vestibulum ex.
</p>
</div>
</div>
<div>
<input type="checkbox" id="toggle_2" hidden>
<label for="toggle_2" hidden></label>
<div class="content">
<p>
Maecenas laoreet nunc sit amet nulla ultrices auctor. Vivamus sed nisi vitae nibh condimentum pulvinar eu vel lorem. Sed pretium viverra eros ut facilisis. In ut fringilla magna. Sed a tempor libero. Donec sapien libero, lacinia sed aliquet ut, imperdiet finibus tellus. Nunc tellus lectus, rhoncus in posuere quis, tempus sit amet enim. Morbi et erat ac velit fringilla dignissim. Donec commodo, est id accumsan cursus, diam dui hendrerit nisi, vel hendrerit purus dolor ut risus. Phasellus mattis egestas ipsum sed ullamcorper. In diam ligula, rhoncus vel enim et, imperdiet porta justo. Curabitur vulputate hendrerit nisl, et ultricies diam. Maecenas ac leo a diam cursus ornare nec eu quam.
</p>
<p>Sed non vulputate purus, sed consectetur odio. Sed non nibh fringilla, imperdiet odio nec, efficitur ex. Suspendisse ut dignissim enim. Maecenas felis augue, tempor sit amet sem fringilla, accumsan fringilla nibh. Quisque posuere lacus tortor, quis malesuada magna elementum a. Nullam id purus in ante molestie tincidunt. Morbi luctus orci eu egestas dignissim. Sed tincidunt, libero quis scelerisque bibendum, ligula nisi gravida libero, id lacinia nulla leo in elit.
</p>
<p>Aenean aliquam risus id consectetur sagittis. Aliquam aliquam nisl eu augue accumsan, vel maximus lorem viverra. Aliquam ipsum dolor, tempor et justo ac, fermentum mattis dui. Etiam at posuere ligula. Vestibulum tortor metus, viverra vitae mi non, laoreet iaculis purus. Praesent vel semper nibh. Curabitur a congue lacus. In et pellentesque lorem. Morbi posuere felis non diam vulputate, non vulputate ex vehicula. Vivamus ultricies, massa id sagittis consequat, sem mauris tincidunt nunc, eu vehicula augue quam ut mauris.
</p>
</div>
</div>
<div>
<input type="checkbox" id="toggle_3" hidden>
<label for="toggle_3" hidden></label>
<div class="content">
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis dolor neque, commodo quis leo ut, auctor tincidunt mauris. Nunc fringilla tincidunt metus, non gravida lorem condimentum non. Duis ornare purus nisl, at porta arcu eleifend eget. Integer lorem ante, porta vulputate dui ut, blandit tempor tellus. Proin facilisis bibendum diam, sit amet rutrum est feugiat ut. Mauris rhoncus convallis arcu in condimentum. Donec volutpat dui eu mollis vulputate. Nunc commodo lobortis nunc at ultrices. Suspendisse in lobortis diam. Suspendisse eget vestibulum ex.
</p>
<p>Sed non vulputate purus, sed consectetur odio. Sed non nibh fringilla, imperdiet odio nec, efficitur ex. Suspendisse ut dignissim enim. Maecenas felis augue, tempor sit amet sem fringilla, accumsan fringilla nibh. Quisque posuere lacus tortor, quis malesuada magna elementum a. Nullam id purus in ante molestie tincidunt. Morbi luctus orci eu egestas dignissim. Sed tincidunt, libero quis scelerisque bibendum, ligula nisi gravida libero, id lacinia nulla leo in elit.
</p>
</div>
</div>
</main>
Set the style="" attributes for tracked elements whenever there's a change in the DOM. plugin called mutant-transition You can use CSS for your transitions and not use hacks. You don't have to write any JavaScript. Just include the JavaScript library and specify which attributes you want to watch in the HTML. You don't have to use fixed height CSS. Set what you want to track on the element in question using data-mutant-attributes="X".
<div data-mutant-attributes="height">
This is an example with mutant-transition
</div>
This uses MutationObserver to follow changes in the DOM. You don't have to set anything up or use JavaScript to manually animate. Changes are tracked automatically. However, because it uses MutationObserver, this will only transition in IE11+. < IE11 will see snap-changes (no transition).
Fiddles
Demonstrating transitioning from height: auto to height: 100%
Demonstrating transitioning height: auto when adding children
Jake's answer to animate the max-height is great, but I found the delay caused by setting a large max-height annoying.
One could move the collapsable content into an inner div and calculate the max height by getting the height of the inner div (via JQuery it'd be the outerHeight()).
$('button').bind('click', function(e) {
e.preventDefault();
w = $('#outer');
if (w.hasClass('collapsed')) {
w.css({ "max-height": $('#inner').outerHeight() + 'px' });
} else {
w.css({ "max-height": "0px" });
}
w.toggleClass('collapsed');
});
Here's a jsfiddle link: http://jsfiddle.net/pbatey/duZpT
Here's a jsfiddle with the absolute minimal amount of code required: http://jsfiddle.net/8ncjjxh8/
I was able to do this. I have a .child & a .parent div. The child div fits perfectly within the parent's width/height with absolute positioning. I then animate the translate property to push it's Y value down 100%. Its very smooth animation, no glitches or down sides like any other solution here.
Something like this, pseudo code
.parent{ position:relative; overflow:hidden; }
/** shown state */
.child {
position:absolute;top:0;:left:0;right:0;bottom:0;
height: 100%;
transition: transform #overlay-animation-duration ease-in-out;
.translate(0, 0);
}
/** Animate to hidden by sliding down: */
.child.slidedown {
.translate(0, 100%); /** Translate the element "out" the bottom of it's .scene container "mask" so its hidden */
}
You would specify a height on .parent, in px, %, or leave as auto. This div then masks out the .child div when it slides down.
I have not read everything in detail but I have had this problem recently and I did what follows:
div.class{
min-height:1%;
max-height:200px;
-webkit-transition: all 0.5s ease;
-moz-transition: all 0.5s ease;
-o-transition: all 0.5s ease;
-webkit-transition: all 0.5s ease;
transition: all 0.5s ease;
overflow:hidden;
}
div.class:hover{
min-height:100%;
max-height:3000px;
}
This allows you to have a div that at first shows content up to 200px height and on hover it's size becomes at least as high as the whole content of the div. The Div does not become 3000px but 3000px is the limit that I am imposing. Make sure to have the transition on the non :hover, otherwise you might get some strange rendering. In this way the :hover inherits from the non :hover.
Transition does not work form px to % or to auto. You need to use same unit of measure.

I have a div that constantly changes height. How can I get a second div to constantly adopt the height that the first div is?

I have a div that contains a list of items. The user is able to add to/remove items from the list, so the div constantly changes height to compensate for the changing size of the list.
I have another div to its right that is supposed to give details about the items on the left. How can I get the div on the right to constantly keep vertically aligned with the left div and change height so that it equals the height that the left div currently is, as items are added and removed from the left div's list?
display:table-cell will help you here:
div { display:table-cell; border:1px solid; }
<div id=master>
one<br>two
</div>
<div>
three
</div>
It's hard to answer your question without showing your code. Try putting it in a fiddle? https://jsfiddle.net/
Here's what I would say. Put your left and right divs into a container div, and then have the left and right div's inherit the containers height.
<div id="container" style="height:200px">
<div style="float: left; height: 100%">
list items<br />
list items<br />
list items
</div>
<div style="float: left; height: 100%; border: 1px solid black;">
right div
</div>
</div>
<br /><br />
<button onclick="document.getElementById('container').style.height='20px'" />
Remove height from both of them, and wrap a div around both of them where you add the height.
This function is called whenever something on the document changes, and it sets the height of div2 to the value for the height of div1
<script type='text/javascript'>
document.onchange=setDivHeight();
function setDivHeight(){
var x=Number(document.getElementById('1').style.height)
document.getElementById('2').style.height=x;
}
</script>
<div id="1"></div>
<div id="2"></div>
Flexbox Solution
This answer is adapted from an example on css-tricks - Check it out
Assuming the following markup:
<div class="wrapper">
<article class="main">
<p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.</p>
</article>
<aside class="aside">
<ul>
<li>Item</li>
<li>Item</li>
<li>Item</li>
<li>Item</li>
<li>Item</li>
<li>Item</li>
<li>Item</li>
<li>Item</li>
<li>Item</li>
<li>Item</li>
</ul>
</aside>
</div>
We can create a flexbox that will force all columns to conform to the height of the largest with the following styles:
.wrapper {
display: -webkit-box;
display: -moz-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
-webkit-flex-flow: row nowrap;
flex-flow: row nowrap;
font-weight: bold;
text-align: center;
}
.wrapper > * {
padding: 10px;
flex: 1 100%;
}
.main {
text-align: left;
background: deepskyblue;
order: 2;
flex: 3 0px;
}
.aside {
background: gold;
max-width: 200px;
order: 1;
}
body {
padding: 2em;
}
Here's a fiddle
NOTE: Browser support for this solution is limited to IE10+, and the use of browser prefixes still applies to most versions of major browsers. For a more thorough breakdown of how flexbox works, I highly recommend that you check out the article I've linked to above.

Hover a div on other div with some opacity using css

My requirement is to get a div overlapping another div at the bottom, as you can see in the first picture, and when you hover on the image I need it to get an effect like in the second image.
Here is my html code, but I don't know how to handle mouse events correctly.
<div id="container">
<div class="overlay">This is overlay div.</div>
<div class="content">This is contents div. This is contents div.</div>
</div>
#container {
position: relative;
}
.overlay,
.content{
display:block;
position: absolute;
top: 0;
left: 0;
}
.overlay,
.content{
display:block;
position: absolute;
top: 0;
left: 0;
}
But it doesn't work as I wanted. Could anyone give me some suggestions?
http://jsfiddle.net/mAzsL/
Here ya go man.
<div class="container">
<div class="lower">Blah Blah Blah</div>
<div class="show">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent feugiat elit vel tortor porta, sit amet venenatis purus condimentum. Suspendisse potenti. Aenean ultrices velit ac mattis volutpat. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae</div>
</div>
.container{
width:250px;
height:300px;
background:#00f;
position:relative;
}
.lower{
position:absolute;
bottom:0;
width:100%;
color:#fff;
padding:10px 0;
text-indent:5px;
background:rgba(0,0,0,.5);
}
.show{
display:none;
height:100%;
width:100%;
color:#000;
text-indent:5px;
background:rgba(255,255,255,.5);
}
.container:hover > .lower{
display:none;
}
.container:hover > .show{
display:block;
}
Here is a fiddle of the same thing, but with the content sliding up into place. I added this because SiKni8 asked why it did not slide up.
http://jsfiddle.net/mAzsL/15/
Essentially, I moved all content into one container, added transition on hover. Pretty simple changes.
something like
<div class="container">
<img src="http://placehold.it/150X200/fff000" />
<div class="inner">
somecontent goes here
<div class="overlay">sho on hover</div>
</div>
</div>
and
.container {
position: relative;
display: inline-block;
}
.container .inner {
position: absolute;
bottom: 0;
opacity: .85;
}
.container .inner .overlay {
display: none;
}
.container:hover .inner .overlay {
display: block;
}
Demo: Fiddle

Categories