Animate an element that moves to occupy empty space with CSS only - html

http://jsfiddle.net/kscjq0y0/
I want to animate the movement of the yellow div when the red one disappears.
I know it can be done with jQuery animate but I want a CSS3 solution (even if it's not fully supported by all modern browsers).
I've tried the CSS transition property but doesn't seem to work for this kind of movement.
It's there a way to do this?

Make it shrink
div {
height: 100px;
width: 300px;
background-color: red;
margin: 20px;
padding: 10px;
}
#bottom {
background-color: yellow !important;
transition: all 0.5s ease;
}
#top {
transition: all 2s;
}
body:hover #top {
height: 0px;
padding: 0px;
margin-top: 0px;
margin-bottom: 0px;
}
<div id="top"></div>
<div id="bottom"></div>

You can do this, by modifying the CSS attribute that you want to animate. Currently the positioning is based on block layout with the other div, and this is not animating. But if you update the CSS position yourself, then that transition will animate. See the below example.
window.setTimeout(function () {
$("#top").fadeOut("slow");
$("#bottom").css({ top: '0px' });
}, 1000);
div {
height: 100px;
width: 300px;
background-color: red;
margin: 20px;
padding: 10px;
}
#bottom {
position: absolute;
top: 140px;
background-color: yellow !important;
transition: all 0.5s ease;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="top"></div>
<div id="bottom"></div>

Related

Can't quite get image to scale, and use overflow:hidden to work

Here is a link to a demo
I'm not sure what I'm missing, I've done this before a few times but It's been a day of fighting this particular CSS. I want the image to enlarge, but stay within the dimensions, so a zoom effect versus any enlargement. I've attempted to move the overflow:hidden into other parent or children, but it doesn't have an effect. I've played around with the display settings as well.
Any advice? The JSfiddle link is above, and the code below. Thanks for taking a look!
#purple-square {
width: 355px;
height: 255px;
background-image: url("../img/website_cards/purple_card.png");
border-radius: 10px;
}
#migraine-dentistry {
width: 355px;
height: 255px;
background-image: url("../img/website_cards/migraine_dentistry_card.png");
border-radius: 10px;
}
/* need position: relative in shell otherwisee the elements disappear */
#shell {
margin: auto;
width: 355px;
height: 255px;
position: relative;
transform-origin: center;
transition: 0.3s ease-in-out;
}
#shell:hover {
transform: scale(1.2);
}
#container {
width: 100%;
overflow: hidden;
display: inline-block;
transition: 0.3s;
margin: 0 auto;
}
#container div {
position: absolute;
left: 0;
transition: 0.3s ease-in-out;
}
#container:hover {
transition: ease-in-out 0.3s;
}
#container div.bottom:hover {
opacity: 0;
}
and here is the HTML setup:
<body>
<div id="shell">
<div id="container">
<div id='purple-square' class="top"></div>
<div id='migraine-dentistry' class="bottom"></div>
</div>
</div>
</body>
Full working code snipped below my steps
remove unnecessary elements Removed purple square, because it's never seen in wanted animation.
Removed the part the full #container div.bottom:hover part.
Removed every style that begins with #shell in the css and later trigger the animation on #container:hover.
main issue Add an #migraine-dentistry after the #container:hover animation, so if someone hovers the container it effects the #migraine-dentistry element. (#container:hover #mi.. {trans..})
In this (#container:hov..) element remove everything and
insert transform: scale(1.2);
because we just want to scale if user is hovering.
Remove whole #container div {..} style element, because we will directly add these styles to the #migraine-dentistry element.
In #container define px values for
> width: 355px; and height: 255px;
just because we not use the #shell element anymore. Also
> set position: relative; and z-index: 2;
that the #migrain.. element is inside his parent. And
> set border-radius: 15px;
for styling. Finally
>remove the display and transition values
because they are simply not needed.
last In #migraine-de.. styles
>set width: 100%; and height: 100%;
to fit div to parent.
> remove border-radius tag
because it's set by the #container
> add transition: 0.3s ease-in-out;
to transition like you wanted.
#container {
border-radius: 15px;
width: 355px;
height: 255px;
overflow: hidden;
z-index: 2;
position: relative;
}
#container:hover #migraine-dentistry {
transform: scale(1.2);
}
#migraine-dentistry {
width: 100%;
height: 100%;
transition: 0.3s ease-in-out;
background-image: url('https://images.unsplash.com/flagged/photo-1563248101-a975e9a18cc6?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=1950&q=80');
}
<body>
<div id="shell">
<div id="container">
<div id='migraine-dentistry' class="bottom"></div>
</div>
</div>
</body>
I know these long nights where you just can't get it done.

Element animation with respect to its center using just css

I have spend hours trying to find a solution that just requires css to work. I am trying to animate a div when it is hoverd, that its height and width be reduced uniformly.
<div class="a"></div>
Above is a simple div element with the following css:
.a {
width: 350px;
height: 350px;
background: #000;
margin: 100px 0 0 400px;
transition: all 2s linear;
position:fixed;
}
I want to reduce the height and width of the element on hover from the center using just css.
Use scale transformation:
.a {
width: 350px;
height: 350px;
background: #000;
margin: 10px;
transition: all 2s linear;
position: fixed;
}
.a:hover {
transform:scale(0.5);
}
<div class="a"></div>
The function you are looking for is scale()
As per your requirement, ideally what you would want to do is to fire the scale() function on hover of the target element as:
.a {
width: 350px;
height: 350px;
background: #000;
margin: 10px;
transition: all 2s linear;
position: fixed;
}
.a:hover {
transform:scale(0.7);
}
This css function will zoom the div element with respect to its center. See this for a complete reference.
Use the :hover pseudoclass.
.a:hover {
width: 300px;
height: 300px;
}
The transition on .a will apply as expected.

CSS: Reduce element size on hover, but keep original "hover area"

I want to reduce element size a bit as an effect, when it is hovered over with a mouse. However, this looks buggy because as the element reduces in size, the "hover area" gets smaller as well, which can result into the element not being hovered anymore, which further results into this "size flickering".
Is there a proper way to implement element size reduction on hover, while keeping the hover area size the same? Without extra elements?
Here is a fiddle: https://jsfiddle.net/ahvonenj/88f5by59/
Required code for fiddle linking:
#di
{
position: absolute;
left: 15px;
top: 15px;
background-color: #2980b9;
box-sizing: border-box;
width: 100px;
height: 100px;
}
#di:hover
{
width: 50px;
height: 50px;
transition: all 200ms linear;
}
Wrapping it in a div would be better, as commented. But if adding no other elements is a must, you could work with pseudo elements.
Make the visible part a pseudo element (like :before), and keep the main one just for hovering:
TIP: If you want the transition effect on both mouse over and out, set the property to the main css rule, not to the hover one
#di
{
position: absolute;
left: 15px;
top: 15px;
box-sizing: border-box;
width: 100px;
height: 100px;
}
#di:before {
content: "";
display: block;
background-color: #2980b9;
width: 100px;
height: 100px;
}
#di:hover:before
{
width: 50px;
height: 50px;
transition: all 200ms linear;
}
<div id = "di">
</div>
You can wrap the div inside a container and "bind" the hover event to the parent.
P.S obviously it is a solution with adding other elements.
#container
{
position: absolute;
left: 15px;
top: 15px;
box-sizing: border-box;
}
#container, #di{
width: 100px;
height: 100px;
}
#di{
background-color: #2980b9;
}
#container:hover #di
{
width: 50px;
height: 50px;
transition: all 200ms linear;
}
<div id="container">
<div id="di">
</div>
</div>
Yep, this is your answer. You have to add one more element. See this fiddle:
https://jsfiddle.net/vwy4utf5/
html:
<div id = "di">
<div id="diin">
</div>
</div>
CSS
#di{width:101px; height:101px; cursor:pointer; position: absolute;
left: 15px;
top: 15px;}
#diin
{
background-color: #2980b9;
box-sizing: border-box;
width: 100px;
height: 100px;
transition: all 200ms linear;
}
#di:hover > div
{
width: 50px;
height: 50px;
transition: all 200ms linear;
}
I tried it using Jquery, didn't specified by OP but I guess it can help somebody.
So changed css to make parent positioning of new parent:
#di {
background-color: #2980b9;
box-sizing: border-box;
width: 100px;
height: 100px;
}
#di_parent {
padding: 0;
overflow: hidden;
position: absolute;
left: 15px;
top: 15px;
}
#di_parent:hover > DIV {
width: 50px;
height: 50px;
transition: all 200ms linear;
}
Then added some JQuery to create a container to each object to maitain size as is suggested above.
$('#di').each(function(i, v){
var o, p;
o=$(v);
p=$('<div id="di_parent"></div>');
p.css({height:o.outerHeight(),width:o.outerWidth()});
o.after(p);
p.append(o.detach());
});
Working fiddle:
https://jsfiddle.net/88f5by59/11/
$('#di').each(function(i, v){
var o, p;
o=$(v);
p=$('<div id="di_parent"></div>');
p.css({height:o.outerHeight(),width:o.outerWidth()});
o.after(p);
p.append(o.detach());
});
#di {
background-color: #2980b9;
box-sizing: border-box;
width: 100px;
height: 100px;
}
#di_parent {
padding: 0;
overflow: hidden;
position: absolute;
left: 15px;
top: 15px;
}
#di_parent:hover > DIV {
width: 50px;
height: 50px;
transition: all 200ms linear;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div id = "di">
</div>
Hope it helps!

How to transform (move whole child dives) div to max width with css?

I have tried with these code. This is HTML code.
<div id="body">
<div id="back_1"></div>
<div id="back_2"></div>
</div>
Now I need to transform back_1 and back_2 divs max width of body div. I use like this. transform:translate(100%), but it is not working. It doesn't transform max width of body div. How can I transform (move whole child dives) that divs ?
I have created 2 DIVs for better understanding.
HTML
<div id="body">
<p>DEMO 1 (Flexible width)</p>
<div id="back_1"></div>
<div id="back_2"></div>
</div>
<div id="body1">
<p>DEMO 2 (fixed width of parent DIV)</p>
<div id="back_11"></div>
<div id="back_21"></div>
</div>
CSS
body{ color: #fff; }
#body {
width: auto;
background: red;
height: auto;
padding: 10px;
}
#back_1, #back_2 {
background: yellow;
width: inherit;
height: 50px;
border: 5px solid #fff;
}
#body1 {
width: 300px;
background: green;
height: auto;
padding: 10px;
margin-top: 10px;
}
#back_11{ margin-bottom: 10px; }
#back_11, #back_21 {
background: grey;
width: inherit;
height: 50px;
}
DEMO: SEE IN ACTION
DEMO1: Added On Hover for #body DIV's first DIV.
As per the clarification from you, it seems that you are trying to move the child divs within the parent upto the edge of the parent.
You started right with the transform: translate(100%).
One problem is that you have to specify which axis you want it to transalte. x-axis in your case and hence it should be translateX.
The other problem is that the 100% in translate is different from the usual percent units in CSS. The CSS percent units are dependent on the parent unit i.e. x% of parent's width/height etc. Whereas, the translate(100%) means 100% of the very element which is being translated.
So, in your case you have to carefully determine the parent width (the .body div) which should be in multiples of child's width. e.g. if parent is 100%, and child is 50%, then translate(100%) will translate the child by another 50% and hence reach the edge of the parent.
This will be more clear by this demo:
Demo: http://jsfiddle.net/abhitalks/Ze9cu/1/
Relevant CSS:
#body {
width: 100%;
height: 200px;
}
#back_2 {
width: 25%;
}
#back_2:hover {
-webkit-transform: translateX(300%);
}
Here, the child is 25% of its parent. So translateX(100%) will move it along the x-axis by only 25%. Making it translateX(300%) will make it move 3 times its own width.
You can use this to get you started as an example:
<style>
#body
{
background: gray;
width: 400px;
}
#back_1, #back_2
{
background: red;
position: relative;
width: 200px;
-moz-transition: .5s;
-webkit-transition: .5s;
-ms-transition: .5s;
-o-transition: .5s;
cursor: pointer;
}
#back_1:hover, #back_2:hover
{
width: 100%;
}
</style>
<div id="body">
<div id="back_1">Back1</div>
<div id="back_2">Back2</div>
</div>
EDIT::: Using jQuery and jQueryUI
<style>
#body
{
position: relative;
width: 200px;
background: gray;
height: 100px;
max-width: 400px;
}
#back_1
{
position: absolute;
width: 100px;
background: red;
height: 10px;
left: 0px;
}
</style>
<script src="jquery.js"></script> <!-- Your jQuery reference -->
<script src="jqueryUI.js"></script> <!-- Your jQuery UI reference -->
<script>
$(document).ready(function() {
$("#body").mouseover(function() {
var maxWidth = $("#body").css("max-width");
$("#back_1").animate({ left: maxWidth });
});
$("#body").mouseleave(function() {
$("#back_1").animate({ left: 0 });
});
});
</script>
<div id="body">
<div id="back_1"></div>
<div id="back_2"></div>
</div>
Your view study this address
http://www.w3schools.com/cssref/css3_pr_transform.asp
example
<style>
#body{
border:1px solid red;
height:500px;
}
#body div{
background-color: blue;
width: 500px;
height: 40px;
/*General*/
transform:translate(200px, 0px);
/*Firefox*/
-moz-transform:translate(200px, 0px);
/*Microsoft Internet Explorer*/
-ms-transform:translate(200px, 0px);
/*Chrome, Safari*/
-webkit-transform:translate(200px, 0px);
/*Opera*/
-o-transform:translate(200px, 0px);
border:1px soldi red;
transition:all 0.5s linear;
float:left;
margin:5px;
padding:10px;
}
#body:hover div{
/*General*/
transform:translate(100px, 50px);
/*Firefox*/
-moz-transform:translate(100px, 50px);
/*Microsoft Internet Explorer*/
-ms-transform:translate(100px, 50px);
/*Chrome, Safari*/
-webkit-transform:translate(100px, 50px);
/*Opera*/
-o-transform:translate(100px, 50px);
transition:all 0.5s linear;
margin:80px;
padding:80px;
}
</style>
<body>
<div id="body" >
<div id="back1"></div>
<div id="back2"></div>
</div>
</body>

How to use transform:translateX to move a child element horizontally 100% across the parent

All,
I'd like to be able to use translateX to animate a child element 100% of the way across it's parent (i.e., from the left edge to the right edge).
The challenge is that percentages in translateX refer to the element itself, not the parent.
So, for example, if my html looks like this:
<div id="parent">
<div id="child">
</div>
And my CSS like this (vendor-prefixes omitted):
#parent {
position: relative;
width: 300px;
height: 100px;
background-color: black;
}
#child {
position: absolute;
width: 20px;
height: 100px;
background-color:red;
transform: translateX(100%);
}
This doesn't work - the child only moves 20px (100% of itself), not all the way across the parent. (You can see this on jsfiddle):
I can do this:
#child {
position: absolute;
width: 20px;
height: 100px;
background-color:red;
-webkit-transform: translateX(300px) translateX(-100%);
transform: translateX(300px) translateX(-100%);
}
This works (seen here again on jsfiddle), because it first moves the child 300px (the full width of the parent), minus 20px (the width of the child). However, this depends on the parent having a fixed, known pixel dimension.
However, in my responsive design - I don't know the width of the parent, and it will change.
I know that I can use left:0 and right:0, but the animation performance of left/right is much worse than translateX (Thanks Paul Irish!).
Is there a way to do this?
Thanks in advance.
I didn't post my idea originally, because it involves creating an additional HTML layer, and expected better solutions to come.
Since that hasn't happened, I explain my comment. What I meant was this:
#parent {
position: relative;
width: 300px;
height: 100px;
background-color: black;
}
#wrapper {
position: absolute;
width: 100%;
height: 100px;
border: solid 1px green;
transition: all 1s;
}
#wrapper:hover {
-webkit-transform: translateX(100%);
transform: translateX(100%);
}
#child {
position: absolute;
width: 20px;
height: 100px;
background-color:red;
}
#wrapper:hover #child {
-webkit-transform: translateX(-100%);
transform: translateX(-100%);
}
Since the wrapper is 100% width of the parent, translating it 100% works as expected.
fiddle
Note that the wrapper is being translated 100% as you stated. However, seems that what you really want is to move the element 100% - width. To achieve this, you have to translate the child also 100% (now this applies to the child width) in the opposite direction.
Correction: the child should share the transition property of the wrapper:
#parent {
position: relative;
width: 300px;
height: 100px;
background-color: black;
}
#wrapper {
position: absolute;
width: 100%;
height: 100px;
border: solid 1px green;
transition: all 5s;
}
#wrapper:hover {
transform: translateX(100%);
}
#child {
position: absolute;
width: 50px;
height: 100px;
background-color:red;
transition: inherit;
}
#wrapper:hover #child {
transform: translateX(-100%);
}
<div id="parent">
<div id="wrapper">
<div id="child"></div>
</div>
</div>
There's a pretty cool solution to this problem using Flexbox. The key is to take advantage of the flex-grow property.
Say you have some HTML that looks like this:
<div class="flex-container">
<div class="flex-spacer"></div>
<div class="slider"></div>
</div>
First, give .flex-container the basic display: flex property, and set its flex-direction to row. Set the positioning of the child elements to relative, so they will sit next to each other inside .flex-container.
By default, the flex-grow property is set to 0, which is exactly what we want at the beginning. This means that .flex-spacer and .slider will only have their normal dimensions to begin with. We simply keep .flex-spacer empty, and it will have a width of 0.
Now for the animation. We only need two CSS rules to make it work: add a transition to .flex-spacer and set flex-grow to 1 on .flex-spacer during some event. The second rule gives all of the unused width inside .flex-container to the width of .flex-spacer, and the first rule animates the change in width. The .slider element gets pushed along to the edge of .flex-container.
The CSS looks something like this - I added a background to .flex-spacer to make its presence a little more obvious, and set flex-grow to 1 when the user hovers over .flex-container:
body * {
box-sizing: border-box;
}
.flex-container {
cursor: pointer;
display: flex;
flex-flow: row nowrap;
width: 100%;
border: 2px solid #444;
border-radius: 3px;
}
.flex-spacer,
.slider {
flex-grow: 0;
position: relative;
}
.slider {
padding: 25px;
background-color: #0DD;
}
.flex-spacer {
background-color: #DDD;
transition: all .4s ease-out;
}
.flex-container:hover .flex-spacer {
flex-grow: 1;
}
<div class="flex-container">
<div class="flex-spacer"></div>
<div class="slider"></div>
</div>
Flexbox makes this pretty configurable, too. For example, say we want .slider to move from right to left, instead. All we have to do is switch the flex-direction property in .flex-container to row-reverse, and we're done!
Feel free to play with it in this pen.
Keep in mind that things can get a little trickier if we want animations for different types of events. For example, I came across this issue when trying to animate a label when a user types in an input element. A little more HTML and CSS is needed to make it work (I used some JS, as well), but the concept is the same.
Here's another pen, this time in the context of a form with input.
With the recent addition of Size Container Queries it is now possible to do this by setting the container-type property to inline-size in the parent and then translating the child element by 100cqw - 100% where 100cqw is the full width of the parent and 100% is the width of the child.
#parent {
position: relative;
width: 300px;
height: 100px;
background-color: black;
container-type: inline-size;
}
#child {
position: absolute;
width: 20px;
height: 100px;
background-color:red;
transform: translateX(calc(100cqw - 100%));
}
<div id="parent">
<div id="child">
</div>
I implemented this using wrapper and flex-grow:1.
Here are two animations at the same time with the same duration: 1) the container (green) moves with the car at 100% of the parent's width; 2) the car moves back -100% of its width (to stay on the track at the finish line). The duration can be taken separately and distributed to the container (.track-inner) and the car (.car)
const goBtn = document.querySelector('.go');
const inner = document.querySelector('.track-inner');
const car = document.querySelector('.car');
const durationFromServerMS = '3000ms';
goBtn.addEventListener('click', ()=>{
inner.classList.add('drive');
inner.style.animationDuration = durationFromServerMS;
car.classList.add('backShift');
car.style.animationDuration = durationFromServerMS;
})
const backBtn = document.querySelector('.back');
backBtn.addEventListener('click', ()=>{
inner.classList.remove('drive');
car.classList.remove('backShift');
})
html, body {
padding: 2rem;
}
.track{
width: 50%;
display:flex;
position: relative;
background-color: gray;
width: auto;
margin-bottom: 1rem;
border: 5px dashed blue;
overflow:hidden;
}
.track-inner{
width: 100%;
border: 5px dotted green;
}
.car{
width: 3rem;
height: 1.5rem;
border: 1px solid black;
background-color: salmon;
}
.finish-line{
position:absolute;
top:0;
right: 0.5rem;
width: 3rem;
height: 1.5rem;
border-left: 6px dotted yellow;
}
button{
padding: 0.5rem 1rem;
background-color: lightblue;
outline: none;
border:none;
margin: 0.2rem
}
button:hover{
pointer:cursor;
background-color: salmon;
}
.backShift {
animation-name: car-back;
/* animation-duration: 5s; */
animation-timing-function: ease-in;
animation-fill-mode: forwards;
}
.drive {
animation-name: driving;
/* animation-duration: 5s; */
animation-timing-function: ease-in;
animation-fill-mode: forwards;
}
#keyframes driving {
0% {
transform: translateX(0%);
}
100% {
transform: translateX(100%);
}
}
#keyframes car-back {
0% {
transform: translateX(0%);
}
100% {
transform: translateX(-100%);
}
}
p{
padding:0;
}
<div class="track">
<div class="track-inner">
<div class="car ">car</div>
</div>
<div class="finish-line">finish</div>
</div>
<div>
<button class='go'>Go</button>
<button class='back'>Back</button>
</div>