Rolagem de uma caixa flexível com conteúdo excedente

214

insira a descrição da imagem aqui

Aqui está o código que estou usando para obter o layout acima:

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

Omiti o código usado para estilizar. Você pode ver tudo isso na caneta .


O procedimento acima funciona, mas quando o contentconteúdo da área excede, faz a página inteira rolar. Eu só quero que a própria área de conteúdo role, então adicionei overflow: autoà contentdiv .

O problema com isso agora é que as próprias colunas não se estendem além da altura dos pais, portanto as bordas são cortadas também.

Aqui está a caneta mostrando o problema da rolagem .

Como definir a contentárea para rolar de forma independente, enquanto seus filhos ainda estão além contentda altura da caixa?

Joseph Silber
fonte

Respostas:

263

Falei com Tab Atkins (autor da especificação do flexbox) sobre isso, e é isso que criamos:

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 */
}

Aqui estão as canetas:

  1. Colunas curtas sendo esticadas .
  2. Colunas mais longas transbordando e rolando .

A razão pela qual isso funciona é porque align-items: stretchnão encolhe seus itens se eles tiverem uma altura intrínseca, o que é realizado aqui por min-content.

Joseph Silber
fonte
3
Eles funcionam quando a altura dos pais não depende dos filhos, geralmente, o que é o caso aqui. min-height: 100% realmente corrige o problema de esticar até quando as colunas são curtas no Firefox (embora não no Chrome). Não tenho certeza se é um bug do Chrome ou do Firefox.
precisa saber é o seguinte
1
@dholbert - Tab Atkins me ajudou com isso. Eu atualizei minha resposta.
Joseph Silber
3
Observe que o Firefox atualmente suporta apenas "conteúdo mínimo" para valores de largura e não de altura - portanto, isso não funcionará no Firefox, se isso for importante para você. (Veja, por exemplo, bugzilla.mozilla.org/show_bug.cgi?id=852367 )
dholbert
2
@ dholbert - O problema com essas canetas é que elas eram públicas, para que qualquer pessoa pudesse mudá-las. I tomou posse deles, então aqui vai: codepen.io/JosephSilber/pen/pmyHh
Joseph Silber
5
Sim, isso está quebrado no IE11
Steve
119

Acabei de resolver esse problema de maneira muito elegante depois de muitas tentativas e erros.

Confira minha postagem no blog: http://geon.github.io/programming/2016/02/24/flexbox-full-page-web-app-layout

Basicamente, para tornar uma célula flexbox rolável, você precisa tornar todos os seus pais overflow: hidden; , ou apenas ignorará suas configurações de estouro e aumentará o pai.

geon
fonte
11
Isso funcionou no meu caso também, mas uau, eu realmente gostaria de ver uma explicação do por que funciona. Na maioria das vezes, acho que as especificações CSS são totalmente inescrutáveis ​​para esse tipo de coisa.
markrian
2
No seu post no blog: "Eu não tenho idéia do por que isso funciona, e as especificações também não dizem nada" . Então, eu estou procurando uma explicação de por que funciona. Eu dei uma olhada nas especificações, mas como você disse, nada salta por aí.
markrian
3
Depois de pensar um pouco mais, acho que faz sentido. O comportamento padrão é que cada div se expanda para conter todos os seus filhos, portanto, não haverá nenhum estouro para ocultar nos nós das folhas. Você precisa forçar o estouro: oculto desde o topo do DOM, para que nenhum pai tenha a chance de acomodar seus filhos até que você esteja no nó que deseja transbordar e rolar.
11136
3
Não sei se isso realmente explica isso. Definir o estouro como oculto em um elemento não impede que ele se expanda para conter todos os seus filhos, o AFAIK. De acordo com o MDN: "A propriedade overflow especifica se é necessário recortar conteúdo, renderizar barras de rolagem ou apenas exibir conteúdo quando ele excede o contêiner no nível do bloco". Além disso, definir o estouro para algo diferente de visível cria um novo contexto de formatação de bloco - mas isso não pode ser relevante, porque os contêineres flex já criam seu próprio contexto de formatação de bloco: developer.mozilla.org/en-US/docs/Web/Guide / CSS /… .
markrian
1
Devo acrescentar que concordo que sua explicação faz sentido intuitivamente , mas não acho que seja uma explicação técnica precisa , que é o que eu quero. Somente entendendo verdadeiramente o motivo, poderei lembrar a solução no futuro!
markrian
55

Trabalhando position:absolute;junto com flex:

Posicione o item flexível com position: relative. Em seguida, dentro dele, adicione outro <div>elemento com:

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

Isso estende o elemento até os limites de seu pai em posição relativa, mas não permite estendê-lo. No interior, overflow: auto;funcionará como esperado.

  • o snippet de código incluído na resposta - Clique em insira a descrição da imagem aquie depois em Página inteiraexecutar o snippet OU
  • Clique aqui para o CODEPEN
  • O resultado: insira a descrição da imagem aqui

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

Boa sorte...

Akash
fonte
2
Esta solução é especialmente útil se o componente interno tiver um conjunto de preenchimento, pois o trancará bem na posição onde você desejar. É muito mais simples. (Sim, você pode definir, box-sizing: border-boxmas isso pode ser mais complexo para determinados controles de terceiros).
Simon_Weaver 23/02/19
2
você salvou minha noite!
Botea Florin
2
Obrigado. De alguma forma, estou decepcionado que isso seja necessário, mas sou grato pelo conselho!
Mathias
9

Um pouco tarde, mas isso pode ajudar: http://webdesign.tutsplus.com/tutorials/how-to-make-responsive-scrollable-panels-with-flexbox--cms-23269

Basicamente você precisa colocar html, bodya height: 100%; e enrole todo o seu conteúdo em um<div class="wrap"> <!-- content --> </div>

CSS:

html, body {
  height: 100%;
}

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

Trabalhou para mim. Espero que ajude

Doua Beri
fonte
Você deve ter muito cuidado ao usar "height: 100vh", pois ele mede diferentemente no iOS Safari vs Android. Um leva em consideração a altura da barra de URL e o outro não.
Sean Anderson
7

Adicione isso:

align-items: flex-start;

à regra para .content {}. Isso o corrige na sua caneta para mim, pelo menos (no Firefox e no Chrome).

Por padrão, .contenthas align-items: stretch, que faz com que todos os seus filhos de altura automática correspondam à sua própria altura, de acordo com http://dev.w3.org/csswg/css-flexbox/#algo-stretch . Por outro lado, o valor flex-startpermite que os filhos calculem suas próprias alturas e se alinhem na sua extremidade inicial (e transbordam e acionam uma barra de rolagem).

dholbert
fonte
Além disso, as colunas não terão mais a mesma altura, que é uma das principais atrações do flexbox.
Joseph Silber
ESTÁ BEM. Não estava claro para mim que isso era uma restrição de design - desculpe.
precisa saber é o seguinte
Ótima sugestão
Vlad
1

Um problema que me deparei é que, para ter uma barra de rolagem, um elemento precisa de uma altura a ser especificada (e não como%).

O truque é aninhar outro conjunto de divs dentro de cada coluna e definir a exibição do pai da coluna para flexionar com flex-direction: column.

    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>

E aqui está o 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
fonte
0

A solução para esse problema é apenas adicionar overflow: auto;ao conteúdo. Para tornar o wrapper de conteúdo rolável.

Além disso, há circunstâncias que ocorrem junto com o wrapper Flexbox e o overflowedconteúdo rolável como este código de código .

A solução é adicionar overflow: hidden (or auto);ao pai do wrapper (definido com estouro: auto;) em torno de conteúdos grandes.

Dognose
fonte