Przewijanie flexboksa z przepełnioną zawartością

214

wprowadź opis zdjęcia tutaj

Oto kod, którego używam do osiągnięcia powyższego układu:

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

Pominąłem kod użyty do stylizacji. Możesz to wszystko zobaczyć w piórze .


Powyższe działa, ale gdy zawartość contentobszaru przepełnia się, przewija całą stronę. Chcę tylko przewijać sam obszar zawartości, więc dodałem overflow: autodo contentdiv .

Problem polega na tym, że same kolumny nie wystają poza wysokość rodziców, więc granice są tam również odcięte.

Oto pióro pokazujące problem z przewijaniem .

Jak ustawić contentobszar tak, aby przewijał się niezależnie, a jego dzieci nadal wystawały poza contentwysokość pudełka?

Joseph Silber
źródło

Odpowiedzi:

264

Rozmawiałem o tym z Tabem Atkinsem (autorem specyfikacji Flexbox) i oto, co wymyśliliśmy:

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

Oto długopisy:

  1. Rozciągane są krótkie kolumny .
  2. Dłuższe kolumny są przepełnione i przewijane .

Powodem tego jest to, że align-items: stretchnie zmniejsza swoich przedmiotów, jeśli mają one wewnętrzną wysokość, co osiąga się tutaj min-content.

Joseph Silber
źródło
3
Działają, gdy wzrost rodzica nie zależy od jego dzieci, co ma miejsce tutaj. min-height: 100% naprawia rzeczywiście problem z rozciąganiem, nawet gdy kolumny są krótkie w Firefoksie (choć nie w Chrome). Nie jestem pewien, czy to błąd Chrome, czy Firefox.
dholbert
1
@dholbert - Tab Atkins pomógł mi w tym. Zaktualizowałem swoją odpowiedź.
Joseph Silber
3
Pamiętaj, że Firefox obsługuje obecnie tylko „minimalną zawartość” dla wartości szerokości, a nie dla wysokości - więc to nie zadziała w Firefoksie, jeśli to dla Ciebie ważne. (Patrz np. Bugzilla.mozilla.org/show_bug.cgi?id=852367 )
dholbert
2
@dholbert - Problem z tymi piórami polega na tym, że były one publiczne, więc każdy mógł je zmienić. Przejęłem
Joseph Silber
5
Tak, jest to zepsute w IE11
Steve
119

Właśnie rozwiązałem ten problem bardzo elegancko po wielu próbach i błędach.

Sprawdź mój post na blogu: http://geon.github.io/programming/2016/02/24/flexbox-full-page-web-app-layout

Zasadniczo, aby przewijać komórkę Flexbox, musisz uczynić wszystkich jej rodzicami overflow: hidden; , albo po prostu zignoruje twoje ustawienia przepełnienia i zamiast tego powiększy rodzica.

geon
źródło
11
To zadziałało również w moim przypadku, ale wow, naprawdę chciałbym zobaczyć wyjaśnienie, dlaczego to działa. W większości przypadków specyfikacje CSS są całkowicie nieprzeniknione dla tego rodzaju rzeczy.
markrian
2
Z Twojego posta na blogu: „Nie mam pojęcia, dlaczego to działa, a specyfikacja też nic nie mówi” . Szukam wyjaśnienia, dlaczego to działa. Przejrzałem specyfikacje, ale jak powiedziałeś, nic tam nie wyskakuje.
markrian
3
Po dłuższym zastanowieniu myślę, że ma to sens. Domyślnym zachowaniem jest rozwinięcie każdego elementu div, aby zawierał wszystkie jego elementy potomne, więc nie będzie żadnego przepełnienia do ukrycia w węzłach liści. Musisz wymusić przepełnienie: ukryte od góry DOM, więc żaden rodzic nie ma szansy pomieścić swoich dzieci, dopóki nie dojdziesz do węzła, który chcesz przepełnić i przewinąć.
geon
3
Nie jestem pewien, czy to naprawdę wyjaśnia. Ustawienie przepełnienia na ukryte na elemencie nie powstrzymuje jego rozwinięcia się, aby objąć wszystkie jego elementy podrzędne, AFAIK. Według MDN: „Właściwość przepełnienia określa, czy przycinać zawartość, renderować paski przewijania, czy po prostu wyświetlać zawartość, gdy przepełni swój kontener na poziomie bloku”. Ponadto ustawienie przepełnienia na wartość inną niż widoczna tworzy nowy kontekst formatowania bloku - ale to nie może być istotne, ponieważ kontenery Flex już tworzą własny kontekst formatowania bloku: developer.mozilla.org/en-US/docs/Web/Guide / CSS /… .
markrian
1
Powinienem dodać, że zgadzam się z tym, że twoje wyjaśnienie ma intuicyjny sens, ale nie sądzę, aby było to dokładne wyjaśnienie techniczne , a tego właśnie chcę. Tylko dzięki prawdziwemu zrozumieniu przyczyny będę w stanie zapamiętać rozwiązanie w przyszłości!
markrian
55

Współpracując position:absolute;z flex:

Ustaw element elastyczny za pomocą position: relative. Następnie dodaj do niego kolejny <div>element z:

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

To rozszerza element do granic jego nadrzędnego położenia względnego, ale nie pozwala go przedłużyć. Wewnątrz overflow: auto;będzie wtedy działać zgodnie z oczekiwaniami.

  • fragment kodu zawarty w odpowiedzi - Kliknij, wprowadź opis zdjęcia tutaja następnie kliknij przycisk Pełna stronapo uruchomieniu fragmentu LUB
  • Kliknij tutaj, aby CODEPEN
  • Wynik: wprowadź opis zdjęcia tutaj

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

Powodzenia...

Akash
źródło
2
To rozwiązanie jest szczególnie przydatne, jeśli element wewnątrz ma zestaw wypełnień, ponieważ dobrze zablokuje go w dowolnym miejscu. To o wiele prostsze. (Tak, możesz ustawić box-sizing: border-boxzamiast tego, ale może to być bardziej skomplikowane dla niektórych kontroli stron trzecich).
Simon_Weaver
2
uratowałeś mi noc!
Botea Florin
2
Dziękuję Ci. Jakoś jestem rozczarowany, że jest to konieczne, ale jestem wdzięczny za radę!
Mathias
9

Trochę późno, ale to może pomóc: http://webdesign.tutsplus.com/tutorials/how-to-make-responsive-scrollable-panels-w--flexbox--cms-23269

Zasadniczo trzeba postawić html, bodyaby height: 100%; i owinąć całą swoją zawartość do<div class="wrap"> <!-- content --> </div>

CSS:

html, body {
  height: 100%;
}

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

Pracował dla mnie. Mam nadzieję, że to pomoże

Doua Beri
źródło
Należy zachować szczególną ostrożność podczas korzystania z opcji „height: 100vh”, ponieważ inaczej mierzy ona w iOS Safari w porównaniu z Androidem. Jeden uwzględnia wysokość paska adresu URL, a drugi nie.
Sean Anderson
7

Dodaj:

align-items: flex-start;

do zasady dla .content {}. To naprawia to w twoim piórze, przynajmniej dla mnie (zarówno w przeglądarce Firefox, jak i Chrome).

Domyślnie .contentma align-items: stretch, co powoduje, że wszystkie dzieci potomne z automatyczną wysokością dopasowują się do własnej wysokości, według http://dev.w3.org/csswg/css-flexbox/#algo-stretch . W przeciwieństwie do tego, wartość ta flex-startpozwala dzieciom obliczyć własne wysokości i wyrównać się na początkowej krawędzi (i przepełnić oraz uruchomić pasek przewijania).

dholbert
źródło
Ponadto kolumny nie będą już miały równej wysokości, co jest jedną z głównych atrakcji Flexbox.
Joseph Silber
DOBRZE. Nie było dla mnie jasne, że to ograniczenie projektowe - przepraszam.
dholbert
Świetna sugestia
Vlad
1

Jednym z problemów, na jakie natknąłem się, jest to, że aby mieć pasek przewijania, element wymaga określenia wysokości (a nie jako%).

Sztuczka polega na zagnieżdżeniu kolejnego zestawu elementów div w każdej kolumnie i ustawieniu wyświetlania elementu nadrzędnego kolumny za pomocą 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>

A oto 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
źródło
0

Rozwiązaniem tego problemu jest dodanie overflow: auto;do zawartości .content, aby umożliwić przewijanie zawartości opakowania.

Ponadto występują okoliczności towarzyszące pakowaniu Flexbox i overflowedprzewijalnej zawartości, takiej jak ten codepen .

Rozwiązaniem jest dodanie overflow: hidden (or auto);do elementu nadrzędnego opakowania (ustawionego z przepełnieniem: auto;) wokół dużej zawartości.

Dognose
źródło