I'm trying to make a chat app and at the press of a button you can see timestamps of messages slide in.
My timestamp always takes 200px in size and the other takes the rest.
Let's call div1 for the timestamp (200px) and div2 for the messages (takes up the rest of the space).
I tried using the translate on the first div1 and to move and quickly realised that the div2 won't resize automatically:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
*{
padding: 0px;
margin: 0px;
box-sizing: border-box;
}
.chat-container {
display: flex;
height: 50vh;
width: 50vw;
background-color: #f0f0f0;
}
#div1 {
background-color: #0004ff;
height: 100%;
width: 200px;
text-align: center;
position: relative;
left:-200px;
transition: left 1s;
}
#div2 {
background-color: #ff0000;
height: 100%;
text-align: center;
width: calc(100% - 200px); /* 100% - 200px or auto would work*/
}
</style>
</head>
<body>
<div class="chat-container">
<div id="div1">
<p>div1</p>
</div>
<div id="div2">
<p>div2</p>
</div>
</div>
<button id="button">animation</button>
<script>
let actived = false;
document.getElementById("button").addEventListener("click", function() {
const div1 = document.getElementById("div1");
const div2 = document.getElementById("div2");
div1.style.left = actived ? "-200px" : "0px";
actived = !actived;
});
</script>
</body>
</html>
So I tried resizing the size of the div2 but when then I did calc(100% - 200px)
it wasn't the same size!!
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
*{
padding: 0px;
margin: 0px;
box-sizing: border-box;
}
.chat-container {
display: flex;
height: 50vh;
width: 50vw;
background-color: #f0f0f0;
overflow: hidden;
}
#div1 {
background-color: #0004ff;
height: 100%;
width: 200px;
text-align: center;
position: relative;
left:-200px;
transition: left 1s;
}
#div2 {
background-color: #ff0000;
height: 100%;
text-align: center;
width: calc(100% - 200px); /* 100% - 200px or auto would work*/
position: relative;
transition: width 1s;
}
</style>
</head>
<body>
<div class="chat-container">
<div id="div1">
<p>div1</p>
</div>
<div id="div2">
<p>div2</p>
</div>
</div>
<button id="button">animation</button>
<script>
let actived = false;
document.getElementById("button").addEventListener("click", function() {
const div1 = document.getElementById("div1");
const div2 = document.getElementById("div2");
div1.style.left = actived ? "-200px" : "0px";
div2.style.width = actived ? "100%" : "calc(100% - 200px)";
actived = !actived;
});
</script>
</body>
</html>
How can 100%
of the parent minus the div1's size isn't the rest? I'm so confused.
Please tell me what method I should use and why 100% - 200px
doesn't line up.
The difference when toggling is due to implicit flex-shrink
behavior (since elements have a default of flex-shrink: 1
in flex layouts:
The
flex-shrink
property manages removing negative free space to make boxes fit into their container without overflowing. Removing space is a bit more complicated than adding space. The flex shrink factor is multiplied by the flex base size; this distributes negative space in proportion to how much the item can shrink. This prevents smaller items from shrinking to0px
before a larger item is noticeably reduced.
This may be better demonstrated through example.
Say chat-container
is 500px
wide.
The intrinsic widths of the elements before any flex shrinking has taken place is:
div1 | div2 |
---|---|
200px |
100% - 200px = 500px - 200px = 300px |
No shrinking happens, everything fits exactly.
Click the animation button twice and then div2's width
is now 100%
, thus:
div1 | div2 |
---|---|
200px |
100% = 500px |
Now, div1 and div2 are now wider than the container, since changing left
on div1 does not remove the space it takes up. Thus, flex shrinking calculations happen as follows:
Calculate the surplus widths of our child elements:
200px + 500px - 500px = 200px;
↑ ↑ ↑
div1 div2 container
The ratio of div1:div2 is 2:5
, thus we allocate this 200px
surplus between them as follows:
div1 | div2 |
---|---|
200px ÷ 7 × 2 ≈ 57px |
200px ÷ 7 × 5 ≈ 143px |
Thus the final widths are as follows:
div1 | div2 |
---|---|
143px |
357px |
If you want to actually slide the div1 in and out, you can use margin
, and let div2 fill up the space naturally with flex-grow: 1
:
let actived = false;
document.getElementById("button").addEventListener("click", function() {
const div1 = document.getElementById("div1");
div1.style.marginLeft = actived ? "-200px" : "0px";
actived = !actived;
});
* {
padding: 0px;
margin: 0px;
box-sizing: border-box;
}
.chat-container {
display: flex;
height: 50vh;
width: 50vw;
background-color: #f0f0f0;
overflow: hidden;
}
#div1 {
background-color: #0004ff;
height: 100%;
width: 200px;
text-align: center;
position: relative;
margin-left: -200px;
transition: margin-left 1s;
}
#div2 {
background-color: #ff0000;
height: 100%;
text-align: center;
flex-grow: 1;
}
<div class="chat-container">
<div id="div1">
<p>div1</p>
</div>
<div id="div2">
<p>div2</p>
</div>
</div>
<button id="button">animation</button>