响应式布局:固定宽度居中div的中间内容必须成为右栏不溢出

Responsive layout: middle content of centered div with fixed width must become the right column without overflowing

我有一个居中的 div,宽度为 700px,middle 部分必须在视口大于某个宽度时成为右列。我为此目的使用了绝对定位,但像此列一样必须响应,我不知道它的宽度。

首先,我想知道在其相对父项之外的绝对定位元素的宽度行为规则是什么。绝对定位应使用其相对父级的宽度,但当元素超出该父级时,该元素将缩小。如果有一个单词没有 space,它会相应地扩展该元素,然后一切都将随之而来。我不明白它是如何工作的以及如何预测这种行为。当没有宽度的元素应该开始溢出其父元素时也是如此。

那有没有什么办法可以让这一列向右填充到window的极限而不溢出(有一点margin-right)?如果我在该列上固定一个大宽度,假设它将是该列将在最大视口中达到的最大宽度,并使用溢出 属性 来隐藏 window 之外的内容,当然,绝对定位元素刚刚被切割。 我真的不知道如何做出响应,因为看起来绝对定位从流程中删除了元素,它不是为我的目的而设计的。当然,请不要 JS。并且必须支持IE8以上的Internet Explorer。
我想到的唯一解决方案是复制内容并使用 display:none/block 来切换带有媒体查询的块,但这意味着冗余代码。我尝试了一个复杂的 display:table 布局,直到我发现 colspan 不存在。
(正如你所知,我还有一个左栏要考虑,这就是我使用三栏 display:table 布局的原因。如果相关的话。)

这是一个简化的代码:
我没有放置媒体查询,但 aside-on-small-screen 显然是它在小屏幕上的样子,取代了 aside 选择器。

main{
  overflow:hidden;
}
.colMain{
  background-color:green;
  margin-left:auto;
  margin-right:auto;
  position:relative;
  width:300px;
}
.aside{
  background-color:red;
  position:absolute;
  top:0px;
  left:320px;
}
.aside-on-small-screen{
  background-color:red;
}
<main>
  <div class="colMain">
    <div>stuff</div>
    <div class="aside">aside that must extend all the way to the right until it reaches the window limit</div>
    <div>stuff</div>
  </div>
</main>

谢谢。

使用 flexbox 并分配一个百分比宽度。详细信息位于代码段的 CSS 部分。

/* Optional Defaults and Resets */

* {
  -ms-box-sizing: border-box;
  box-sizing: border-box;
}
html {
  font: 400 10px/1 Arial;
  width: 100%;
  height: 100%;
}
/*,
*:before,
*:after {
  box-sizing: inherit;
  margin: 0;
  padding: 0;
  border: none;
}*/

body {
  font: inherit;
  font-size: 160%;
  /* background: rgba(0, 0, 0, .2);*/
  line-height: 1;
  overflow: visible;
  width: 100%;
  height: 100%;
}
/* Demo Styles */

/* All outlines and backgrounds are for presentational purposes */

/* vw/vh viewport width/height 1vw/vh = 1% of viewport width/height */

main {
  overflow: hidden;
  /* width: 100vw;
  height: 100vh;
  background: rgba(0, 0, 255, .2);*/
  width: 100%;
  height: 100%;
  min-height: 35em;
  display: table;
}
/* Flexbox layout will automatically keep .aside to the right with the */

/* property justify-content: space-between; which keeps the max amount */

/* of even space between flex-items (which is .stuff and .aside) */

.colMain {
  /* display: flex;
  flex-direction: row;
  flex-wrap: nowrap;
  justify-content: space-between; */
  background-color: green;
  margin-left: auto;
  margin-right: auto;
  position: relative;
  min-width: 99%;
  min-height: 99%;
  padding: 1em;
  display: table-row;
  width: 700px;
}
/* Removed absolute positioning in favor of flexbox and a percentage */

/* width. .aside will start dis-proportionally expanding while the viewport */

/* expands. The two columns on the right while begin to shrink in response */

/* to.aside's expansion. All this stretching and shrinking happens when the */

/* elements are at 210px or more (210 is 30% of 700px). This behavior is */

/* accomplished by using flex-shrink, flex-grow, and flex-basis */

.aside {
  display: table-cell;
  background-color: red;
  position: absolute;
  top: 1em;
  right: 0;
  left: 70%;
  /* order: 3; */
  min-width: 30%;
  max-width: 500px;
  min-height: 100%;
  /* flex-grow: 1;
  flex-basis: 210px;*/
  outline: 2px solid #7c1b38;
  padding: 5px;
}
.aside-on-small-screen {
  background-color: red;
}
.stuff {
  outline: 2px dotted white;
  width: 30%;
  max-width: 210px;
  min-height: 100%;
  position: absolute;
  /* flex-shrink: 1;
  flex-basis: 210px; */
  display: table-cell;
}
#col1 {
  left: 1em;
  top: 1em;
}
#col2 {
  left: 36%;
  top: 1em;
}
/*.stuff:first-of-type {
  order: 1;
}
.stuff:last-of-type {
  order: 2; */

}
/* The HTML shows that the second column (the second .stuff) would be */

/* in-between .aside and the edge of .colMain. Instead of moving it out of */

/* the way in markup (HTML), I used the flexbox property, order. */
<main>
  <div class="colMain">
    <div id="col1" class="stuff">stuff</div>

    <div class="aside">aside that must extend all the way to the right until it reaches the window limit</div>

    <div id="col2" class="stuff">stuff</div>
  </div>
</main>

三个问题合二为一:

第一个问题。

如何转换中间内容

<div class="wrapper">
    <div>stuff</div>
    <div class="aside">Middle content</div>
    <div>stuff</div>
</div>

在向右扩展而不会溢出 window 的右侧列中,当过去列的其余部分 "wrapper" 必须是固定宽度的居中列时。

<div class="colLeft"></div>
<div class="wrapper" style="text-align:center; width:700px;">
    <div>stuff</div>
    <div>stuff</div>
</div>
<div class="aside">Middle content now to the right</div>

绝对定位没有帮助,因为没有固定大小(% 或 px),它会超出流程,可变宽度的内容将无法适应这种情况(并溢出)。

这可以通过显示table轻松解决。

第二个问题。

显示table/table-cell导致第二个问题
要用 display:table 单元格制作三个 "columns",顺序非常重要。这意味着 "aside" div 必须是其列的最后一个元素(我的第一个片段中的包装列),以便使其成为右侧一行的独立单元格。如果你不用担心这个中间内容的故事,只需要将div末尾的内容向右切换或将开头的内容向左切换,就已经结束了。 您只需要使用 display:table-cell 对 colLeft、wrapper 和 aside of my second snippet 进行样式设置,并使用带有 display:table 的另一个全局包装器和一些其他样式,例如 table-layout:fixed 和 width:100% 来解决这个问题。对于小屏幕的媒体查询,您只需使用 display:none.

隐藏 colLeft

但是,如果您需要中间内容在小屏幕上仍然是中间内容,而在大屏幕上是右栏,那就另当别论了。

这可以用anonymous table objects和table-header/footer/row-group来解决。

使用table-header/footer/row-group,你可以重新组织你的行,这样你就可以把"aside"放在最后,在大屏幕上将它转换成一个独立的单元格,然后用[=104把它放在中间=]-小屏幕上的行组:

.header{
  background-color:green;
  display:table-header-group;
}
.footer{
  background-color:green;
  display:table-footer-group;
}
.aside{
  background-color:red;
  display:table-row-group;
}
<div class="header">stuff</div>
<div class="footer">stuff</div>
<div class="aside">Middle content</div>

第三个问题。

最难的问题是定宽居中"column"。使用 table-xxx-group,禁止在 table-header-group 和 table-footer-group 周围放置 wrapper 以设置 700px 的宽度,因为 table-group 是行元素,包装器将自动成为一个 table 对象,不包括 "aside" 无法将其自身插入中间的 table-row-group小屏幕上的样式。 如果不在 "stuff" 周围放置一个包装器,您将无法在大屏幕上控制创建的匿名单元格的宽度,因为您无法设置匿名内容的样式。所以它像每个单元格一样需要1/3的宽度。

main{
  display:table;
  table-layout: fixed;
  width:100%;
}
.colLeft{
  background-color:yellow;
  display:table-cell;
}
.header,.footer{
  background-color:green;
  /*no display style > it will create an anonymous cell
  object around the header/footer elements*/
}
.aside{
  background-color:red;
  display:table-cell;
}
<main>
  <div class="colLeft"></div>
  <div class="header">stuff</div>
  <div class="footer">stuff</div>
  <div class="aside">Middle content now to the right</div>
</main>

解决方法是使用table-column-group/table-column。您将能够设置列的样式并设置中间列的宽度,即使它是匿名确定的。

解决方案

小屏幕

.rowTabled{
  display:table;
  table-layout: fixed;
  width:100%;
}
.header{
  background-color:green;
  display:table-header-group;
}
.footer{
  background-color:green;
  display:table-footer-group;
}
.aside{
  background-color:red;
  display:table-row-group;
}
.colLeft, .colgroup{
  display:none;
}
<main>
  <div class="colgroup">
    <div class="colCol left"></div>
    <div class="colCol middle"></div>
    <div class="colCol right"></div>
  </div>
  <div class="rowTabled">
    <div class="colLeft"></div>
    <div class="header">stuff</div>
    <div class="footer">stuff</div>
    <div class="aside">asideeeeeeeeeeeex eeeeee eeeeeeeee eeeeeeeeeeeeee</div>
  </div>
</main>

大屏幕

main{
  display:table;
  table-layout: fixed;
  width:100%;
}
.colgroup{
  display:table-column-group;
}
.colCol{
  display:table-column;
}
.middle{
  background-color:green;
  width:100px;
}
.left,.right{
  background-color:yellow;
}
.rowTabled{
  display:table-row;
}
.colLeft{
  display:table-cell;
}
.aside{
  background-color:red;
  display:table-cell;
}
<main>
  <div class="colgroup">
    <div class="colCol left"></div>
    <div class="colCol middle"></div>
    <div class="colCol right"></div>
  </div>
  <div class="rowTabled">
    <div class="colLeft"></div>
    <div class="header">stuff</div>
    <div class="footer">stuff</div>
    <div class="aside">asideeeeeeeeeeeex eeeeee eeeeeeeee eeeeeeeeeeeeee</div>
  </div>
</main>