CSS wait till parent transition is finished then instantly transition child - html

I have a situation like the following
.parent {
width: 200px;
height: 100px;
padding: 25px;
background-color: grey;
transition: width 0.25s;
}
.parent:hover {
width: 300px;
}
.child {
width: 100%;
height: 100%;
background-color: blue;
}
<h3>Hover Over</h3>
<div class="parent">
<div class="child"></div>
</div>
I need have the child stay at the same width until the parent is completed its transition.
I know that this is possible with absolute styles. See the snippet below:
.parent {
width: 200px;
height: 100px;
padding: 25px;
background-color: grey;
transition: width 0.25s;
}
.parent:hover {
width: 300px;
}
.child {
width: 200px;
height: 100%;
background-color: blue;
}
.parent:hover .child {
width: 300px;
transition-delay: 0.25s;
}
<h3>Hover Over</h3>
<div class="parent">
<div class="child"></div>
</div>
The current element that I need this for is has relative styles (100%) so the snippet above wouldn't work in my case. Is there a way to change the snippet above to work with relative styles or is there another way to do this?

It is actually possible with only CSS, although this is a bit of a dirty method.
If you change the font-size to some number [px|em|etc.] instead of the width property, this will enable the size of both to change "independently".
The drawback of this method is that you will need to add another child element (or ::before | ::after) with a more reasonable font-size if you want to display some text inside these elements, so it might be better for your purpose to use some JS like #jmc but if you can't (or don't want to :p) this might be the solution for you.
.parent {
font-size: 200px;
width: 1em;
height: 100px;
padding: 25px;
background-color: grey;
transition: width 0.25s;
}
.parent:hover {
font-size: 300px;
}
.child {
width: 1em;
height: 100%;
background-color: blue;
transition: width 0.25s;
}
.child:hover, .parent:hover > .child {
transition: width 0.25s 0.25s linear;
}
<h3>Hover Over</h3>
<div class="parent">
<div class="child"></div>
</div>

Just add same transition to child class. Take A look below:
.parent {
width: 200px;
height: 100px;
padding: 25px;
background-color: grey;
transition: width 0.25s;
}
.parent:hover {
width: 300px;
}
.child {
width: 200px;
height: 100%;
background-color: blue;
transition: width 0.25s;
}
.parent:hover .child {
width: 300px;
transition-delay: 0.25s;
}
<h3>Hover Over</h3>
<div class="parent">
<div class="child"></div>
</div>
If you have to say that .child will have the width of 100%, so it will really have follow the width of its parent no matter what width it is. To make it have a delay transition, the .child should have a starting width then. But if you have to insist on having the child a 100% width, is it possible if you can use JS/JQuery? If that so, check the snippet I have below:
$(document).ready(function() {
var width = $('.child').width();
$('.child').css({
'width': width
});
$('.parent').hover(function() {
setTimeout(function() {
$('.child').css({
'width': 'calc(100%)'
})
}, 500)
}, function() {
$('.child').css({
'width': width
});
});
});
.parent {
width: 200px;
height: 100px;
padding: 25px;
background-color: grey;
transition: width 0.25s;
}
.parent:hover {
width: 300px;
}
.child {
width: 100%;
height: 100%;
background-color: blue;
transition: .2s width 0.25s;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<h3>Hover Over</h3>
<div class="parent">
<div class="child"></div>
</div>

Related

Transition left div width over right div and vise versa

Please refer to this jsfiddle: https://jsfiddle.net/b53te5qb/1/
I am attempting to make each of these div widths transition nicely over the other.
Right now it is an instant effect, but I would like for it to transition smoothly. When I attempt the transition it starts to get buggy.
Here is the HTML:
<div class="outer">
<div class="color left"></div>
<div class="color right"></div>
</div>
And here is the CSS so far:
.outer {
position: relative;
height: 100px;
width: 200px;
}
.color {
height: 50px;
width: 50%;
float: left;
transition: width 0.3s linear;
-webkit-transition: width 0.3s linear;
}
.color:hover {
width: 100%;
position: absolute;
}
.left {
background-color: #ff0;
}
.right {
background-color: #0ff;
}
I am open to restructuring this however I would need to in order to complete the task. I just provided this as a base example.
If you're just doing this with solid colors, I would transition transform: scaleX(). Using transition with transform will give you better performance.
.outer {
position: relative;
height: 100px;
width: 200px;
}
.color {
height: 50px;
width: 50%;
float: left;
transition: transform 0.3s linear;
-webkit-transition: transform 0.3s linear;
transform-origin: 0 0;
}
.color:hover {
transform: scaleX(2);
}
.left {
background-color: #ff0;
}
.right {
background-color: #0ff;
transform-origin: 100% 0;
}
<div class="outer">
<div class="color left"></div>
<div class="color right"></div>
</div>
Here you go: https://jsfiddle.net/prowseed/b53te5qb/10/
Two techniques, one with flexbox and one with position absolute, pick any :)
.outer {
position: relative;
height: 100px;
width: 666px;
display:flex;
}
.color {
flex: 1;
height: 100%;
transition: .3s;
}
.color:hover {
flex-basis:100%;
}
.outer2 {
margin-top:100px;
position: relative;
height: 100px;
width: 666px;
}
.outer2:hover .color {
width:0;
}
.outer2 .color {
position:absolute;
top:0;
left:0;
bottom:0;
width:50%;
}
.outer2 .color + .color {
left:auto;
right:0;
}
.outer2 .color:hover {
width:100%;
z-index:2;
}
You'll need to position them absolutely in order to avoid them from moving.
https://jsfiddle.net/b53te5qb/6/
I would highly recommend not transitioning the width, much better would be to transition transform: translateX(), since it will be hardware accelerated and much smoother: https://jsfiddle.net/b53te5qb/8/.
It still needs polishing, but the idea is there. (note the overflow: hidden to avoid showing the excess.) Another improvement would be to have two elements on top (50%/50% width) that trigger the hover via javascript, since when the elements move it's difficult to keep the hover on them, or to remove the hover without leaving the .outer component.
Hope it helps.

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!

A moving element to push adjacent element only if they collide

I have a container with 2 children.
One child has dynamic width and at it's maximum width can fill the container
The other child has fixed width and starts off being hidden as it's starting point is to the right of the overflow:hidden container
What I want is the fixed-width child to move to the left so that it exactly fits into the right of the container such that
a) If both children fit into the container - the other element should say put on the left and
b) If there is no room for both elements - the fixed-width element should push the other element to the left as much as it needs to in order to fit into the right of the container.
Here is what I tried:
Attempt #1
.container {
width: 200px;
height: 50px;
border: 1px solid green;
overflow: hidden;
white-space: noWrap;
}
span {
height: 50px;
display: inline-block;
}
.child1 {
background: aqua;
float: right;
width: 50px;
margin-right: -50px;
transition: margin .2s;
}
.container:hover .child1 {
margin-right: 0;
}
.child2 {
background: tomato;
//width: 100%;
}
<div class="container">
<span class="child1">Fixed</span>
<span class="child2">Dynamic Width</span>
</div>
<div class="container">
<span class="child1">Fixed</span>
<span class="child2">Here is a Dynamic Width box</span>
</div>
Condition a) Succeeds but condition b) Fails
Attempt #2
.container {
width: 200px;
height: 50px;
border: 1px solid green;
overflow: hidden;
white-space: noWrap;
}
span {
height: 50px;
display: inline-block;
}
.child2 {
background: aqua;
width: 50px;
margin: 0;
float: right;
margin-right: -50px;
transition: margin .2s;
}
.container:hover .child1 {
margin-left: -50px;
}
.container:hover .child2 {
margin: 0;
}
.child1 {
background: tomato;
transition: margin .2s;
}
<div class="container">
<span class="child1">Dynamic Width</span>
<span class="child2">Fixed</span>
</div>
<div class="container">
<span class="child1">Here is a Dynamic Width box</span>
<span class="child2">Fixed</span>
</div>
Condition a) Fails and condition b) Succeeds
Can both conditions be fulfilled with CSS alone?
PS: The markup which I provided in the demos may be modified. Also CSS3 including flexbox is also fine.
Here is a CSS only solution.
The trick is to use this basic rule:
Consider two or more inline elements rendered side by side.
If you increase the width of the first element, the second elements is pushed to the right.
The problem is that you need the elements to move to the left. I solved this by inverting the X direction to the child elements scaleX(-1) and re-inverting again the container.
To help you better understand this, you can comment out the transform: scaleX(-1); in the jsfiddle link below, and watch what happens.
The beauty of this is that you don't need to know the width of the .child2. You just need to push it to the left.
.container {
width: 200px;
height: 50px;
border: 1px solid green;
overflow: hidden;
white-space: nowrap;
text-align: right;
transform: scaleX(-1);
}
span {
height: 50px;
display: inline-block;
transform: scaleX(-1);
}
.child1 {
background: aqua;
width: 50px;
margin-left: -50px;
float: left;
transition: margin-left .2s;
text-align: left;
}
.child2 {
background: tomato;
}
.container:hover .child1 {
margin-left: 0;
}
<div class="container">
<span class="child1">Fixed</span>
<span class="child2">Dynamic Width</span>
</div>
<div class="container">
<span class="child1">Fixed</span>
<span class="child2">Here is a Dynamic Width box</span>
</div>
Also on jsfiddle
Solution 2
Another slightly simpler solution is to use direction: rtl; on the container. By reversing the direction of inline elements from right to left, we achieve the same effect without the need to use CSS3 transformations.
See http://jsfiddle.net/epfqjtft/12/
Since css can't do conditional statements (bar media queries), I don't think this is truly possible with css alone.
update
I have seen that it is in fact possible using CSS3 transforms (which works in modern browsers). but just in case some users might want older browser support which CSS3 transforms cant provide, i'll leave this here anyway.
Apart from that, I've used positioning instead of floats to 'clean up' the styling (and attempted the jquery):
$('.container').hover(function() {
var parentWidth = $(this).width();
var thisWidth = $(this).find(".child1").width() + 50; /*i.e. width of fixed box*/
if (parentWidth < thisWidth) { /*if it doesn't fit, move it!*/
$(this).find('.child1').addClass("moveLeft");
}
}, function() {
$(this).find(".child1").removeClass("moveLeft");
});
.container {
width: 200px;
height: 50px;
border: 1px solid green;
overflow: hidden;
white-space: noWrap;
position: relative;
}
span {
height: 50px;
display: inline-block;
}
.child2 {
background: aqua;
width: 50px;
margin: 0;
position: absolute;
top: 0;
right: -50px;
transition: all .2s;
}
.child1 {
background: tomato;
transition: all .2s;
position: absolute;
top: 0;
left: 0;
}
.container:hover .child2 {
right: 0;
}
.moveLeft:hover {
left: -50px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
<span class="child1">Dynamic Width</span>
<span class="child2">Fixed</span>
</div>
<div class="container">
<span class="child1">Here is a Dynamic Width box</span>
<span class="child2">Fixed</span>
</div>
As for your 'solution', you will have to test if the child + 50px is greater than the parent width, if so, move child1. If not, no action is needed.
Okay, I changed LinkinTED's code a little bit. Try this:
http://jsfiddle.net/epfqjtft/9/
Of course, I don't know if it's something you can work with. These types of problems should be solved with Jquery.
.container {
width: 200px;
height: 50px;
border: 1px solid green;
display: table;
table-layout: fixed;
transition: all 2s;
}
span {
height: 50px;
display: table-cell;
transition: all .2s;
}
.child1 {
background: tomato;
width: 100%;
}
.child2 {
background: aqua;
width: 0px;
overflow: hidden;
transition: all .2s;
}
.container:hover .child2 {
width: 50px;
}
<div class="container">
<div class="wrapper">
<span class="child1">Dynamic Width</span>
</div>
<span class="child2">Fixed</span>
</div>
<div class="container">
<div class="wrapper">
<span class="child1">Here is a Dynamic Width box</span>
</div>
<span class="child2">Fixed</span>
</div>
.container {
width: 250px;
height: 40px;
border: 1px solid read;
overflow: hidden;
white-space: nowrap;
text-align: right;
transform: scaleX(-1);
}
span {
height: 50px;
display: inline-block;
transform: scaleX(-1);
}
.child1 {
background: pink;
width: 50px;
margin-left: -50px;
float: left;
transition: margin-left .3s;
text-align: left;
}
.child2 {
background: #####;
}
.container:hover .child1 {
margin-left: 0;
}
<div class="container">
<span class="child1">Fixed</span>
<span class="child2">Dynamic Width</span>
</div>
<div class="container">
<span class="child1">Fixed</span>
<span class="child2">Here is Dynamic Width box</span>
</div>

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

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>

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>