animate width of a box towards left
You can do it by animating the box's margin-left and width at the same time. Alternatively, if your box is absolutely positioned, animate it's left property and width at the same time.
HTML
<div id="loading"></div>
CSS
#loading {
margin-left: 200px;
width: 0;
height: 10px;
background: red;
}
jQuery
$('#loading').animate({width: 200, marginLeft: 0}, {duration: 1000});
You can see it in action here.
Keep div width after expanding it with hover (CSS)
Set an extremely high transition time for the shrinking animation part, which will give the effect of not shrinking. No js required, just setting it to something like 3600s (maybe try even higher?) which will be an hour will give you a visually static for a long time. I couldn't find the maximum time but it seems to work.
div.container{
width: 400px;
height: 250px;
border: 1px solid;
clear: both;
}
.square{
width: 100px;
height: 100px;
background: black;
float: left;
position: relative;
transition:width 5s;
-webkit-transition:width 5s;
}
.grow {
width: 0px;
height: 100px;
float: left;
background: black;
position: relative;
transition:width 3600s;
-webkit-transition:width 3600s;
background: green;
}
.square:hover + .grow{
width: 200px;
transition:width 0.5s;
-webkit-transition:width 0.5s;
}
<div class="container">
<div class="square"></div>
<div class="grow"></div>
</div>
Expand div from the middle instead of just top and left using CSS
The key is to transition the margin by a formula. There is a little "wiggle" that is annoying during the transition if it is floated.
EDITED ADDING OPTIONS
Option 1: Expands within space reserved around it http://jsfiddle.net/xcWge/14/:
#square {
width: 10px;
height: 10px;
margin: 100px; /*for centering purposes*/
-webkit-transition: width 1s, height 1s, margin 1s;
-moz-transition: width 1s, height 1s, margin 1s;
-ms-transition: width 1s, height 1s, margin 1s;
transition: width 1s, height 1s, margin 1s;
}
#square:hover {
width: 100px;
height: 100px;
margin: 55px; /* initial margin - (width change (and/or height change)/2), so here 100px is initial margin, and the change is (100px final W/H - 10px initial W/H = 90px change, so 100px - (90px / 2 [= 45px]) = 55px) */
}
Option 2: Expands over elements around it http://jsfiddle.net/xcWge/18/:
#square {
width: 10px;
height: 10px;
margin: 0; /*for centering purposes*/
-webkit-transition: width 1s, height 1s, margin 1s;
-moz-transition: width 1s, height 1s, margin 1s;
-ms-transition: width 1s, height 1s, margin 1s;
transition: width 1s, height 1s, margin 1s;
}
#square:hover {
width: 110px;
height: 110px;
margin: -50px; /* 0 - (110px - 10px [= 100px]) / 2 = -50px */
}
Option 3: Expands over elements before it in flow and shifts elements after it http://jsfiddle.net/xcWge/22/:
#square {
width: 10px;
height: 10px;
margin: 0;
position: relative;
top: 0;
left: 0;
-webkit-transition: width 1s, height 1s, top 1s, left 1s, margin 1s;
-moz-transition: width 1s, height 1s, top 1s, left 1s, margin 1s;
-ms-transition: width 1s, height 1s, top 1s, left 1s, margin 1s ;
transition: width 1s, height 1s, top 1s, left 1s, margin 1s;
}
#square:hover {
width: 110px;
height: 110px;
top: -50px; /* initial top[0] - (new height[110px] - initial height[10px] [=100px])/2 [=50px] = -50px) */
left: -50px; /* initial left[0] - (new width[110px] - initial width[10px] [=100px])/2 [=50px] = -50px) */
margin-right: -50px;
margin-bottom: -50px;
}
ADDED NON-SQUARE EXAMPLE
A comment was made this does not work for a non-square (same width/height), but that just means one has to adjust differently for each direction during the transition. So here is Option 2 (with non-square) that starts as a rectangle, and the width expands twice as much as the height (so changes rectangle shape even) during the transition: Expands over elements around it http://jsfiddle.net/xcWge/2131/
#rectangle {
width: 110px;
height: 10px;
margin: 0; /*for centering purposes*/
-webkit-transition: width 1s, height 1s, margin 1s;
-moz-transition: width 1s, height 1s, margin 1s;
-ms-transition: width 1s, height 1s, margin 1s;
transition: width 1s, height 1s, margin 1s;
}
#rectangle:hover {
width: 310px;
height: 110px;
margin: -50px -100px; /* initial margin - ((initial margin - width change (or height change))/2) */
}
If the width
were only changing by 100px also (so from 110px to 210px), then just a margin: -50px
would have still worked.
how to make a CSS animation end point the right edge of the browser
solution is to use both left
and margin-left
JSFIDDLE DEMO
.square
{
width: 30px;
height: 3px;
background: red;
position: relative;
animation: colors 2s;
-webkit-animation: colors 2s;
animation-iteration-count: infinite;
-webkit-animation-iteration-count: infinite;
top: 0px;
margin-left:-30px;
}
@keyframes colors {
0% {left: 30px;}
99% { left: 100%;}
}
@-webkit-keyframes colors {
0% {left: 30px;}
99% { left: 100%;}
}
How to animate svg rect to grow
Instead of animating two attributes simultaneously, I think you'll find it much easier to use a transform
attribute to get the coordinate system you wanted in the first place.
In this example, the animated <rect>
elements are wrapped in the following <g>
element:
<g transform="scale(1,-1) translate(0,-200)">
...
</g>
The scale
transform turns all the y coordinates upside down, and the translate
transform shifts the coordinates so that y=0
is at the bottom of the SVG canvas.
<svg version="1.1" xmlns="http://www.w3.org/2000/svg"
width="400" height="200" viewBox="0 0 400 200">
<g transform="scale(1,-1) translate(0,-200)">
<rect x="50" y="0" fill="#f00" width="100" height="100">
<animate attributeName="height" from="0" to="100" dur="0.5s" fill="freeze" />
</rect>
<rect x="150" y="0" fill="#f70" width="100" height="200">
<animate attributeName="height" from="0" to="200" dur="0.5s" fill="freeze" />
</rect>
<rect x="250" y="0" fill="#ec0" width="100" height="150">
<animate attributeName="height" from="0" to="150" dur="0.5s" fill="freeze" />
</rect>
</g>
</svg>
Circle to rectangle transformation animation
If you want both the scaling up and corner radius reduction to happen at the same time, you can simplify the code from my other answer significantly.
You now no longer need to 'chain' the animations together, so you can add them both to a single CAAnimationGroup
and run them concurrently.
The properties we use will remain almost identical, except with the addition of a groupAnim
property and deletion of the cornerRadiusUndoAnim
.
class ViewController2: UIViewController {
let animLayer = CALayer() // the layer that is going to be animated
let cornerRadiusAnim = CABasicAnimation(keyPath: "cornerRadius") // the corner radius reducing animation
let widthAnim = CABasicAnimation(keyPath: "bounds.size.width") // the width animation
let groupAnim = CAAnimationGroup() // the combination of the corner and width animation
let animDuration = NSTimeInterval(1.0) // the duration of one 'segment' of the animation
let layerSize = CGFloat(100) // the width & height of the layer (when it's a square)
...
We can now just add the setup for the CAAnimationGroup
, adding both our corner radius animation and our scaling animation
override func viewDidLoad() {
super.viewDidLoad()
let rect = view.frame
animLayer.backgroundColor = UIColor.blueColor().CGColor // color of the layer, feel free to change
animLayer.frame = CGRect(x: rect.width-layerSize*0.5, y: rect.height-layerSize*0.5, width: layerSize, height: layerSize)
animLayer.cornerRadius = layerSize*0.5;
animLayer.anchorPoint = CGPoint(x: 1, y: 1) // sets so that when the width is changed, it goes to the left
view.layer.addSublayer(animLayer)
// decreases the corner radius
cornerRadiusAnim.duration = animDuration
cornerRadiusAnim.fromValue = animLayer.cornerRadius
cornerRadiusAnim.toValue = 0;
cornerRadiusAnim.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut) // timing function to make it look nice
// increases the width
widthAnim.duration = animDuration
widthAnim.fromValue = animLayer.frame.size.width
widthAnim.toValue = rect.size.width
widthAnim.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut) // timing function to make it look nice
// adds both animations to a group animation
groupAnim.animations = [cornerRadiusAnim, widthAnim]
groupAnim.duration = animDuration;
groupAnim.autoreverses = true; // auto-reverses the animation once completed
}
Finally, we can run the group animation when the view gets touched, and both animations will run concurrently together (and auto-reverse when done).
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
animLayer.addAnimation(groupAnim, forKey: "anims") // runs both animations concurrently
}
Result
Full project: https://github.com/hamishknight/Circle-to-Rect-Animation
Related Topics
Swift, Sprite Kit Game: Have Circle Disappear in Clockwise Manner? on Timer
Xcode 6, Swift - Read Standard Input (Console) to String
Launch Sudo Command from MACos App Swift
Swift: Using "/" Slash in Filename with Createdirectoryatpath
Issue with Adding Node to Scene View
No Code Signature Found After Pod Installed in Xcode 8
Difference Between Type Method and Type Instance Method, etc
Fill Circle with Wave Animation in Swiftui
Timestamped Event Matching Error: Failed to Find Matching Element
System Volume Change Observer Not Working on iOS 15
Nsdata Contentsofurl Constructor Returns Nil
Call External Function Using Watchkit Force Touch Menuitem
Nsjsonserialization Not Working as Expected in a Playground