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

我是研究僧i 提交于 2019-12-11 12:20:04

问题


I have a centered div with a width of 700px, with a middle part that must become a right column when viewport is > to some width. I used absolute positioning for that purpose but like this column must be responsive, I don't know its width.

First, I would like to know what is the rule for how behave the width of absolute positioned elements which are out of their relative parent. Absolute positioning should use the width of their relative parent but when the element is out of that parent, the element is shrinked. If there is a word without space, it extends the element accordingly and everything follows. I don't understand how it works and how predict that behavior. It's the same when that element without width is supposed to start overflowing out of its parent.

Then, is there a way to make this column fills the right until it reaches the limit of the window without overflowing (with a little margin-right)? If I fix a big width on that column assuming it will be the max-width that column will achieve in the biggest viewport and use the overflow property to hide what is out of the window, of course, the absolute positioned element is just cut. I really don't know how to make that responsive because it seems like absolute positioning removes the element from the flow, it is not made for my purpose. Of course, no JS, please. And it must support Internet Explorer since IE8.
The only solution that comes to my mind is to duplicate the content and use display:none/block to switch blocks with media queries but it means redundant code. I tried with a complicated display:table layout until I found that colspan doesn't exist.
(Just so you know, I have a left column too to take into consideration, the reason why I am using a three columns display:table layout. If that's relevant.)

Here is a simplified code:
I didn't put media queries but the aside-on-small-screen is obviously what it should look like on small screens, replacing the aside selector.

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>

Thank you.


回答1:


Used flexbox and assigned aside a percentage width. The details are in the CSS portion of Snippet.

  • Flexbox
    • justify-content: space-between
    • order
    • flex-shrink, flex-grow, flex-basis
  • Relative units of measurement
    • Viewport width/height vw and vh
    • Percentage
    • 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>



回答2:


There are three problems in one:

First problem.

How to transform a middle content

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

in a right column that expends to the right without overflowing out of the window, when the rest of the past column "wrapper" must be a centered column of fixed width.

<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>

Absolute positioning doesn't help because without fixed sizes (% or px), it is out of the flow and the content of variable width won't adapt to the situation (and overflow).

This can be easily solved with display table.

Second problem.

Display table/table-cell leads to the second problem.
To make three "columns" with display:table-cell, order is really important. That means the "aside" div must be the last element of its column (the wrapper column in my first snippet) in order to make it an independent cell of a row put to the right. If you don't have to worry about this story of middle content and you just have to switch a content at the end of a div to the right or a content at the beginning to the left, it's already over. You just have to style colLeft, wrapper and aside of my second snippet with display:table-cell and use another global wrapper with display:table and some other styles like table-layout:fixed and width:100% to do the trick. With a media queries for small screen, you just have to hide the colLeft with display:none.

But if you need that middle content to be a middle content nonetheless on small screens and a right column on large screens, it's a different case.

This can be solved with anonymous table objects and table-header/footer/row-group.

With table-header/footer/row-group, you can reorganize your rows so you can put the "aside" at the end to transform it in an independent cell on large screens and place it in the middle with table-row-group on small screens:

.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>

Third problem.

The hardest problem is the centered "column" of fixed width. With table-xxx-group, it is forbidden to put a wrapper around the table-header-group and table-footer-group to set a width of 700px because table-group are row elements and the wrapper will automatically becoming a table object, excluding the "aside" that won't be able to insert itself in the middle with its table-row-group style on small screens. Without putting a wrapper around the "stuff", you won't be able to control the width of the created anonymous cell on large screens because you can't style something anonymous. So it takes a width of 1/3 like each cell.

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>

The solution is to use table-column-group/table-column. You will be able to style your columns and set a width to the middle column even though it is determined anonymously.

The solution

Small screens

.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>

Large screens

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>


来源:https://stackoverflow.com/questions/36241802/responsive-layout-middle-content-of-centered-div-with-fixed-width-must-become-t

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!