Multiple divs width transition with 100% fill of parent - html

I've got such an issue:
I want to increase hovered div width with simultaneously width decrease of his siblings. Everything works fine without setting transition property.
If I set transition and move mouse quickly. My divs don't fully fill their parent.
Here's my code:
#parent {
display: block;
position: relative;
}
#parent .child {
float: left;
height: 300px;
width: 20%;
background-color: red;
transition: width .5s;
}
#parent .child:nth-child(2) {
background-color: grey;
}
#parent .child:nth-child(3) {
background-color: green;
}
#parent .child:nth-child(4) {
background-color: yellow;
}
#parent .child:nth-child(5) {
background-color: brown;
}
#parent:hover .child {
width: 17.25%;
}
#parent:hover .child:hover {
width: 31%;
}
<div id="parent">
<div class="child">1</div>
<div class="child">2</div>
<div class="child">3</div>
<div class="child">4</div>
<div class="child">5</div>
</div>
Do you have any ideas how to solve this problem? Can I fix it with pure CSS or I should use javascript for it?

Perhaps using Flexbox would give you a smoother effect.
You can adjust the flex property as you need to get the dimensions right.
body,
html {
/* for demo purposes */
padding: 0;
margin: 0;
}
#parent {
display: flex;
}
#parent .child {
height: 300px;
flex: 1 1 auto;
background-color: red;
transition: all .5s;
}
#parent .child:nth-child(2) {
background-color: grey;
}
#parent .child:nth-child(3) {
background-color: green;
}
#parent .child:nth-child(4) {
background-color: yellow;
}
#parent .child:nth-child(5) {
background-color: brown;
}
#parent .child:hover {
flex: 2 1 auto;
}
<div id="parent">
<div class="child">1</div>
<div class="child">2</div>
<div class="child">3</div>
<div class="child">4</div>
<div class="child">5</div>
</div>

Related

CSS - Animate parent width when child element is removed

I have a div container inside a flex container with set maximum width. When a child is removed the width will decrease. Is it possible to animate the width change with just CSS?
function remove(el) {
var element = el;
element.remove();
}
#flex {
display: flex;
}
#parent {
max-width: 200px;
background: blue;
border: 2px solid green;
height: 100px;
width: auto;
}
#child {
width: 100px;
height: 100px;
background: red;
}
#other {
flex: 1;
height: 100px;
background: yellow;
}
<div id="flex">
<div id="parent">
<div id="child" onclick="remove(this)">
</div>
</div>
<div id="other">
</div>
</div>
You cannot do with pure CSS. The animation is based on the width changes, so you need to set the width of #child to 0 by Javascript. To remove #child completely, you can delay it with setTimeout.
function remove(el) {
var element = el;
el.style.width = 0; //trigger the animation with width changes
setTimeout(() => {
element.remove();
}, 500); //0.5 seconds
}
#flex {
display: flex;
}
#parent {
max-width: 200px;
background: blue;
border: 2px solid green;
height: 100px;
width: auto;
}
#child {
width: 100px;
height: 100px;
background: red;
transition: width 0.5s; /* Width animation in 0.5 seconds */
}
#other {
flex: 1;
height: 100px;
background: yellow;
}
<div id="flex">
<div id="parent">
<div id="child" onclick="remove(this)">
</div>
</div>
<div id="other">
</div>
</div>

Make empty Div in Flex 100% Height

Using the following my .divider <div> is not showing. I guess this is because it is empty. If I add a "." in there, then I see it. Is it possible to make it 100% the height of the .wrapper without adding content?
.wrapper {
display: flex;
background-color: orange;
}
.left {
background-color: gray;
}
.divider {
background-color: green;
cursor: ew-resize;
width: 12px;
height: 100%;
}
.right {
flex-grow: 1;
background-color: yellow;
}
<div class="wrapper">
<div class="left">Left</div>
<div class="divider"></div>
<div class="right">Right</div>
</div>
https://jsfiddle.net/sub7fxk5/
Remove height: 100%; for .divider
.wrapper {
display: flex;
background-color: orange;
}
.left {
background-color: gray;
}
.divider {
background-color: green;
cursor: ew-resize;
width: 12px;
/* height: 100%; */
}
.right {
flex-grow: 1;
background-color: yellow;
}
<div class="wrapper">
<div class="left">Left</div>
<div class="divider"></div>
<div class="right">Right</div>
</div>
Removing the height and adding flex: 1 seems to help.
Is the result of the code below what you expect it to be?
The wrapper has no height, that means that setting a height to 100% would equal setting the height to 0.
the flex: 1 makes the item flexible even though it has no content and it shows.
Of course you can set a width too. So width: 12px would work. As would width: 100%; (which would push the left and right item to the other side)
You might also use a pseudo-element ::after as a divider. That would clean up your html a bit.
.wrapper {
display: flex;
background-color: orange;
}
.left {
background-color: gray;
}
.divider {
background-color: green;
cursor: ew-resize;
flex: 1;
}
.right {
flex-grow: 1;
background-color: yellow;
}
<div class="wrapper">
<div class="left">Left<br/><br/>Left</div>
<div class="divider"></div>
<div class="right">Right</div>
</div>

Pull the previous sibling element

You can use margin-right, for example, to push a next sibling as seen below:
#parent {
background: tan;
font-size: 0;
}
#parent * {
display: inline-block;
width: 50px;
height: 50px;
}
#child1 {
background: teal;
margin-right: 100px;
}
#child2 {
background: olive;
}
<div id="parent">
<div id="child1"></div>
<div id="child2"></div>
</div>
I know there is no previous sibling selector in CSS. However, I wonder if there's a workaround so #child2 can pull #child1 to a distance of say, 20px. Here's a before-after screenshot:
Note: I don't want to give a margin value to #child1 or alter the HTML. The effect should be achieved using #child2 only.
This code works for me, it doesn't touch #child1 but #parent. Changed to classes instead of ids just to show the same code works for all.
.parent {
background: tan;
font-size: 0;
display: flex;
}
.parent * {
display: inline-block;
width: 50px;
height: 50px;
}
.child1 {
background: teal;
margin-right: 100px;
}
.child2 {
background: olive;
}
.child3 {
background: red;
}
.parent > div:only-child {
margin-right:100px;
margin-left:0px;
}
.parent > div {
margin-right:20px;
}
.parent > div:first-child:not(:last-child) {
margin-left:60px;
}
<div class="parent">
<div class="child1"></div>
<div class="child2"></div>
<div class="child3"></div>
</div>
<br>
<div class="parent">
<div class="child1"></div>
<div class="child2"></div>
</div>
<br>
<div class="parent">
<div class="child1"></div>
</div>
There is no previous sibling selector using pure CSS.
The possible workaround is using CSS flexbox.
First, set display property as flex to the #parent element. reverse the order of displaying child elements
<div id="child2"></div>
<div id="child1"></div>
We can correct this visually by setting
order:-1 to #child1.
Then we will address the #child1 by using
#parent>div:first-child+div
This means the next div after the first div, ie, #child1. Then set the styles.
#parent>div:first-child+div {
margin-right: 20px;
margin-left: 80px;
}
#parent {
background: tan;
display: flex;
}
#parent * {
width: 50px;
height: 50px;
}
#child1 {
background: teal;
order: -1;
}
#child2 {
background: olive;
}
#parent>div:first-child+div {
margin-right: 20px;
margin-left: 80px;
}
<div id="parent">
<div id="child2"></div>
<div id="child1"></div>
</div>
For better understandability, hover the #child2 then you can see the color change of its previous sibling.
#child2:hover+div {
background: brown;
}
#parent {
background: tan;
display: flex;
}
#parent * {
width: 50px;
height: 50px;
}
#child1 {
background: teal;
order: -1;
}
#child2 {
background: olive;
}
#parent>div:first-child+div {
margin-right: 20px;
margin-left: 80px;
}
#child2:hover+div {
background: brown;
}
<div id="parent">
<div id="child2"></div>
<div id="child1"></div>
</div>
According to your replies on the given answers your question should have been:
Can you 'pull the previous sibling element' by using CSS (only), and without changing the HTML?
The answer to that question is as simple as unsatisfying:
No, there is not.
Not even when you change the reading direction. I am sorry.
I am not sure whether this is what the OP is asking, but the following code, pulls the first child only when the second child exists, so in a sense, the second child pulls the first one :)
#parent > div:first-child:nth-last-child(2) {
margin-left:60px;
margin-right:20px;
}
Here is a working fiddle:
https://jsfiddle.net/06urn796/
Removing the second child, leaves the first one intact:
https://jsfiddle.net/06urn796/1/
#parent {
background: tan;
font-size: 0;
}
#parent * {
display: inline-block;
width: 50px;
height: 50px;
}
#parent div{
margin: 0px 20px;
}
#child1 {
background: teal;
}
#child2 {
background: olive;
}
<div id="parent">
<div id="child1"></div>
<div id="child2"></div>
</div>

Div content in wrong position

I'm trying to put 3 divs in the same row as the following code.
My CSS and HTML:
.row {
display: table;
width: 100%
}
.row > div {
display: table-cell;
height:30px; /*demo purposes */
}
#left-bar {
width: 10%;
background-color: #FF0000;
}
#middle-bar {
width: 70%;
background-color: #6600FF;
}
#right-bar {
width: 20%;
background-color: #99FF99;
}
<div class="row">
<div id="left-bar"> here I have an accordion </div>
<div id="middle-bar"> heve a have my canvas </div>
<div id="right-bar"> and here I have an editor</div>
</div>
Somehow the content of the middle-bar(my canvas) is positioned in the correct place, but the other two divs contents are in the bottom of the page as you can see here see photo. Do you guys know why this is happening?
After discussing the project further with you in the comments, and in chat, I think you should take an approach that uses flexbox instead. The code is fairly straight forward:
.container {
display: flex;
}
.left { flex-basis: 10%; background: #F99; }
.right { flex-basis: 20%; background: #99F; }
.middle { flex-basis: 70%; background: #9F9; }
<div class="container">
<div class="left">L</div>
<div class="middle">C</div>
<div class="right">R</div>
</div>
I only managed width.
There's nothing problematic see this.
.row {
display: table;
width: 100%
}
.row > div {
display: table-cell;
height:30px; /*demo purposes */
}
#left-bar {
width: 20%;
background-color: #FF0000;
}
#middle-bar {
width: 60%;
background-color: #6600FF;
}
#right-bar {
width: 20%;
background-color: #99FF99;
}
<div class="row">
<div id="left-bar"> here I have an accordion </div>
<div id="middle-bar"> heve a have my canvas </div>
<div id="right-bar"> and here I have an editor</div>
</div>

Centering multiple side-by-side divs

I am trying to make multiple divs, specifically five and center them all. I have used the display:inline-block to get them to be side by side but then when I use margin: 0 auto, the display:inline-block seems to get negated and then it's a vertical strip going down the page.
Below is my code:
div {
width: 50px;
height: 300px;
border-radius: 0;
display: inline-block;
}
#red {
background-color: red;
}
#orange {
background-color: orange;
}
#yellow {
background-color: yellow;
}
#green {
background-color: green;
}
#blue {
background-color: blue;
}
<div class="container">
<div id="red"></div>
<div id="orange"></div>
<div id="yellow"></div>
<div id="green"></div>
<div id="blue"></div>
</div>
I tried looking at the other relevant posts on SO but they don't do it with as many divs or they use static positioning which I don't want to use.
Can someone point me in the right direction?
This happens cause the width of the container is 50px. One quick solution is to set width of container to 100%:
div {
width: 50px;
height: 300px;
border-radius: 0;
display: inline-block;
}
#red {
background-color: red;
}
#orange {
background-color: orange;
}
#yellow {
background-color: yellow;
}
#green {
background-color: green;
}
#blue {
background-color: blue;
}
.container {
width: 100%;
}
<div class="container">
<div id="red"></div>
<div id="orange"></div>
<div id="yellow"></div>
<div id="green"></div>
<div id="blue"></div>
</div>
You can align to center using text-align center to container:
div {
width: 50px;
height: 300px;
border-radius: 0;
display: inline-block;
}
#red {
background-color: red;
}
#orange {
background-color: orange;
}
#yellow {
background-color: yellow;
}
#green {
background-color: green;
}
#blue {
background-color: blue;
}
.container {
width: 100%;
text-align: center;
}
<div class="container">
<div id="red"></div>
<div id="orange"></div>
<div id="yellow"></div>
<div id="green"></div>
<div id="blue"></div>
</div>
To achieve both and vertical and horizontal align you can use position: absolute to the container top: 50% left: 50% and margin-top: -150px; /* Half the height */ margin-left: -135px; /* Half the width */:
div {
width: 50px;
height: 300px;
border-radius: 0;
display:inline-block;
}
#red {
background-color: red;
}
#orange {
background-color: orange;
}
#yellow {
background-color: yellow;
}
#green {
background-color: green;
}
#blue {
background-color: blue;
}
.container {
width: 270px;
position: absolute;
top: 50%;
left:50%;
margin-top: -150px; /* Half the height */
margin-left: -135px; /* Half the width */
}
<div class="container">
<div id="red"></div>
<div id="orange"></div>
<div id="yellow"></div>
<div id="green"></div>
<div id="blue"></div>
</div>
You can set text-align: center on .container. Updated you code:
.container {
width: 100%;
text-align: center;
}
.container > div{
width: 50px;
height: 300px;
border-radius: 0;
display:inline-block;
}
http://jsfiddle.net/jermund/wzdLrs0m/