This is my minimal reproduction (only works in Chromium browsers due to calc-size
):
.parent {
display: flex;
align-items: start;
}
.item {
display: flex;
flex-direction: column;
background: orange;
}
p {
box-sizing: border-box;
overflow: hidden;
}
.long {
width: 100%;
opacity: 0;
margin: 0;
padding: 0;
overflow: hidden;
white-space: nowrap;
transition:
width 3s,
opacity 3s;
}
.item:hover .long {
height: 1.5rem;
width: calc-size(auto, size);
opacity: 1;
}
<div class="parent">
<div class="item">
<p>Good test.</p>
<p class="long collapsed">Yappity yap yap yap.</p>
</div>
</div>
I recently switched from width: 0
to width: 100%
for the long
paragraph to try to make the animation smoother (no animating from the absolute start), but it isn't working as intended. It's making the container wider when it's in the collapsed form (although oddly it works fine while animating).
So what can I do? How do I either make width: 100%
not affect the width of the parent or otherwise use the available width in the collapsed state for the starting width in the animation instead of 0?
Clarification: this is a version that uses a fixed width to mock up what I'm aiming for (closed = exact width of parent container, open = normal width):
.parent {
display: flex;
align-items: start;
}
.item {
display: flex;
flex-direction: column;
background: orange;
}
p {
box-sizing: border-box;
overflow: hidden;
}
.long {
width: 75px;
opacity: 0;
margin: 0;
padding: 0;
overflow: hidden;
white-space: nowrap;
transition:
width 3s,
opacity 3s;
}
.item:hover .long {
height: 1.5rem;
width: 157px;
opacity: 1;
}
<div class="parent">
<div class="item">
<p>Good test.</p>
<p class="long collapsed">Yappity yap yap yap.</p>
</div>
</div>
You cannot animate a parent from auto
-to- auto
. Or, in other words, from a first shorter child width — to a longer child width, natively.
What you can do (without using JavaScript) is to animate from a known width — to auto
, using interpolate-size: allow-keywords;
.
In the example below I stored the initial width into a CSS Property (var) in the style attribute like <div class="item" style="--initialWidth: 8ch;">
* {
margin: 0;
box-sizing: border-box;
}
.item {
display: inline-flex;
flex-direction: column;
background: orange;
overflow: hidden;
transition: width 2s;
width: var(--initialWidth, 10ch);
interpolate-size: allow-keywords;
P {
white-space: nowrap;
&.long {
opacity: 0;
transition: opacity 2s;
}
}
&:hover {
width: auto;
}
&:hover .long {
opacity: 1;
}
}
<div class="item" style="--initialWidth: 8ch;">
<p class="short">Good test.</p>
<p class="long">Yappity yap yap yap.</p>
</div>
<div class="item" style="--initialWidth: 13ch;">
<p class="short">Super good test.</p>
<p class="long">Lorem ipsom dolor sit amet consectetur adipiscing elit.</p>
</div>
Now, if you want that --initialWidth to be dynamic, you'll have to calculate it using JavaScript (and be prepared to, once done, see flickers of widths - or tackle that problem as well).