Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

A moving element to push adjacent element only if they collide

Tags:

html

css

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.

like image 351
Danield Avatar asked Feb 10 '15 10:02

Danield


3 Answers

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/

like image 121
Jose Rui Santos Avatar answered Nov 17 '22 23:11

Jose Rui Santos


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.

like image 25
jbutler483 Avatar answered Nov 17 '22 22:11

jbutler483


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>
like image 3
Arzach15 Avatar answered Nov 18 '22 00:11

Arzach15