Skip to content

Instantly share code, notes, and snippets.

@andrewgrewell
Last active August 29, 2015 14:19
Show Gist options
  • Save andrewgrewell/cdda9682737ce9315afb to your computer and use it in GitHub Desktop.
Save andrewgrewell/cdda9682737ce9315afb to your computer and use it in GitHub Desktop.
Animate Container Height Change

Animate Container Height Change

A better solution for animating a change in an elements height when children are added.

SANS REACT: Without react this is usually done by adding the child to the DOM in such a way that it doesn't effect the positioning of existing elements, measure its height and use that info to animate the parent to a new height.

THE REACT WAY: By using React we can respond to changes in an elements children and adjust the height of the parent accordingly.

A Pen by Andrew Grewell on CodePen.

License.

<div id="reactEl" />
/*
DISCLAIMER: This code is not optimized I just wanted to throw something together as a test to
see if this would be better then the typical flow for handling element height change
*/
var AnimateHeightComponent = React.createClass({
componentDidMount: function() {
this.$container = $(this.refs.container.getDOMNode());
this.baseHeight = this.$container.innerHeight();
this.$container.css("height", this.baseHeight);
},
componentDidUpdate: function(prevProps, prevState) {
if (prevProps.children.length < this.props.children.length) {
//if this is the first child only animate the difference
if (prevProps.children.length == 0) {
var childNumber = "item" + prevProps.children.length;
var childHeight = $(this.refs[childNumber].getDOMNode()).height();
var heightDiff = childHeight - this.$container.height();
this.$container.animate({
"height": "+=" + heightDiff
}, 150)
}
else {
var childNumber = "item" + prevProps.children.length;
var childHeight = $(this.refs[childNumber].getDOMNode()).outerHeight(true);
this.$container.animate({
"height": "+=" + childHeight
}, 150)
}
//save off the last childs height since we don't have access to it when the child
//is deleted and we want to be able to animate the height change
this.lastChildHeight = childHeight;
}
else {
//we are are removing from the container animate the change,
//but don't make it smaller then the base height.
console.log(this.$container.height() - this.lastChildHeight, this.baseHeight);
if (this.$container.height() - this.lastChildHeight < 0) {
this.$container.animate({
"height": this.baseHeight
}, 150)
}
else {
this.$container.animate({
"height": "-=" + this.lastChildHeight
}, 150)
}
}
},
render: function() {
return (
<div ref="container" className="dynamic-height-el">
{this.getChildren()}
</div>
);
},
getChildren: function() {
var children = this.props.children;
if (children && children.length) {
return React.Children.map(this.props.children, function(child, i) {
return React.addons.cloneWithProps(child, {
ref: "item"+i
});
});
}
return <i className="fa fa-arrows-v" />;
}
});
var Component = React.createClass({
getInitialState: function() {
return {
items: []
}
},
addItem: function() {
var itemPos = this.state.items.length;
var newItem = (
<div key={'item-' + itemPos} className={'item item-' +itemPos}>
<button className="remove-item-button" onClick={this.removeItem}>
<i className="fa fa-times"></i>
</button>
</div>
);
this.setState({
items: this.state.items.concat([newItem])
})
},
removeItem: function() {
this.state.items.pop();
this.setState({
items: this.state.items
})
},
render: function() {
return (
<div className="landing-page">
<div className="container">
<p className="title">Animate element height change <br/> When items are added</p>
<AnimateHeightComponent>
{this.state.items}
</AnimateHeightComponent>
<button className="add-child-button" onClick={this.addItem}>
Add an element to container
</button>
</div>
</div>
);
}
});
React.render(<Component/>, $('#reactEl')[0]);
@import "compass/css3";
body {
font-family: 'Open Sans', sans-sarif;
background-color: $color6;
padding: 10px 25px;
}
#reactEl {
height: 100%;
}
.container {
text-align: center;
}
.title {
width: 100%;
text-align: center;
font-weight: 800;
text-transform: uppercase;
font-size: 1.8em;
color: $color3;
}
.landing-page {
height: 100%;
width: 100%;
}
.dynamic-height-el {
box-sizing: border-box;
box-shadow: inset 0px 0px 15px 0px rgba(0,0,0,0.1);
margin: auto;
@include border-radius(5px 5px 0 0);
width: 500px;
padding: 10px;
background-color: mix(black, $color6, 13%);
text-align: center;
i {
color: mix(white, $color6, 45%);
font-size: 2em;
}
}
.add-child-button {
@include border-radius(0 0 5px 5px);
@include transition(all .2s ease-out);
margin: 5px 0;
background-color: $color3;
color: mix(black, $color1, 60%);
font-weight: 800;
text-align: center;
bottom: 50px;
padding: 15px;
width: 500px;
&:hover, &:focus, &:active {
background-color: rgba($color2, 1);
}
}
.item {
background-color: $color3;
text-align: right;
margin-bottom: 2px;
i {
color: mix(black, $color3, 25%);
}
button {
margin: 0;
height: 100%;
@include transition(all .3s ease-out);
&:hover {
background-color: rgba($color2, 1);
i {
color: mix(black, $color3, 30%);
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment