The stretch keyword, which you can use with width and height (as well as min-width, max-width, min-height, and max-height, of course), was shipped in Chromium web browsers back in June 2025. But the value is actually a unification of the non-standard -webkit-fill-available and -moz-available values, the latter of which has been available to use in Firefox since 2008.
The issue was that, before the @supports at-rule, there was no nice way to implement the right value for the right web browser, and I suppose we just forgot about it after that until, whoops, one day I see Dave Rupert casually put it out there on Bluesky a month ago:

Layout pro Miriam Suzanne recorded an explainer shortly thereafter. It’s worth giving this value a closer look.
What does stretch do?
The quick answer is that stretch does the same thing as declaring 100%, but ignores padding when looking at the available space. In short, if you’ve ever wanted 100% to actually mean 100% (when using padding), stretch is what you’re looking for:
div {
padding: 3rem 50vw 3rem 1rem;
width: 100%; /* 100% + 50vw + 1rem, causing overflow */
width: stretch; /* 100% including padding, no overflow */
}
The more technical answer is that the stretch value sets the width or height of the element’s margin box (rather than the box determined by box-sizing) to match the width/height of its containing block.
Note: It’s never a bad idea to revisit the CSS Box Model for a refresher on different box sizings.
And on that note — yes — we can achieve the same result by declaring box-sizing: border-box, something that many of us do, as a CSS reset in fact.
*,
::before,
::after {
box-sizing: border-box;
}
I suppose that it’s because of this solution that we forgot all about the non-standard values and didn’t pay any attention to stretch when it shipped, but I actually rather like stretch and don’t touch box-sizing at all now.
Yay stretch, nay box-sizing
There isn’t an especially compelling reason to switch to stretch, but there are several small ones. Firstly, the Universal selector (*) doesn’t apply to pseudo-elements, which is why the CSS reset typically includes ::before and ::after, and not only are there way more pseudo-elements than we might think, but the rise in declarative HTML components means that we’ll be seeing more of them. Do you really want to maintain something like the following?
*,
::after,
::backdrop,
::before,
::column,
::checkmark,
::cue (and ::cue()),
::details-content,
::file-selector-button,
::first-letter,
::first-line,
::grammar-error,
::highlight(),
::marker,
::part(),
::picker(),
::picker-icon,
::placeholder,
::scroll-button(),
::scroll-marker,
::scroll-marker-group,
::selection,
::slotted(),
::spelling-error,
::target-text,
::view-transition,
::view-transition-image-pair(),
::view-transition-group(),
::view-transition-new(),
::view-transition-old() {
box-sizing: border-box;
}
Okay, I’m being dramatic. Or maybe I’m not? I don’t know. I’ve actually used quite a few of these and having to maintain a list like this sounds dreadful, although I’ve certainly seen crazier CSS resets. Besides, you might want 100% to exclude padding, and if you’re a fussy coder like me you won’t enjoy un-resetting CSS resets.
Animating to and from stretch
Opinions aside, there’s one thing that box-sizing certainly isn’t and that’s animatable. If you didn’t catch it the first time, we do transition to and from 100% and stretch:
Because stretch is a keyword though, you’ll need to interpolate its size, and you can only do that by declaring interpolate-size: allow-keywords (on the :root if you want to activate interpolation globally):
:root {
/* Activate interpolation */
interpolate-size: allow-keywords;
}
div {
width: 100%;
transition: 300ms;
&:hover {
width: stretch;
}
}
The calc-size() function wouldn’t be useful here due to the web browser support of stretch and the fact that calc-size() doesn’t support its non-standard alternatives. In the future though, you’ll be able to use width: calc-size(stretch, size) in the example above to interpolate just that specific width.
Web browser support
Web browser support is limited to Chromium browsers for now:
- Opera 122+
- Chrome and Edge 138+ (140+ on Android)
Luckily though, because we have those non-standard values, we can use the @supports at-rule to implement the right value for the right browser. The best way to do that (and strip away the @supports logic later) is to save the right value as a custom property:
:root {
/* Firefox */
@supports (width: -moz-available) {
--stretch: -moz-available;
}
/* Safari */
@supports (width: -webkit-fill-available) {
--stretch: -webkit-fill-available;
}
/* Chromium */
@supports (width: stretch) {
--stretch: stretch;
}
}
div {
width: var(--stretch);
}
Then later, once stretch is widely supported, switch to:
div {
width: stretch;
}
In a nutshell
While this might not exactly win Feature of the Year awards (I haven’t heard a whisper about it), quality-of-life improvements like this are some of my favorite features. If you’d rather use box-sizing: border-box, that’s totally fine — it works really well. Either way, more ways to write and organize code is never a bad thing, especially if certain ways don’t align with your mental model.
Plus, using a brand new feature in production is just too tempting to resist. Irrational, but tempting and satisfying!
Can’t wait to start using this property in 2035 when all users are updated
The main reason for using stretch is to avoid overflow when using margins. If you have an element with some margin, setting width to 100% will overlap the parent container regardless of box sizing. By using width: stretch the container won’t overflow.
“I suppose that it’s because of this solution that we forgot all about the non-standard values and didn’t pay any attention to stretch when it shipped, but I actually rather like stretch and don’t touch box-sizing at all now.”
Yes, you like it. But most people don’t. That’s why using box-sizing with an asterisk has become standard practice. Anyway, basic “spreading” is considered a mistake.
https://wiki.csswg.org/ideas/mistakes
“Box-sizing should be border-box by default.”
It’s standard practice because it’s the only option until the other two major browsers pick it up. It’s nice to have options. I personally don’t consider it a mistake (anymore).
You didn’t mention that
height: stretchdoesn’t have a non-standard equivalent in Firefox, onlywidthdoes, so animated height won’t work :/How odd! I didn’t catch that.
I haven’t tested it too much, so don’t quote me on this, but I noticed we can’t use
stretchin something likemin(some-value, stretch).It would be huge for
stretch, so I hope it can be implemented soon :)I agree. I don’t think
min()works with any intrinsic values, even if interpolated.