A moving element to push adjacent element only if they collide - html

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>

Related

CSS wait till parent transition is finished then instantly transition child

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>

How can I allow a CSS table column with width 100% to overflow table?

I have a CSS table that actually has two columns but one of the columns is hidden by setting it's width to 0 and the second column has width 100% so it takes up the entire table. When the first column is shown (controlled by a checkbox and CSS), the second column resizes but I want it to stay the same size to look like it's content is being pushed to the side. I've been able to get that to work if I give the column an explicit width in pixels but is it possible to get it to work using a percentage width using just CSS?
#container {
width: 400px;
border: 2px solid red;
}
.table {
margin-top: 16px;
display: table;
table-layout: fixed;
width: 100%;
white-space: nowrap;
overflow: hidden;
}
.col {
display: table-cell;
overflow: hidden;
}
.col1 {
width: 0;
transition: width .5s ease;
}
.col2 {
width: 100%;
width: px;
position: relative;
}
.col3 {
width: 400px;
position: relative;
}
.marker {
position: absolute;
right: 2px;
top: 0;
}
input[type="checkbox"]:checked ~ div > div > .col1 {
width: 100px;
}
<label for="show-col">Show extra col</label>
<input type="checkbox" id="show-col">
<div id="container">
<div class="table">
<span class="col1 col">Column 1</span>
<span class="col2 col">
Column 2 - with width as 100%
<span class="marker">Edge</span>
</span>
</div>
<div class="table">
<span class="col1 col">Column 1</span>
<span class="col3 col">
Column 2 - with explicit width in pixels
<span class="marker">Edge</span>
</span>
</div>
</div>
So you could set a min-width on the element, but again this isn't using percentages. The only other way i think you can do this is with a bit of jQuery to get the parent elements width, which you could do inside a resize function.
UPDATE - the first table now uses position absolute on .col2 which is set to 100%, then CSS transition on left
fiddle - https://fiddle.jshell.net/Jim_Miraidev/pa734h2y/
$(document).ready(function(){
var resizeTimer;
var $col3 = $('.col3');
$(window).on('resize load', function(e) {
clearTimeout(resizeTimer);
resizeTimer = setTimeout(function() {
// get parent width and set
var $pw = $col3.parent().width();
$col3.css({'width':$pw});
}, 100);
});
});
#container {
width: 100%;
border: 2px solid red;
position: relative;
overflow:hidden;
}
.table {
margin-top: 16px;
display: table;
table-layout: fixed;
width: 100%;
white-space: nowrap;
overflow: hidden;
box-sizing: border-box;
}
.col {
display: table-cell;
overflow: hidden;
}
.col1 {
width: 0;
transition: width .5s ease;
}
.col2 {
position: absolute;
width: 100%;
left:0;
transition: left .5s ease;
}
.col3 {
position: absolute;
width: 100%;
}
.marker {
float: right;
}
input[type="checkbox"]:checked ~ div > div > .col1 {
width: 100px;
}
input[type="checkbox"]:checked ~ div > div > .col2 {
left: 100px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<label for="show-col">Show extra col</label>
<input type="checkbox" id="show-col">
<p>Using css transition left width set to 100%</p>
<div id="container">
<div class="table">
<span class="col1 col">Column 1</span>
<span class="col2 col">
Column 2 - using postion absolute and
animating the left
<span class="marker">Edge</span>
</span>
</div>
</div>
<p>Using the jQuery</p>
<div id="container">
<div class="table">
<span class="col1 col">Column 1</span>
<span class="col3 col">
Column 2 - with explicit width in pixels
<span class="marker">Edge</span>
</span>
</div>
</div>

Make div in flexbox grow on hover

I'm trying to implement a view that displays three columns. When the user hovers over one of them it should grow at expense of the others.
I have a few requirements:
I want each column to have a background image and it should not move when the column is resized.
There should be a smooth transition when columns grows/shrinks
It should work in at least Safari, Firefox and Chrome
I would also like to have each column separated by diagonal line if possible. This is what the end result should look like:
I have basic functionality working, but I've run into several problems:
I've not managed to get the background image to be fixed on the parent div
Transitions does not work in Safari
In the real context, which is a website based on Bootstrap, the background image moves by a pixel or two seemingly by random on Safari and Chrome.
I've tried to achieve the diagonal lines using clip-path, but it does not work in Safari and very poorly in Chrome
When changing column from the second to the third the first column is resized a bit
In Chrome the rightmost pixel column flickers while growing/shrinking
Any hints appreciated!
Here's my current code:
.content {
display: flex;
border: 1px solid #f00;
background: #fbb;
padding: 10px;
height: 800px;
color: #fff;
}
.col {
flex-grow: 1;
flex-basis: 0;
transition: flex-grow .3s;
-webkit-transition: flex-grow .3s;
border: 1px solid #0f0;
padding: 10px;
}
.col:hover {
flex-grow: 5;
transition: flex-grow .3s;
-webkit-transition: flex-grow .3s;
}
.col1 {
background: url(https://images.pexels.com/photos/130184/pexels-photo-130184.jpeg?w=1260&h=750&auto=compress&cs=tinysrgb);
background-attachment: fixed;
}
.col2 {
background: url(https://images.pexels.com/photos/354939/pexels-photo-354939.jpeg?w=1260&h=750&auto=compress&cs=tinysrgb);
background-attachment: fixed;
}
.col3 {
background: url(https://images.pexels.com/photos/259915/pexels-photo-259915.jpeg?w=1260&h=750&auto=compress&cs=tinysrgb);
background-attachment: fixed;
}
<div class="content">
<div class="col col1">
<h1>Foo!</h1>
</div>
<div class="col col2">
<h1>Bar!</h1>
</div>
<div class="col col3">
<h1>Brovinkel!</h1>
</div>
</div>
With transform: skew() one can tilt the items.
As that will create an unfilled upper left and lower right area, widen the left/right will cover that.
Finally we then revert that skew for text/image, where I used a pseudo for the image.
Stack snippet
.content {
display: flex;
height: 400px;
color: #fff;
overflow: hidden;
border: 5px solid #f00;
background: lime;
}
.col {
position: relative;
overflow: hidden;
flex-grow: 1;
flex-basis: 0;
transition: flex-grow .3s;
transform: skew(-20deg, 0);
background: yellow;
}
.col + .col {
border-left: 10px solid #0ff;
}
.col:first-child {
margin-left: -100px;
}
.col:last-child {
margin-right: -100px;
}
.col::before {
content: '';
position: absolute;
height: 100%;
width: calc(100% + 200px);
margin-left: -100px;
display: block;
background-attachment: fixed;
transform: skew(20deg, 0);
}
.col:hover {
flex-grow: 3;
transition: flex-grow .3s;
}
.col1::before {
background: url(https://images.pexels.com/photos/130184/pexels-photo-130184.jpeg?w=1260&h=750&auto=compress&cs=tinysrgb);
}
.col2::before {
background: url(https://images.pexels.com/photos/354939/pexels-photo-354939.jpeg?w=1260&h=750&auto=compress&cs=tinysrgb);
}
.col3::before {
background: url(https://images.pexels.com/photos/259915/pexels-photo-259915.jpeg?w=1260&h=750&auto=compress&cs=tinysrgb);
}
.col h1 {
margin: 0;
padding: 10px;
transform: skew(20deg, 0);
}
.col:first-child h1 {
margin-left: 40px;
}
<div class="content">
<div class="col col1">
<h1>Foo!</h1>
</div>
<div class="col col2">
<h1>Bar!</h1>
</div>
<div class="col col3">
<h1>Brovinkel!</h1>
</div>
</div>

CSS, overlap children div but the width of parent div stay the same

I would like to make an overlap of children div using position:relative and left attribute. Because of overlapping, I would like to reduce the parent width. However, in fact, the parent div does not reduced.
Here is my codepen. https://codepen.io/anon/pen/eRMMwW
HTML
<div class="mother">
<div class="child">1</div>
<div class="child">2</div>
<div class="child">3</div>
<div class="child">4</div>
</div>
CSS
div.mother {
background-color: red;
display:inline-block;
}
div.child {
background-color: blue;
width: 50px;
height: 50px;
display: inline-block;
position: relative;
}
div.child:nth-child(2) {
left: -25px;
background-color: yellow;
}
div.child:nth-child(3) {
left: -50px;
background-color: pink;
}
div.child:nth-child(4) {
left: -75px;
background-color: green;
}
As you can see, the mother div width does not fit to its own children width and there is an exceed red section. I would like to remove the exceed red section. Do you know any solution here. One more point. I try to avoid flex and float.
Update for Kumar why not reduce the width of children by half.
I suppose to make a cluster of image which overlap each other. Let imagine those child div is round border like this. As you can see, it's not a good idea to set the width of child to half.
You can use negative margins on the inner divs (margin-left: -25px) while giving the parent div an offset margin - (margin-left: 25px)
div.mother {
background-color: red;
display: inline-block;
margin-left: 25px;
}
div.child {
background-color: blue;
width: 50px;
height: 50px;
display: inline-block;
position: relative;
margin-left: -25px;
}
div.child:nth-child(2) {
background-color: yellow;
}
div.child:nth-child(3) {
background-color: pink;
}
div.child:nth-child(4) {
background-color: green;
}
<div class="mother">
<div class="child">1</div>
<div class="child">2</div>
<div class="child">3</div>
<div class="child">4</div>
</div>
This is also easy to animate in case you want to remove the overlap on :hover
Rough animation draft:
div.mother {
background-color: red;
display: inline-block;
margin-left: 25px;
z-index: 1; /* botttom layer */
}
div.child {
background-color: blue;
width: 50px;
height: 50px;
display: inline-block;
position: relative;
margin-left: -25px;
}
div.child:nth-child(2) {
background-color: yellow;
z-index: 2; /* botttom layer +1 */
}
div.child:nth-child(3) {
background-color: pink;
z-index: 3; /* botttom layer +2 */
}
div.child:nth-child(4) {
background-color: green;
z-index: 4; /* botttom layer +3 */
}
div.child:hover {
position: relative;
animation-name: slide;
animation-duration: 1s; /*animation speed */
animation-iteration-count: 1;
animation-fill-mode: forwards; /* makes animation stop at 100% and not revet back to original state */
cursor: pointer;
}
div.child:nth-child(4):hover {
animation-name: none; /* doesn't need animation othewise you would see red background from parent div */
}
#keyframes slide {
0% {
margin-right: 0px;
}
100% {
margin-right: 20px; /* pushes the next div out so you can see current div. */
}
}
<div class="mother">
<div class="child">1</div>
<div class="child">2</div>
<div class="child">3</div>
<div class="child">4</div>
</div>
Apply background:transparent in mother css class.
div.mother {
background: transparent;
display:inline-block;
}
div.child {
background-color: blue;
width: 50px;
height: 50px;
display: inline-block;
position: relative;
border-radius:2em;
}
div.child:nth-child(2) {
left: -25px;
background-color: yellow;
}
div.child:nth-child(3) {
left: -50px;
background-color: pink;
}
div.child:nth-child(4) {
left: -75px;
background-color: green;
}
<div class="mother">
<div class="child">1</div>
<div class="child">2</div>
<div class="child">3</div>
<div class="child">4</div>
</div>

Building horizontal slider - divs floating vertically

I am trying to build simple horizontal image slider with overflow:hidden and floating divs. Hovewer, I am not able to float them horizontally - they always appear in vertical order. I tried many examples from the web, hovewer I still don't know where I am wrong.
HTML:
<div id="slidingWindow">
<div class="slidingSection clearfix">Something something</div>
<div class="slidingSection clearfix">Again something</div>
</div>
CSS:
#slidingWindow {
overflow:hidden;
width: 470px;
height: 500px;
background-color: red;
}
.slidingSection {
margin: 5px;
background-color: green;
width: 470px;
height: 400px;
float: left;
}
.clearfix:after {
content: ".";
visibility: hidden;
display: block;
height: 0;
clear: both;
}
This JSFiddle contains simplest example of my problem:
http://jsfiddle.net/v4udd47t/
If your support is IE10+ and are not concerned with Opera Mini, then you can use display: flex. That way you don't need any extra markup or even floats and clearfix.
Along with using flex you will also have to set a min-width on the slides that is equal to the container minus any margins and padding. In regards to margins and padding, the container will also have to accommodate any that are applied to the slides (I noticed you have a 5px margin on them).
HTML:
<div id="slidingWindow">
<div class="slidingSection clearfix">Something something</div>
<div class="slidingSection clearfix">Again something</div>
</div>
CSS:
#slidingWindow {
overflow:hidden;
width: 480px; /* width of slide + left and right margins */
height: 500px;
background-color: red;
display: -ms-flex;
display: -webkit-flex;
display: flex;
}
.slidingSection {
margin: 5px;
background-color: green;
width: 470px;
min-width: 470px; /* required */
height: 400px;
}
Below is a fork of your fiddle with the size reduced and having an animation on hover to show it is working properly:
#slidingWindow {
overflow:hidden;
width: 260px;
height: 300px;
background-color: red;
display: -ms-flex;
display: -webkit-flex;
display: flex;
}
.slidingSection {
margin: 5px;
background-color: green;
width: 250px;
min-width: 250px;
height: 200px;
-webkit-transition: -webkit-transform 750ms;
transition: transform 750ms;
}
#slidingWindow:hover > .slidingSection {
-webkit-transform: -webkit-translate3d(-260px, 0, 0);
transform: translate3d(-260px, 0, 0);
-webkit-transition: -webkit-transform 750ms;
transition: transform 750ms;
}
<div id="slidingWindow">
<div class="slidingSection">Something something</div>
<div class="slidingSection">Again something</div>
</div>
That's because you need to Wrap the individual sliders in another div that has a width = number of slides*width. I updated your example here, and made the overflow: scroll so you can see the difference http://jsfiddle.net/v4udd47t/1/
<div id="slidingWindow">
<div class="slider-container">
<div class="slidingSection clearfix">Something something</div>
<div class="slidingSection clearfix">Again something</div>
</div>
</div>
.slider-container {
width: 1000px;
}
to set the width dynamically you can do this
var number_of_slides = $(".slidingSection").length;
$(".slider-container").css('width', number_of_slides * 470 + "px");