min-content、max-content and fit-content are magic keyword for describing length. Developers could set the suitable size through these value setting.
Howerver CSS animation won't running with these values. Because browser can't gether the exactly length information for mutation.
With CSS: interpolate-size setting, It's possible to run animation with these magin keywords. Browser will exchange the length before running animation, so the animation will run as good as you wish.
Check the following sample out. It applied interpolate-size: allow-keywords for buttons section and set transition when its inline-size change(fit-content <--> 40px ). The input field will bend when you type something.
Add Circle
Collections
Sticky Note
Mic
Tutorial
Chekc the following tutorial and see how the sample works.
VIDEO
Instantiation
Developers could copy / paste the following style、HTML and JavaScript into your web page and check the effect.
style
<style>
.container {
--count: 5;
--gap: .5em;
/* self */
--inline-size: 400px;
--background-color: rgba(255 255 255);
--box-shadow: 0 0 1px rgba(0 0 0/.1), 0 2px 4px rgba(0 0 0/.08);
/* button */
--button-size: 40;
--button-size-with-unit: calc(var(--button-size) * 1px);
--button-icon-scale-rate: .57;
--button-icon-scale-basis: calc((var(--button-size) * var(--button-icon-scale-rate)) / 24);
--button-background-color-normal: transparent;
--button-background-color-active: rgba(242 242 242);
--button-background-color: var(--button-background-color-normal);
--icon-color: rgba(64 104 240);
--icon-collections: path('M20 4v12H8V4h12m0-2H8c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-8.5 9.67l1.69 2.26 2.48-3.1L19 15H9zM2 6v14c0 1.1.9 2 2 2h14v-2H4V6H2z');
--icon-sticky-note: path('M19,5v9l-5,0l0,5H5V5H19 M19,3H5C3.9,3,3,3.9,3,5v14c0,1.1,0.9,2,2,2h10l6-6V5C21,3.9,20.1,3,19,3z M12,14H7v-2h5V14z M17,10H7V8h10V10z');
--icon-mic: path('M12 14c1.66 0 2.99-1.34 2.99-3L15 5c0-1.66-1.34-3-3-3S9 3.34 9 5v6c0 1.66 1.34 3 3 3zm5.3-3c0 3-2.54 5.1-5.3 5.1S6.7 14 6.7 11H5c0 3.41 2.72 6.23 6 6.72V21h2v-3.28c3.28-.48 6-3.3 6-6.72h-1.7z');
--icon-add-circle: path('M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm5 11h-4v4h-2v-4H7v-2h4V7h2v4h4v2z');
--icon-video-call: path('M17 10.5V7c0-.55-.45-1-1-1H4c-.55 0-1 .45-1 1v10c0 .55.45 1 1 1h12c.55 0 1-.45 1-1v-3.5l4 4v-11l-4 4zM15 16H5V8h10v8zm-6-1h2v-2h2v-2h-2V9H9v2H7v2h2z');
--icon-games: path('M13 4v2.67l-1 1-1-1V4h2m7 7v2h-2.67l-1-1 1-1H20M6.67 11l1 1-1 1H4v-2h2.67M12 16.33l1 1V20h-2v-2.67l1-1M15 2H9v5.5l3 3 3-3V2zm7 7h-5.5l-3 3 3 3H22V9zM7.5 9H2v6h5.5l3-3-3-3zm4.5 4.5l-3 3V22h6v-5.5l-3-3z');
--button-add-display-normal: none;
--button-add-display-active: grid;
--button-add-display: var(--button-add-display-normal);
/* input */
--input-background-color: rgba(240 242 245);
--input-placeholder-color: rgba(108 110 114);
--input-color: rgba(8 8 9);
/* container__actions */
--actions-inline-size-normal: fit-content;
--actions-inline-size-active: var(--button-size-with-unit);
--actions-inline-size: var(--actions-inline-size-normal);
inline-size: var(--inline-size);
background-color: var(--background-color);
border-radius: 4em;
padding: .75em;
box-sizing: border-box;
box-shadow: var(--box-shadow);
display: flex;
gap: var(--gap);
button {
flex-shrink: 0;
font-size: 0;
appearance: none;
box-shadow: unset;
border: unset;
background: transparent;
-webkit-user-select: none;
user-select: none;
pointer-events: auto;
margin: 0;
padding: 0;
outline: 0 none;
}
&:not(:has(:placeholder-shown)) {
--actions-inline-size: var(--actions-inline-size-active);
--button-add-display: var(--button-add-display-active);
:nth-child(1 of .container__actions__button:not(.container__actions__button--add-circle)) {
visibility: hidden;
}
}
.container__actions {
interpolate-size: allow-keywords;
flex-shrink: 0;
position: relative;
inline-size: var(--actions-inline-size);
display: flex;
gap: var(--gap);
overflow: clip;
transition: inline-size .25s ease;
will-change: inline-size;
.container__actions__button {
inline-size: var(--button-size-with-unit);
aspect-ratio: 1/1;
background-color: var(--button-background-color);
border-radius: var(--button-size-with-unit);
display: grid;
place-content: center;
transition: background-color .2s ease;
will-change: background-color;
@media (hover: hover) {
&:hover {
--button-background-color: var(--button-background-color-active);
}
}
&:active {
scale: .85;
}
&::before {
content: '';
inline-size: 24px;
aspect-ratio: 1/1;
background-color: var(--icon-color);
display: block;
clip-path: var(--icon);
scale: var(--button-icon-scale-basis);
}
&.container__actions__button--add-circle {
--icon: var(--icon-add-circle);
position: absolute;
inset-inline-start: 0;
inset-block-start: 0;
display: var(--button-add-display);
}
&.container__actions__button--collections {
--icon: var(--icon-collections);
}
&.container__actions__button--sticky-note {
--icon: var(--icon-sticky-note);
}
&.container__actions__button--mic {
--icon: var(--icon-mic);
}
&.container__actions__button--video-call {
--icon: var(--icon-video-call);
}
&.container__actions__button--games {
--icon: var(--icon-games);
}
}
}
.container__form {
flex-grow: 1;
min-inline-size: 0;
.container__form__input {
inline-size: 100%;
block-size: var(--button-size-with-unit);
font-size: 16px;
color: var(--input-color);
line-height: var(--button-size-with-unit);
background-color: var(--input-background-color);
box-sizing: border-box;
display: block;
padding-inline: 1em;
border-radius: var(--button-size-with-unit);
border: 0 none;
outline: 0 none;
caret-color: var(--icon-color);
&::-webkit-input-placeholder {
color: var(--input-placeholder-color);
}
&::-moz-placeholder {
color: var(--input-placeholder-color);
}
}
}
}
</style>
HTML
<div class="container">
<div class="container__actions">
<button type="button" class="container__actions__button container__actions__button--add-circle">Add Circle</button>
<button type="button" class="container__actions__button container__actions__button--collections">Collections</button>
<button type="button" class="container__actions__button container__actions__button--sticky-note">Sticky Note</button>
<button type="button" class="container__actions__button container__actions__button--mic">Mic</button>
<button type="button" class="container__actions__button container__actions__button--video-call">Video Call</button>
<button type="button" class="container__actions__button container__actions__button--games">Games</button>
</div>
<form class="container__form">
<input type="text" class="container__form__input" placeholder="Aa" />
</form>
</div>
The animation will happen only when user type something. So we can apply CSS pseudo class for mutation. Pure CSS is rock!
<style>
.container {
...
--actions-inline-size-normal: fit-content;
--actions-inline-size-active: 40px;
--actions-inline-size: var(--actions-inline-size-normal);
&:not(:has(:placeholder-shown)) {
--actions-inline-size: var(--actions-inline-size-active);
}
...
}
</style>
How to detect current rowser support or not ?
Developers could use CSS or JavaScript detect current enviroment support interpolate-size or not.
CSS
<style>
@supports (interpolate-size: allow-keywords) {
/* Yes. current enviroment support interpolate-size */
...
}
</style>
JavaScript
<script type="module">
const support = CSS.supports('interpolate-size', 'allow-keywords');
if (support) {
/* Yes. current enviroment support interpolate-size */
...
}
</script>
Reference