Fixing full-bleed CSS
摘要
文章讨论了 Josh Comeau 介绍的全屏布局(full-bleed)通常用 CSS 网格实现,但整个页面无法用网格时,Andy Bell 的实用类可用。指出 viewport 单位(如 100vw)存在经典滚动条问题:macOS 或有花样滚动条的系统下,在 Windows 测试时 100vw 会比视口宽,导致裁切几像素,建议加边框或阴影观察。macOS 外观设置中 “始终显示滚动条” 可复现此问题。Andy 部分解决方案是隐藏<body>元素横向溢出;另一种是始终为经典滚动条预留空间。现代方案是使用 CSS containment 将<body>或 100% 宽子元素转为容器,用容器单位(cqi)替换视口单位,隐藏溢出不再严格必要,推荐 clip 方案并用逻辑属性支持 RTL。作者 fork 了 Andy 的 CodePen,添加嵌套容器证明问题存在,引入 @property at-rule 定义 --body-size 变量使值在设置点计算(相对于父容器),解决嵌套场景;建议直接子元素如<main>设置该变量。结尾提 CSS 需提供容器引用功能,提议 Cancel Interop 2026 实现。
荐读理由
通过 CSS container 单位与 @property 自定义属性结合,主体据此可直接在 AI 工程项目中实现全屏布局的精准控制,避免视口单位宽度超出的对齐问题,同时支持子容器嵌套与 RTL 方向
原文
Fixing full-bleed CSS
Friday 3 Jul 2026 Play Synthesised Audio
I’m a front-end developer not a medical practitioner. If you’re bleeding IRL visit the hospital and stop googling medical issues!
The full-bleed layout — as described there by Josh Comeau — can be done with CSS grid (and subgrid). Sometimes you can’t grid the entire page.
That’s where Andy Bell’s utility class is useful.
.full-bleed {
width: 100vw;
margin-left: calc(50% - 50vw);
}
But it ain’t perfect. The issue is that viewport units don’t solve the classic scrollbar problem. If you’re on macOS or a fancy OS that has fancy scrollbars, test on Windows! 100vw can be wider than the viewport. Because why would browsers do anything sensible?
It’s hard to see in Andy’s CodePen but a few pixels can be cropped either side. Add something like a border or shadow and it’s easier to see.
.full-bleed {
box-shadow: inset 0 0 0 10px yellow;
}

Ignore the pink left border that’s my blog style.
This is not always a problem but it can lead to subtle alignment issues. By the way, macOS has a scrollbar setting “Show scroll bars > Always” that’ll let you test the issue.

macOS scrollbar settings on the appearance tab.
Andy solves this partially by hiding horizontal overflow on the <body> element.
body {
overflow-x: hidden;
}
An alternative fix is to always reserve space for the classic scrollbar.
html {
scrollbar-gutter: stable;
}
That can look weird if there is no vertical scroll necessary.
Modern solution
The “modern” approach is to use CSS containment. Turn the <body> element (or any 100% width child) into a container. Then replace the viewport units with container units.
body {
container: body / inline-size;
overflow-x: clip;
}
.full-bleed {
inline-size: 100cqi;
margin-inline-start: calc(50% - 50cqi);
}
Now hiding overflow is not strictly necessary. I prefer clip — see Overflow Clip guide by Ahmad Shadeed. I clip out of caution because I make dumb things. I also use logical properties and values to support right-to-left (RTL) text direction. Ahmad has an excellent RTL Styling 101 too.
But wait!
Using cqi units assumes body is the parent container of the .full-bleed element. What if we have nested containers? Check this out. I’ve forked Andy’s CodePen to add another .inside container that is not the full viewport width.

Inspecting CSS container layout using Chromium dev tools to show that the inside container is smaller.
This alone would usually break the new .full-bleed class and ruin the fun.
But we can fix that!
@property --body-size {
syntax: "<length> | <percentage>";
inherits: true;
initial-value: 100%;
}
body {
container: body / inline-size;
}
.inside {
--body-size: 100cqi;
container: inside / inline-size;
}
.full-bleed {
inline-size: var(--body-size);
margin-inline-start: calc(50% - (0.5 * var(--body-size))); /* † */
}
What is that @property magic?
To be honest I struggle to wrap my smooth brain around this!
Let me try to explain it to myself. Without the at-rule the value of --body-size is calculated at the time of use, i.e. within .full-bleed and therefore relative to the inside container. By explicitly defining a @property the value is now calculated when it’s set within .inside. There 100cqi refers to the parent body container and .full-bleed inherits that value.
But what if you have more containers?
(╯°□°)╯︵ ┻━┻
Gosh! Stop being so difficult!
I would have a direct child of <body> like <main> set the --body-size value.
<body>
<main>
<!-- blah -->
</main>
</body>
† I’m multiplying by 0.5 because division is for chumps.
Next-gen solution
What CSS needs is a way to reference a container when using container units.
Ideas have been proposed for example:
.full-bleed {
inline-size: 100cqi(body);
inline-size: calc(100 * cqi(body));
inline-size: calc(100 * container(cqi, body));
}
Cancel Interop 2026 and make this happen!
这条对你有帮助吗?