使元素不在水平方向滚动

huangapple go评论53阅读模式
英文:

Make an element not scroll horizontally

问题

我正在尝试创建一个布局,其中包括:

  • 页眉(代码段中的灰色块)
  • 主体(绿色边框)
  • 主体内容(带有红色边框的块)

如果你水平滚动页面,那么页眉不应滚动,它应该是全宽度并保持可见。如果你垂直滚动页面,那么页眉应该像通常一样滚动离开页面。页眉的高度是动态的,适应其中的内容(这个SO答案 使用固定高度)。

<main> 元素允许比视口更宽,但页眉始终具有视口宽度。
我之所以不在 <main> 元素上添加 max-width: 100%; overflow-x: auto(就像这个SO答案),是因为这样水平滚动条会出现在元素底部,然后如果有人正在阅读第一个块,希望水平滚动,必须滚动到主元素的底部才能看到水平滚动条,然后滚动到侧边,然后再滚回到上面。我希望如果 main 比视口更宽,水平滚动条始终可见。

我尝试在页眉上使用 position: sticky/fixed,但无法使其正常工作。

如果可能的话,我宁愿不使用JavaScript。

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-css -->
header {
  padding: 32px;
  background: gray;
  width: 100%;
}
main {
  border: 2px solid lime;
  min-width: 100%;
}
div {
  height: 200px;
  width: 120%; /* make it overflow horizontally */
  display: flex;
  align-items: center;
  justify-content: center;
  border: 2px solid red;
}

<!-- language: lang-html -->
<header>The Header should not scroll horizontally<br>(is dynamic height)</header>
<main>
  <div>content 1</div>
  <div>content 2</div>
  <div>content 3</div>
  <div>content 4</div>
  <div>content 5</div>
  <div>content 6</div>
</main>

<!-- end snippet -->

希望这对你有所帮助。

英文:

I am trying to make a layout with:

  • A header (gray block in the snippet)
  • A body (lime borrder)
  • Main body content ( blocks with red border)

If you scroll horizontally, then the header should not scroll, it should be full width and stay in view. If you scroll vertically, then the header should scroll off the page as usual. The height of the header is dynamic, and fits the content within it (this SO answer works with a fixed height)..

The &lt;main&gt; element is allowed to be wider than the viewport, but the header is always the viewport width.
The reason I dont add max-width: 100%; overflow-x: auto on the &lt;main&gt; element (like this SO answer, is because then the horizontal scroll appears at the bottom of the element, and then say one is reading the first block, and you wish to scroll horizontally, you have to scroll to the bottom of the main element to see the horizontal scroll bar, scroll to the side, then scroll back up. I wish to have the horizontal scroll bar always present if main is wider than the view port.

I have tried position: sticky/fixed on the header but could not get it to work.

I would prefer not to use JavaScript if possible.

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-css -->

header {
  padding: 32px;
  background: gray;
  width: 100%;
}
main {
  border: 2px solid lime;
  min-width: 100%;
}
div {
  height: 200px;
  width: 120%; /* make it overflow horizontally */
  display: flex;
  align-items: center;
  justify-content: center;
  border: 2px solid red;
}

<!-- language: lang-html -->

&lt;header&gt;The Header should not scroll horizntally&lt;br&gt;(is dynamic height)&lt;/header&gt;
&lt;main&gt;
  &lt;div&gt;content 1&lt;/div&gt;
  &lt;div&gt;content 2&lt;/div&gt;
  &lt;div&gt;content 3&lt;/div&gt;
  &lt;div&gt;content 4&lt;/div&gt;
  &lt;div&gt;content 5&lt;/div&gt;
  &lt;div&gt;content 6&lt;/div&gt;
&lt;/main&gt;

<!-- end snippet -->

答案1

得分: 3

我所做的是将页眉固定在屏幕的左侧。其父元素必须知道内容的大小,以允许页眉移动。因此,我将body的最小宽度设置为min-content,并且对main也采用相同的设置,以便它可以将其子元素的大小传递给body。

您还可能注意到,我在页眉中使用了box-sizing: border-box;,这样在计算元素大小时会考虑到填充大小(在本例中是100vw)。您不希望在页眉宽度上使用百分比,因为它不会有足够的空间来滑动。

此外,div的大小不应该依赖于父元素的大小,因此在这里也不能使用百分比。

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-css -->
body {
  min-width: min-content;
}

header {
  box-sizing: border-box;
  position: sticky;
  left: 0;
  padding: 32px;
  background: gray;
  width: 100vw;
}
main {
  min-width: min-content;
  border: 2px solid lime;
}
div {
  height: 200px;
  width: 120vw; /* make it overflow horizontally */
  display: flex;
  align-items: center;
  justify-content: center;
  border: 2px solid red;
}

<!-- language: lang-html -->
<body>

<header>The Header should not scroll horizntally<br>(is dynamic height)</header>
<main>
  <div>content 1</div>
  <div>content 2</div>
  <div>content 3</div>
  <div>content 4</div>
  <div>content 5</div>
  <div>content 6</div>
</main>
</body>

<!-- end snippet -->
英文:

What I have done here is make header sticky to the left part of the screen. Its parent element must be aware of size of your content to allow header to move. So I set body min-width to min-content and same with main so it can transfer its children's size to body.

You also may notice I used box-sizing: border-box; in the header, its so padding size is taken into account when element size is calculated(100vw in this case). You don´t want to use % on header width because it won´t have room to slide.

Also div sizes must not be dependent on parent size, so you can´t use % here either.

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-css -->

body{
  min-width: min-content;
}

header {
  box-sizing: border-box;
  position: sticky;
  left: 0;
  padding: 32px;
  background: gray;
  width: 100vw;
}
main {
  min-width: min-content;
  border: 2px solid lime;
}
div {
  height: 200px;
  width: 120vw; /* make it overflow horizontally */
  display: flex;
  align-items: center;
  justify-content: center;
  border: 2px solid red;
}

<!-- language: lang-html -->

&lt;body&gt;

&lt;header&gt;The Header should not scroll horizntally&lt;br&gt;(is dynamic height)&lt;/header&gt;
&lt;main&gt;
  &lt;div&gt;content 1&lt;/div&gt;
  &lt;div&gt;content 2&lt;/div&gt;
  &lt;div&gt;content 3&lt;/div&gt;
  &lt;div&gt;content 4&lt;/div&gt;
  &lt;div&gt;content 5&lt;/div&gt;
  &lt;div&gt;content 6&lt;/div&gt;
&lt;/main&gt;
&lt;/body&gt;

<!-- end snippet -->

答案2

得分: 0

Edit: @Max Tuzenko的回答更好,因为它不需要额外的标记。我们采取了相同的方法,但我甚至没有考虑简单地不勾选“top”。我将保留我的答案,因为它解释了一些事情。


如果您愿意将您的页眉内容包装在另一个元素中,您可以使用position: sticky来使其正常工作。还有一个注意事项,您不能像在演示中那样强制百分比溢出。但我猜那只是为了举例说明?

思路是将页眉扩展到您最宽的内容元素的宽度,并且内部包装器只沿x轴粘附,并且还限制其宽度为视口宽度(100vw)。

为此,我们首先需要告诉body扩展到视口的宽度之外,这默认情况下不会发生。请参阅此问题及其答案,了解原因。我们选择使用min-width: min-content

我不太确定为什么强制百分比溢出不会触发<main>超出视口限制,但我猜这与百分比相对于包含元素有关。

无论如何,请参见以下代码片段,以获取一个可工作示例。由于添加了边框,会发生一些“颠簸”。

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-css -->
html { box-sizing: border-box; }
*, *::before, *::after { box-sizing: inherit; }

body {
  margin: 0;
  min-width: min-content; /* 让body扩展到视口之外。 */
  padding: 0;
}

header {
  border: 2px solid blue;
}

header div {
  background: gray;
  left: 0;
  max-width: 100vw; /* 限制宽度为视口宽度。 */
  padding: 32px;
  position: sticky;
  top: 0;
}

main {
  border: 2px solid lime;
}

main div {
  align-items: center;
  border: 2px solid red;
  display: flex;
  height: 200px;
  justify-content: center;
  width: 120vw; /* 水平溢出,无法使用百分比。 */
}

<!-- language: lang-html -->
<header>
  <div>
      页眉不应水平滚动<br>(动态高度)<br>更多内容
  </div>
</header>
<main>
  <div>内容 1</div>
  <div>内容 2</div>
  <div>内容 3</div>
  <div>内容 4</div>
  <div>内容 5</div>
  <div>内容 6</div>
</main>

<!-- end snippet -->
[1]: https://stackoverflow.com/q/55595647/151509
英文:

Edit: @Max Tuzenko's answer is better as it doesn't need additional markup. We went the same route but I didn't even think of simply leaving top unchecked. I'll leave my answer up as it explains some things.


You can get this to work with position: sticky if you're willing to wrap your header content in another element. And there's a caveat in that you can't force the overflow in percentages as you do in your demo. But I guess that was just for exemplary purposes?

The idea is to extend your header to whatever width your widest content elements are and have the inside wrapper only stick along the x-axis and also limit its width to the viewport width (100vw).

For that we first need to tell body to extend beyond the width of the viewport, which it doesn't do by default. See this question and its answer as to why. We're going with min-width: min-content.

I'm not really sure why forcing the overflow in percentages doesn't trigger &lt;main&gt; to grow beyond the viewport limits but I guess it's something to do that percentages are relative to the containing element.

Anyways, see the following code snippet for a working example. Some "bumping" occurs due to the borders added.

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-css -->

html { box-sizing: border-box; }
*, *::before, *::after { box-sizing: inherit; }

body {
  margin: 0;
  min-width: min-content; /* Have body extend past viewport. */
  padding: 0;
}

header {
  border: 2px solid blue;
}

header div {
  background: gray;
  left: 0;
  max-width: 100vw; /* Restricting width to viewport width. */
  padding: 32px;
  position: sticky;
  top: 0;
}

main {
  border: 2px solid lime;
}

main div {
  align-items: center;
  border: 2px solid red;
  display: flex;
  height: 200px;
  justify-content: center;
  width: 120vw; /* Horizontal overflow, can&#39;t use pecentages. */
}

<!-- language: lang-html -->

&lt;header&gt;
  &lt;div&gt;
      The Header should not scroll horizntally&lt;br&gt;(is dynamic height)&lt;br&gt;more lines
  &lt;/div&gt;
&lt;/header&gt;
&lt;main&gt;
  &lt;div&gt;content 1&lt;/div&gt;
  &lt;div&gt;content 2&lt;/div&gt;
  &lt;div&gt;content 3&lt;/div&gt;
  &lt;div&gt;content 4&lt;/div&gt;
  &lt;div&gt;content 5&lt;/div&gt;
  &lt;div&gt;content 6&lt;/div&gt;
&lt;/main&gt;

<!-- end snippet -->

huangapple
  • 本文由 发表于 2023年6月1日 17:41:06
  • 转载请务必保留本文链接:https://go.coder-hub.com/76380577.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定