Desplazar una caja flexible con contenido desbordado

214

ingrese la descripción de la imagen aquí

Aquí está el código que estoy usando para lograr el diseño anterior:

.header {
  height: 50px;
}

.body {
  position: absolute;
  top: 50px;
  right: 0;
  bottom: 0;
  left: 0;
  display: flex;
}

.sidebar {
  width: 140px;
}

.main {
  flex: 1;
  display: flex;
  flex-direction: column;
}

.content {
  flex: 1;
  display: flex;
}

.column {
  padding: 20px;
  border-right: 1px solid #999;
}
<div class="header">Main header</div>
<div class="body">
  <div class="sidebar">Sidebar</div>

  <div class="main">
    <div class="page-header">Page Header. Content columns are below.</div>
    <div class="content">
      <div class="column">Column 1</div>
      <div class="column">Column 1</div>
      <div class="column">Column 1</div>
    </div>
  </div>
</div>

Omití el código utilizado para el estilo. Puedes verlo todo en la pluma .


Lo anterior funciona, pero cuando el contentcontenido del área se desborda, hace que toda la página se desplace. Solo quiero que el área de contenido se desplace, así que agregué overflow: autoal contentdiv .

El problema con esto ahora es que las columnas en sí no se extienden más allá de la altura de sus padres, por lo que los bordes también se cortan allí.

Aquí está la pluma que muestra el problema de desplazamiento .

¿Cómo puedo configurar el contentárea para que se desplace de forma independiente, mientras que sus hijos se extiendan más allá contentde la altura de la caja?

Joseph Silber
fuente

Respuestas:

264

He hablado con Tab Atkins (autor de la especificación flexbox) sobre esto, y esto es lo que se nos ocurrió:

HTML:

<div class="content">
    <div class="box">
        <div class="column">Column 1</div>
        <div class="column">Column 2</div>
        <div class="column">Column 3</div>
    </div>
</div>

CSS:

.content {
    flex: 1;
    display: flex;
    overflow: auto;
}

.box {
    display: flex;
    min-height: min-content; /* needs vendor prefixes */
}

Aquí están los bolígrafos:

  1. Columnas cortas se estiran .
  2. Las columnas más largas se desbordan y se desplazan .

La razón por la que esto funciona es porque align-items: stretchno reduce sus elementos si tienen una altura intrínseca, lo cual se logra aquí min-content.

Joseph Silber
fuente
3
Funcionan cuando la altura de los padres no depende de sus hijos, en general, que es el caso aquí. min-height: 100% realmente soluciona su problema de estiramiento incluso cuando las columnas son cortas en Firefox (aunque no en Chrome). No estoy seguro de antemano si eso es un error de Chrome o un error de Firefox.
dholbert
1
@dholbert - Tab Atkins me ayudó con esto. He actualizado mi respuesta.
Joseph Silber
3
Tenga en cuenta que Firefox actualmente solo admite "contenido mínimo" para valores de ancho, no valores de altura, por lo que esto no funcionará en Firefox, si eso es importante para usted. (Véase por ejemplo bugzilla.mozilla.org/show_bug.cgi?id=852367 )
dholbert
2
@dholbert - El problema con estos bolígrafos es que eran públicos, por lo que cualquiera podría cambiarlos. Tomé posesión de ellos, así que aquí tienes: codepen.io/JosephSilber/pen/pmyHh
Joseph Silber
55
Sí, esto está roto en IE11
Steve
119

Acabo de resolver este problema con mucha elegancia después de muchas pruebas y errores.

Echa un vistazo a mi publicación de blog: http://geon.github.io/programming/2016/02/24/flexbox-full-page-web-app-layout

Básicamente, para hacer que una celda flexbox se pueda desplazar, debe hacer que todos sus padres overflow: hidden; , o simplemente ignorará su configuración de desbordamiento y hará que el padre sea más grande.

geon
fuente
11
Esto funcionó en mi caso también, pero wow, realmente me gustaría ver una explicación de por qué funciona. La mayoría de las veces, encuentro que las especificaciones CSS son totalmente inescrutables para este tipo de cosas.
markrian
2
De tu publicación de blog: "No tengo idea de por qué eso funciona, y las especificaciones tampoco dicen nada" . Entonces, estoy buscando una explicación de por qué funciona. He leído las especificaciones, pero como dijiste, nada salta por ahí.
markrian
3
Después de pensarlo un poco más, creo que tiene sentido. El comportamiento predeterminado es que cada div se expanda para contener todos sus elementos secundarios, por lo que no habrá ningún desbordamiento que ocultar en los nodos hoja. Debe forzar el desbordamiento: oculto desde la parte superior del DOM, por lo que ningún padre tiene la oportunidad de acomodar a sus hijos hasta que llegue al nodo que desea desbordar y desplazarse.
Geon
3
No estoy seguro de que eso realmente lo explique. Establecer el desbordamiento como oculto en un elemento no evita que se expanda para contener a todos sus elementos secundarios, AFAIK. De acuerdo con MDN: "La propiedad de desbordamiento especifica si se debe recortar el contenido, representar barras de desplazamiento o simplemente mostrar contenido cuando desborda su contenedor de nivel de bloque". Además, establecer el desbordamiento en algo que no sea visible crea un nuevo contexto de formato de bloque, pero eso no puede ser relevante, porque los contenedores flexibles ya crean su propio contexto de formato de bloque: developer.mozilla.org/en-US/docs/Web/Guide / CSS / ... .
markrian
1
Debo agregar que estoy de acuerdo en que su explicación tiene un sentido intuitivo , pero no creo que sea una explicación técnica precisa , que es lo que quiero. ¡Solo al comprender verdaderamente la razón podré recordar la solución en el futuro!
markrian
55

Trabajando position:absolute;junto con flex:

Coloque el elemento flexible con position: relative. Luego, dentro de él, agregue otro <div>elemento con:

position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;

Esto extiende el elemento a los límites de su padre en posición relativa, pero no permite extenderlo. En el interior, overflow: auto;funcionará como se esperaba.

  • el fragmento de código incluido en la respuesta: haga clic en ingrese la descripción de la imagen aquíy luego haga clic en Página completadespués de ejecutar el fragmento O
  • Haga clic aquí para el CODEPEN
  • El resultado: ingrese la descripción de la imagen aquí

.all-0 {
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
}
p {
  text-align: justify;
}
.bottom-0 {
  bottom: 0;
}
.overflow-auto {
  overflow: auto;
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.2/css/bootstrap.min.css" rel="stylesheet"/>


<div class="p-5 w-100">
  <div class="row bg-dark m-0">
    <div class="col-sm-9 p-0 d-flex flex-wrap">
      <!-- LEFT-SIDE - ROW-1 -->
      <div class="row m-0 p-0">
        <!-- CARD 1 -->
        <div class="col-md-8 p-0 d-flex">
          <div class="my-card-content bg-white p-2 m-2 d-flex flex-column">
            <img class="img img-fluid" src="https://via.placeholder.com/700x250">
            <h4>Heading 1</h4>
            <p>
              Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old...
          </div>
        </div>
        <!-- CARD 2 -->
        <div class="col-md-4 p-0 d-flex">
          <div class="my-card-content bg-white p-2 m-2 d-flex flex-column">
            <img class="img img-fluid" src="https://via.placeholder.com/400x250">
            <h4>Heading 1</h4>
            <p>
              Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old...
          </div>
        </div>
      </div>
      <div class="row m-0">
        <!-- CARD 3 -->
        <div class="col-md-4 p-0 d-flex">
          <div class="my-card-content bg-white p-2 m-2 d-flex flex-column">
            <img class="img img-fluid" src="https://via.placeholder.com/400x250">
            <h4>Heading 1</h4>
            <p>
              Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old...
          </div>
        </div>
        <!-- CARD 4 -->
        <div class="col-md-4 p-0 d-flex">
          <div class="my-card-content bg-white p-2 m-2 d-flex flex-column">
            <img class="img img-fluid" src="https://via.placeholder.com/400x250">
            <h4>Heading 1</h4>
            <p>
              Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old...
          </div>
        </div>
        <!-- CARD 5-->
        <div class="col-md-4 p-0 d-flex">
          <div class="my-card-content bg-white p-2 m-2 d-flex flex-column">
            <img class="img img-fluid" src="https://via.placeholder.com/400x250">
            <h4>Heading 1</h4>
            <p>
              Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old...
          </div>
        </div>
      </div>
    </div>
    <div class="col-sm-3 p-0">
      <div class="bg-white m-2 p-2 position-absolute all-0 d-flex flex-column">
        <h4>Social Sidebar...</h4>
        <hr />
        <div class="d-flex overflow-auto">
          <p>
            Topping candy tiramisu soufflé fruitcake ice cream chocolate bar. Bear claw ice cream chocolate bar donut sweet tart. Pudding cupcake danish apple pie apple pie. Halva fruitcake ice cream chocolate bar. Bear claw ice cream chocolate bar donut sweet tart.
            opping candy tiramisu soufflé fruitcake ice cream chocolate bar. Bear claw ice cream chocolate bar donut sweet tart. Pudding cupcake danish apple pie apple pie. Halva fruitcake ice cream chocolate bar. Bear claw ice cream chocolate bar donut sweet tart.
            opping candy tiramisu soufflé fruitcake ice cream chocolate bar. Bear claw ice cream chocolate bar donut sweet tart. Pudding cupcake danish apple pie apple pie. Halva fruitcake ice cream chocolate bar. Bear claw ice cream chocolate bar donut sweet tart.
            Pudding cupcake danish apple pie apple pie. Halvafruitcake ice cream chocolate bar. Bear claw ice cream chocolate bar donut sweet tart. Pudding cupcake danish apple pie apple pie. Halvafruitcake ice cream chocolate bar. Bear claw ice cream
            chocolate bar donut sweet tart. Pudding cupcake danish apple pie apple pie. Halvafruitcake ice cream chocolate bar. Bear claw ice cream chocolate bar donut sweet tart. Pudding cupcake danish apple pie apple pie. Halvafruitcake ice cream chocolate
            bar. Bear claw ice cream chocolate bar donut sweet tart. Pudding cupcake danish apple pie apple pie. Halva
        </div>
      </div>
    </div>
  </div>

Buena suerte...

Akash
fuente
2
Esta solución es especialmente útil si el componente en el interior tiene un relleno acolchado porque lo bloqueará muy bien en su posición donde lo desee. Es mucho mas simple. (Sí, puede configurarlo, box-sizing: border-boxpero eso puede ser más complejo para ciertos controles de terceros).
Simon_Weaver
2
me salvaste la noche!
Botea Florin
2
Gracias. De alguna manera estoy decepcionado de que esto sea necesario, ¡pero estoy agradecido por el consejo!
Mathias
9

Un poco tarde, pero esto podría ayudar: http://webdesign.tutsplus.com/tutorials/how-to-make-responsive-scrollable-panels-with-flexbox--cms-23269

Básicamente hay que poner html, bodya height: 100%; y envolver todo su contenido en una<div class="wrap"> <!-- content --> </div>

CSS:

html, body {
  height: 100%;
}

.wrap {
  height: 100vh;
  display: flex;
}

Trabajó para mi. Espero eso ayude

Doua Beri
fuente
Debe tener mucho cuidado al usar "height: 100vh", ya que mide de manera diferente en iOS Safari vs Android. Uno tiene en cuenta la altura de la barra de URL y el otro no.
Sean Anderson
7

Agrega esto:

align-items: flex-start;

a la regla para .content {} . Eso lo arregla en tu pluma para mí, al menos (tanto en Firefox como en Chrome).

Por defecto, .contenthas align-items: stretch, lo que hace que dimensione todos sus hijos de altura automática para que coincidan con su propia altura, según http://dev.w3.org/csswg/css-flexbox/#algo-stretch . Por el contrario, el valor flex-startpermite a los niños calcular sus propias alturas y alinearse en su borde inicial (y desbordarse, y activar una barra de desplazamiento).

dholbert
fuente
Además, las columnas ya no tendrán la misma altura, que es una de las principales atracciones de flexbox.
Joseph Silber
OKAY. No estaba claro para mí que eso fuera una restricción de diseño, lo siento.
dholbert
Gran sugerencia
Vlad
1

Un problema que he encontrado es que para tener una barra de desplazamiento, un elemento necesita una altura que se especifique (y no como un%).

El truco consiste en anidar otro conjunto de divisiones dentro de cada columna y configurar la pantalla del padre de la columna para que se flexione con la dirección de flexión: columna.

    html, body {
        height: 100%;
        margin: 0;
        padding: 0;
    }

    body {
        overflow-y: hidden;
        overflow-x: hidden;
        color: white;
    }

    .base-container {
        display: flex;
        flex: 1;
        flex-direction: column;
        width: 100%;
        height: 100%;
        overflow-y: hidden;
        align-items: stretch;
    }

    .title {
        flex: 0 0 50px;
        color: black;
    }

    .container {
        flex: 1 1 auto;
        display: flex;
        flex-direction: column;
    }

        .container .header {
            flex: 0 0 50px;
            background-color: red;
        }

        .container .body {
            flex: 1 1 auto;
            display: flex;
            flex-direction: row;
        }

            .container .body .left {
                display: flex;
                flex-direction: column;
                flex: 0 0 80px;
                background-color: blue;
            }
                .container .body .left .content,
                .container .body .main .content,
                .container .body .right .content {
                    flex: 1 1 auto;
                    overflow-y: auto;
                    height: 100px;
                }
                .container .body .main .content.noscrollbar {
                    overflow-y: hidden;
                }

            .container .body .main {
                display: flex;
                flex-direction: column;
                flex: 1 1 auto;
                background-color: green;
            }

            .container .body .right {
                display: flex;
                flex-direction: column;
                flex: 0 0 300px;
                background-color: yellow;
                color: black;
            }

    .test {
        margin: 5px 5px;
        border: 1px solid white;
        height: calc(100% - 10px);
    }
</style>

Y aquí está el html:

<div class="base-container">
    <div class="title">
        Title
    </div>
    <div class="container">
        <div class="header">
            Header
        </div>
        <div class="body">
            <div class="left">
                <div class="content">
                    <ul>
                        <li>1</li>
                        <li>2</li>
                        <li>3</li>
                        <li>4</li>
                        <li>5</li>
                        <li>6</li>
                        <li>7</li>
                        <li>8</li>
                        <li>9</li>
                        <li>10</li>
                        <li>12</li>
                        <li>13</li>
                        <li>14</li>
                        <li>15</li>
                        <li>16</li>
                        <li>17</li>
                        <li>18</li>
                        <li>19</li>
                        <li>20</li>
                        <li>21</li>
                        <li>22</li>
                        <li>23</li>
                        <li>24</li>
                    </ul>
                </div>
            </div>
            <div class="main">
                <div class="content noscrollbar">
                    <div class="test">Test</div>
                </div>
            </div>
            <div class="right">
                <div class="content">
                    <div>Right</div>
                    <div>Right</div>
                    <div>Right</div>
                    <div>Right</div>
                    <div>Right</div>
                    <div>Right</div>
                    <div>Right</div>
                    <div>Right</div>
                    <div>Right</div>
                    <div>Right</div>
                    <div>Right</div>
                    <div>Right</div>
                    <div>Right</div>
                    <div>Right</div>
                    <div>Right</div>
                    <div>Right</div>
                    <div>Right</div>
                    <div>Right</div>
                    <div>Right</div>
                    <div>Right</div>
                    <div>Right</div>
                    <div>Right</div>
                    <div>Right</div>
                    <div>Right</div>
                    <div>Right</div>
                    <div>Right</div>
                    <div>Right</div>
                    <div>Right</div>
                    <div>Right</div>
                    <div>Right</div>
                    <div>Right</div>
                    <div>Right</div>
                    <div>Right</div>
                    <div>Right</div>
                    <div>Right</div>
                    <div>Right</div>
                    <div>Right</div>
                    <div>Right</div>
                    <div>Right</div>
                    <div>Right</div>
                    <div>Right</div>
                    <div>Right</div>
                    <div>Right</div>
                    <div>Right</div>
                    <div>Right</div>
                    <div>Right</div>
                    <div>Right</div>
                    <div>Right</div>
                    <div>Right</div>
                    <div>Right</div>
                    <div>Right</div>
                    <div>Right</div>
                    <div>Right</div>
                    <div>Right</div>
                    <div>End</div>
                </div>
            </div>
        </div>
    </div>
</div>

https://jsfiddle.net/LiamFlavelle/czpjdfr4/

Liam
fuente
0

La solución para este problema es simplemente agregar overflow: auto;al contenido para hacer que el contenedor de contenido se pueda desplazar.

Además, hay circunstancias que ocurren junto con el contenedor Flexbox y el overflowedcontenido desplazable como este codepen .

La solución es agregar overflow: hidden (or auto);al padre del contenedor (configurado con overflow: auto;) alrededor de contenidos grandes.

Dognose
fuente