Faire défiler une flexbox avec un contenu débordant

214

entrez la description de l'image ici

Voici le code que j'utilise pour réaliser la disposition ci-dessus:

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

J'ai omis le code utilisé pour le style. Vous pouvez tout voir dans le stylo .


Ce qui précède fonctionne, mais lorsque le contentcontenu de la zone déborde, cela fait défiler la page entière. Je veux seulement que la zone de contenu défile, alors j'ai ajouté overflow: autoà la contentdiv .

Le problème avec cela maintenant est que les colonnes elles-mêmes ne s'étendent pas au-delà de la hauteur de leurs parents, donc les bordures y sont également coupées.

Voici le stylo montrant le problème de défilement .

Comment puis-je configurer la contentzone pour qu'elle défile indépendamment, tout en laissant ses enfants s'étendre au-delà de la contenthauteur de la boîte?

Joseph Silber
la source

Réponses:

264

J'ai parlé à Tab Atkins (auteur de la spécification flexbox) à ce sujet, et c'est ce que nous avons trouvé:

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

Voici les stylos:

  1. De courtes colonnes sont étirées .
  2. Colonnes plus longues débordant et défilant .

La raison pour laquelle cela fonctionne est parce align-items: stretchque ne rétrécit pas ses articles s'ils ont une hauteur intrinsèque, ce qui est accompli ici par min-content.

Joseph Silber
la source
3
Ils fonctionnent lorsque la taille du parent ne dépend pas de ses enfants, généralement, ce qui est le cas ici. min-height: 100% résout en effet votre problème d'étirement, même lorsque les colonnes sont courtes dans Firefox (mais pas dans Chrome). Je ne sais pas si c'est un bogue Chrome ou un bogue Firefox.
dholbert
1
@dholbert - Tab Atkins m'a aidé avec ça. J'ai mis à jour ma réponse.
Joseph Silber
3
Notez que Firefox ne prend actuellement en charge que le "contenu minimal" pour les valeurs de largeur, pas les valeurs de hauteur - cela ne fonctionnera donc pas dans Firefox, si cela vous importe. (Voir par exemple bugzilla.mozilla.org/show_bug.cgi?id=852367 )
dholbert
2
@dholbert - Le problème avec ces stylos est qu'ils étaient publics, donc tout le monde pouvait les changer. Je les ai pris en charge, alors voilà: codepen.io/JosephSilber/pen/pmyHh
Joseph Silber
5
Oui, cela est cassé dans IE11
Steve
119

Je viens de résoudre ce problème très élégamment après beaucoup d'essais et d'erreurs.

Consultez mon article de blog: http://geon.github.io/programming/2016/02/24/flexbox-full-page-web-app-layout

Fondamentalement, pour faire défiler une cellule flexbox, vous devez faire tous ses parents overflow: hidden; , ou elle ignorera simplement vos paramètres de débordement et agrandira le parent à la place.

geon
la source
11
Cela a également fonctionné dans mon cas, mais wow, j'aimerais vraiment voir une explication de pourquoi cela fonctionne. La plupart du temps, je trouve que les spécifications CSS sont totalement impénétrables pour ce genre de chose.
Markrian
2
D'après votre article de blog: "Je ne sais pas pourquoi cela fonctionne, et les spécifications ne disent rien non plus" . Donc, je cherche une explication de pourquoi cela fonctionne. J'ai survolé les spécifications, mais comme vous l'avez dit, rien ne saute aux yeux.
Markrian
3
Après y avoir réfléchi un peu plus, je pense que cela a du sens. Le comportement par défaut est que chaque div se développe pour contenir tous ses enfants, il n'y aura donc pas de débordement à masquer aux nœuds terminaux. Vous devez forcer le débordement: caché depuis le haut du DOM, donc aucun parent n'a la possibilité d'accueillir ses enfants jusqu'à ce que vous soyez sur le nœud que vous souhaitez déborder et faire défiler.
geon
3
Je ne suis pas sûr que cela l'explique vraiment. Définir le débordement sur caché sur un élément ne l'empêche pas de se développer pour contenir tous ses enfants, AFAIK. Selon MDN: "La propriété de débordement spécifie s'il faut couper le contenu, rendre les barres de défilement ou simplement afficher le contenu lorsqu'il déborde de son conteneur de niveau bloc." De plus, définir le débordement sur autre chose que visible crée un nouveau contexte de formatage de bloc - mais cela ne peut pas être pertinent, car les conteneurs flex créent déjà leur propre contexte de formatage de bloc: developer.mozilla.org/en-US/docs/Web/Guide / CSS /… .
Markrian
1
Je dois ajouter que je suis d'accord que votre explication est intuitive , mais je ne pense pas que ce soit une explication technique précise , ce que je veux. Ce n'est qu'en comprenant vraiment la raison que je pourrai me souvenir de la solution à l'avenir!
Markrian
55

Travailler position:absolute;avec flex:

Positionnez l'élément flexible avec position: relative. Puis à l'intérieur, ajoutez un autre <div>élément avec:

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

Cela étend l'élément aux limites de son parent positionné par rapport, mais ne permet pas de l'étendre. À l'intérieur, overflow: auto;fonctionnera alors comme prévu.

  • l'extrait de code inclus dans la réponse - Cliquez sur entrez la description de l'image icipuis sur Page entièreaprès avoir exécuté l'extrait OU
  • Cliquez ici pour le CODEPEN
  • Le résultat: entrez la description de l'image ici

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

Bonne chance...

Akash
la source
2
Cette solution est particulièrement utile si le composant à l'intérieur a un jeu de remplissage car il le verrouillera bien en position où vous le souhaitez. C'est beaucoup plus simple. (Oui, vous pouvez définir à la box-sizing: border-boxplace, mais cela peut être plus complexe pour certains contrôles tiers).
Simon_Weaver
2
tu as sauvé ma nuit!
Botea Florin
2
Je vous remercie. D'une certaine manière, je suis déçu que cela soit nécessaire, mais je suis reconnaissant pour les conseils!
Mathias
9

Un peu tard mais cela pourrait aider: http://webdesign.tutsplus.com/tutorials/how-to-make-responsive-scrollable-panels-with-flexbox--cms-23269

Fondamentalement, vous devez mettre html, bodymettre height: 100%; et envelopper tout votre contenu dans un<div class="wrap"> <!-- content --> </div>

CSS:

html, body {
  height: 100%;
}

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

A travaillé pour moi. J'espère que ça aide

Doua Beri
la source
Vous devez être très prudent lorsque vous utilisez "height: 100vh" car il mesure différemment dans iOS Safari vs Android. L'un prend en compte la hauteur de la barre d'URL et l'autre non.
Sean Anderson
7

Ajoute ça:

align-items: flex-start;

à la règle pour .content {}. Cela le corrige dans votre stylo pour moi, au moins (dans Firefox et Chrome).

Par défaut, .contenthas align-items: stretch, ce qui lui permet de dimensionner tous ses enfants à hauteur automatique pour correspondre à sa propre hauteur, par http://dev.w3.org/csswg/css-flexbox/#algo-stretch . En revanche, la valeur flex-startpermet aux enfants de calculer leurs propres hauteurs et de s'aligner sur son bord de départ (et de déborder, et de déclencher une barre de défilement).

dholbert
la source
De plus, les colonnes n'auront plus la même hauteur, ce qui est l'une des principales attractions de flexbox.
Joseph Silber
D'ACCORD. Il n'était pas clair pour moi qu'il s'agissait d'une contrainte de conception - désolé.
dholbert
Grande suggestion
Vlad
1

Un problème que j'ai rencontré est que pour avoir une barre de défilement, un élément doit être spécifié en hauteur (et non en%).

L'astuce consiste à imbriquer un autre ensemble de divs dans chaque colonne et à définir l'affichage du parent de la colonne sur flex avec 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>

Et voici le 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
la source
0

La solution à ce problème consiste simplement à ajouter overflow: auto;au .content pour rendre le wrapper de contenu défilable.

De plus, il y a des circonstances qui se produisent avec l'encapsuleur overflowedFlexbox et le contenu défilable comme ce codepen .

La solution consiste à ajouter overflow: hidden (or auto);au parent de l'encapsuleur (défini avec overflow: auto;) autour de grands contenus.

Dognose
la source