响应式布局:固定宽度居中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 部分。
- Flexbox
justify-content: space-between
order
flex-shrink
、flex-grow
、flex-basis
- Relative units of measurement
- 视口[=52=]
vw
和vh
- 百分比
em
/* 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>
我有一个居中的 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 部分。
- Flexbox
justify-content: space-between
order
flex-shrink
、flex-grow
、flex-basis
- Relative units of measurement
- 视口[=52=]
vw
和vh
- 百分比
em
- 视口[=52=]
/* 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.
但是,如果您需要中间内容在小屏幕上仍然是中间内容,而在大屏幕上是右栏,那就另当别论了。
这可以用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>