Прокрутка flexbox с переполнением контента


214

введите описание изображения здесь

Вот код, который я использую для достижения вышеуказанного макета:

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

Я опустил код, используемый для стилизации. Вы можете увидеть все это в ручке .


Вышеописанное работает, но когда contentсодержимое области переполняется, происходит прокрутка всей страницы. Я хочу, чтобы прокручивалась только сама область контента, поэтому я добавил overflow: autoв contentdiv .

Проблема с этим теперь в том, что сами столбцы не выходят за пределы родительской высоты, поэтому границы там тоже обрезаются.

Вот ручка, показывающая проблему с прокруткой .

Как я могу настроить contentобласть для прокрутки независимо, в то время как ее дочерние элементы выходят за пределы contentрамки?

Ответы:


264

Я говорил об этом с Табом Аткинсом (автором спецификации flexbox), и вот что мы придумали:

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

Вот ручки:

  1. Растягиваются короткие колонны .
  2. Более длинные столбцы переполнены и прокручиваются .

Причина, по которой это работает, заключается в том, что align-items: stretchне сжимает свои элементы, если они имеют внутреннюю высоту, что достигается здесь min-content.


3
Они работают, когда рост родителя, как правило, не зависит от его детей. min-height: 100% действительно исправляет проблему растяжения, даже когда столбцы короткие, в Firefox (хотя и не в Chrome). Не уверен, что это ошибка Chrome или Firefox.
Дхолберт

1
@dholbert - Таб Аткинс помог мне с этим. Я обновил свой ответ.
Джозеф Силбер

3
Обратите внимание, что Firefox в настоящее время поддерживает только «минимальное содержимое» для значений ширины, а не значений высоты - так что это не будет работать в Firefox, если это важно для вас. (См., Например, bugzilla.mozilla.org/show_bug.cgi?id=852367 )
Дхолберт

2
@ dholbert - проблема с этими ручками в том, что они были публичными, поэтому любой мог их поменять. Я взял на себя ответственность за них, так что вы идете: codepen.io/JosephSilber/pen/pmyHh
Джозеф

5
Да, это не работает в IE11
Стив

119

Я просто очень элегантно решил эту проблему после долгих проб и ошибок.

Проверьте мой блог: http://geon.github.io/programming/2016/02/24/flexbox-full-page-web-app-layout

По сути, чтобы сделать прокручиваемую ячейку flexbox, вы должны сделать все ее родительские элементы overflow: hidden;, или она просто проигнорирует ваши настройки переполнения и вместо этого увеличит родительский элемент.


11
Это сработало и в моем случае, но я действительно хотел бы увидеть объяснение того, почему это работает. Большую часть времени я считаю, что спецификации CSS абсолютно непонятны для такого рода вещей.
Маркриан

2
Из вашего блога: «Я понятия не имею, почему это работает, и спецификации тоже ничего не говорят» . Итак, я ищу объяснение того, почему это работает. Я просмотрел спецификации, но, как вы сказали, там ничего не выпрыгивает.
Маркриан

3
Подумав об этом еще немного, я думаю, что это имеет смысл. Поведение по умолчанию для каждого div, чтобы развернуть, чтобы содержать все его дочерние элементы, так что не будет никакого переполнения, чтобы скрыться в конечных узлах. Вам необходимо принудительно переполнить: скрытый полностью от вершины DOM, чтобы ни у одного из родителей не было возможности разместить своих детей, пока вы не окажетесь на узле, который хотите переполнить и прокрутить.
Geon

3
Я не уверен, что это действительно объясняет. Установка переполнения на скрытый для элемента не останавливает его расширение для включения всех его дочерних элементов, AFAIK. Согласно MDN: «Свойство overflow указывает, следует ли обрезать содержимое, отображать полосы прокрутки или просто отображать содержимое, когда оно переполняет свой контейнер уровня блока». Кроме того, установка переполнения на что-либо, кроме видимого, создает новый контекст форматирования блока - но это не может быть релевантным, поскольку контейнеры flex уже создают свой собственный контекст форматирования блока: developer.mozilla.org/en-US/docs/Web/Guide / CSS /… .
Маркриан

1
Я должен добавить, что я согласен, что ваше объяснение имеет интуитивный смысл, но я не думаю, что это точное техническое объяснение, чего я и хочу. Только по-настоящему поняв причину, я смогу вспомнить решение в будущем!
Маркриан

55

Работаем position:absolute;вместе с flex:

Поместите гибкий элемент с помощью position: relative. Затем внутри него добавьте еще один <div>элемент с:

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

Это расширяет элемент до границ его родителя с относительным положением, но не позволяет расширять его. Внутри overflow: auto;потом будет работать как положено.

  • фрагмент кода, включенный в ответ - нажмите введите описание изображения здесьи затем нажмите Полная страницапосле запуска фрагмента ИЛИ
  • Нажмите здесь для CODEPEN
  • Результат: введите описание изображения здесь

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

Удачи...


2
Это решение особенно полезно, если компонент внутри имеет набор отступов, потому что он будет хорошо блокировать его в нужном положении. Это намного проще. (Да, вы можете установить box-sizing: border-boxвместо этого, но это может быть более сложным для некоторых сторонних элементов управления).
Simon_Weaver

2
ты спас мою ночь!
Ботеа Флорин

2
Спасибо. Я почему-то разочарован тем, что это необходимо, но я благодарен за совет!
Матиас

9

Немного поздно, но это может помочь: http://webdesign.tutsplus.com/tutorials/how-to-make-responsive-scrollable-panels-with-flexbox--cms-23269

В основном вам нужно поставить html, bodyчтобы height: 100%; и обернуть все свое содержимое в<div class="wrap"> <!-- content --> </div>

CSS:

html, body {
  height: 100%;
}

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

Работал на меня. Надеюсь, поможет


Вы должны быть очень осторожны при использовании «height: 100vh», так как оно отличается в iOS Safari от Android. Один учитывает высоту строки URL, а другой - нет.
Шон Андерсон

7

Добавь это:

align-items: flex-start;

к правилу для .content {}. Это исправляет это в вашей ручке для меня, по крайней мере (как в Firefox, так и в Chrome).

По умолчанию .contentимеет align-items: stretch, что делает его размер всех дочерних элементов авто-высоты, чтобы соответствовать его собственному росту, в соответствии с http://dev.w3.org/csswg/css-flexbox/#algo-stretch . Напротив, значение flex-startпозволяет дочерним элементам вычислять свои собственные высоты и выравнивать их по начальному краю (и переполнять, и запускать полосу прокрутки).



Кроме того, колонны больше не будут иметь одинаковую высоту, что является одной из главных достопримечательностей flexbox.
Джозеф Силбер

ХОРОШО. Мне не было ясно, что это было ограничением дизайна - извините.
Дхолберт

Отличное предложение
Влад

1

Одна проблема, с которой я столкнулся, заключается в том, что для наличия полосы прокрутки элементу необходимо указать высоту (а не%).

Хитрость заключается в том, чтобы вкладывать другой набор элементов div в каждый столбец и настраивать отображение родительского элемента столбца на 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>

И вот 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/


0

Решением этой проблемы является просто добавление overflow: auto;в .content для прокрутки оболочки содержимого.

Кроме того, существуют обстоятельства, возникающие вместе с оболочкой Flexbox и overflowedпрокручиваемым контентом, например, эта кодовая ручка .

Решение состоит в том, чтобы добавить overflow: hidden (or auto);к родительскому элементу обертки (устанавливается с помощью overflow: auto;) вокруг большого содержимого.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.