I'm not sure if this is possible, but I thought it would be cool using CSS transforms to create an effect where a div expands from its center to a predetermined height and width, rather than just from the upper left corner.
For instance, if I have (demo)
<div id="square"></div>
and (vendor prefixes left out for brevity)
#square { width: 10px; height: 10px; background: blue; transition: width 1s, height 1s; } #square:hover { width: 100px; height: 100px; }
On hover, this will expand the square to the right and down to 100px. I would like to have it expand from the middle.
I'm aware that I could probably use transform: scale(x)
(demo), but this doesn't really provide me with a very "pixel perfect" layout (as it is percentage-based), and it also does not affect the surrounding layout (make other elements that are in the document flow adjust to its resizing). This is essentially what I want to do, except with the document flow affected accordingly.
Does anyone know of a way to do this without javascript?
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.
You'll have to transition it's position in order to do this as well, setting it to relative/absolute and changing the top
value as it animates.
(edit based on comment)
Instead of absolute positioning, you could try to do the same sort of thing with a negative top margin. That would keep it in the document flow. Somehow, though, you need to actually move the div as well as animating the height/width.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With