CSS Grid 横向溢出时 position: sticky 为何异常?
结论
grid-template-columns: 12em 100% 会让两列的总宽度达到视口宽度再加上 12em,因为第二列的 100% 是按网格容器的宽度计算的。横向溢出会影响页面和网格的尺寸,但本身不应直接改变 position: sticky 的垂直定位规则。
sticky 的位置受最近的滚动容器和包含块边界限制。如果网格轨道尺寸、网格项对齐方式或实际 DOM 结构与预期不符,菜单的可移动范围和观察到的滚动位置也可能不同。仅凭这些信息无法判断各浏览器模拟器偏移不同的具体原因,需要先检查页面结构和滚动容器。
先检查列宽和滚动容器
当前的列定义是:
grid-template-columns: 12em 100%;
这表示左列宽 12em,右列宽为网格容器的 100%,并不是“左侧 12em,剩余空间给右侧”。如果网格容器和视口一样宽,网格总宽度就会超出视口。
也要检查菜单及其祖先元素是否设置了 overflow: auto、scroll 或 hidden。sticky 参考最近的滚动容器。即使祖先只设置了横向溢出,计算后的纵向 overflow 也可能形成滚动容器,改变 sticky 所依据的区域。
让主列留在网格内
如果主内容应占用视口的剩余空间,可以这样设置列:
body {
margin: 0;
display: grid;
grid-template-columns: 12em minmax(0, 1fr);
grid-template-areas: "sidebar page";
}
.menu {
grid-area: sidebar;
position: sticky;
bottom: 0;
align-self: end;
}
.content {
grid-area: page;
min-width: 0;
}
minmax(0, 1fr) 允许主列缩到网格可用宽度,避免 1fr 的最小尺寸被内容的最小宽度撑大。min-width: 0 则允许 .content 这个网格项缩到列宽以内。
如果主内容确实需要比视口宽,可以把宽内容放进 .content 内的子元素,只让该子元素设置宽度或启用横向滚动。不要在同时包含菜单的祖先元素上设置横向 overflow,否则它可能成为菜单的滚动容器。例如:
.content {
min-width: 0;
}
.content-inner {
width: max-content;
min-width: 100%;
}
如果要让内容区域内部滚动,可以把 overflow-x: auto 设在 .content 或更深层的内容容器上,并确认菜单不是它的后代。具体做法取决于页面需要整体横向滚动,还是只让主内容区域横向滚动。
检查 sticky 的适用范围
position: sticky 只能在包含块范围内移动。菜单所在网格区域的高度、align-self: end 设置的初始对齐位置,以及菜单自身的高度,都会影响它能移动多远。如果菜单比视口还高,就无法完整贴合视口底边。这时可以限制菜单高度并让菜单内部滚动,也可以重新设计侧栏的滚动方式。
还要核对实际 HTML。给出的片段里有 <main class"content">,缺少属性赋值符号;列表以 <ol> 开始,却以 </ul> 结束。这些标记需要先修正,否则浏览器解析出的 DOM 可能与预期不同,也会影响复现结果。
可以先用开发者工具检查网格总宽度、.menu 的实际包含块、最近的滚动容器,以及菜单是否高于视口。修正列宽并排除菜单祖先上的意外滚动容器后,再单独调整 bottom 和对齐方式。
备注:内容仅供参考。
