Невозможно прокрутить к верхней части гибкого элемента, который переполнен контейнер

259

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

То, что я пытаюсь решить, имеет два аспекта. Во-первых, получим модальное окно вертикально по центру, которое работает как положено. Второе - заставить модальное окно прокручиваться - внешне, чтобы прокручивалось все модальное окно, а не содержимое внутри него (это значит, что у вас могут быть выпадающие списки и другие элементы пользовательского интерфейса, которые могут выходить за пределы модальных границ). как пользовательский сборщик дат и т. д.)

Однако при объединении вертикального центрирования с полосами прокрутки верхняя часть модальной зоны может стать недоступной, поскольку она начинает переполняться. В приведенном выше примере вы можете изменить размер, чтобы вызвать переполнение, и при этом он позволяет вам прокручиваться до нижней части модальной, но не до верхней части (первый абзац обрезается).

Вот ссылка на пример кода (очень упрощенный)

https://jsfiddle.net/dh9k18k0/2/

.modal-container {
  position: fixed;
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
  background: rgba(0, 0, 0, 0.5);
  overflow-x: auto;
}
.modal-container .modal-window {
  display: -ms-flexbox;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  // Optional support to confirm scroll behavior makes sense in IE10
  //-ms-flex-direction: column;
  //-ms-flex-align: center;
  //-ms-flex-pack: center;
  height: 100%;
}
.modal-container .modal-window .modal-content {
  border: 1px solid #ccc;
  border-radius: 4px;
  background: #fff;
  width: 100%;
  max-width: 500px;
  padding: 10px
}

Это влияет (в настоящее время) на Firefox, Safari, Chrome и Opera. Интересно, что в IE10 правильно работает, если вы прокомментируете в префере IE10 с префиксом продавца - я еще не потрудился тестировать в IE11, но предполагаю, что поведение соответствует IE10 ,

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

jejacks0n
источник

Ответы:

478

Эта проблема

Flexbox делает центрирование очень простым.

Просто применяя align-items: centerиjustify-content: center к гибкому контейнеру, ваши гибкие элементы будут центрированы по вертикали и горизонтали.

Тем не менее, существует проблема с этим методом, когда гибкий элемент больше, чем гибкий контейнер.

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

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

При горизонтальном переполнении левая часть становится недоступной (или правая часть на языках RTL).

Вот пример с контейнером LTR, имеющим justify-content: centerтри элемента flex:

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

Смотрите в нижней части этого ответа для объяснения этого поведения.


Решение № 1

Чтобы решить эту проблему, используйте авто-поля flexbox вместо justify-content.

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

Итак, вместо этого кода в контейнере flex:

#flex-container {
    align-items: center;
    justify-content: center;
}

Используйте этот код на элементе flex:

.flex-item {
    margin: auto;
}

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

Пересмотренный Демо


Решение № 2 (еще не реализовано в большинстве браузеров)

Добавьте safeзначение в правило выравнивания ключевых слов, например так:

justify-content: safe center

или

align-self: safe center

Из спецификации CSS Alignment Module :

4.4. Переполнение Выравнивание: safeи unsafeключевые слова и ограничение безопасности прокрутки

Когда [flex item] больше, чем [flex container], он будет переполнен. Некоторые режимы выравнивания, если их соблюдать в этой ситуации, могут привести к потере данных: например, если содержимое боковой панели центрировано, при переполнении они могут отправить часть своих полей за начальный край области просмотра, который нельзя прокрутить до ,

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

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

safe

Если размер [flex item] выходит за пределы [flex container], вместо этого [flex item] выравнивается, как если бы режим выравнивания был [ flex-start].

unsafe

Независимо от относительных размеров [flex item] и [flex container], заданное значение выравнивания учитывается.

Примечание. Модуль выравнивания ящиков предназначен для использования в разных моделях ящиков, а не только в гибких. Таким образом, в приведенном выше отрывке спецификации термины в скобках на самом деле говорят «объект выравнивания», «контейнер выравнивания» и « start». Я использовал гибкие термины, чтобы сосредоточиться на этой конкретной проблеме.


Объяснение ограничения прокрутки из MDN:

Особенности Flex

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

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

В будущем выпуске свойства выравнивания будут расширены, чтобы также иметь «безопасный» параметр.

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

Вместо того, чтобы использовать align-свойства, просто поместите autoполя на гибкие элементы, которые вы хотите центрировать.

Вместо justify- свойств поместите авто поля на внешние края первого и последнего элементов Flex в контейнере Flex.

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

Однако, если вы пытаетесь заменить justify-contentцентрирование на основе полей в многострочном флексбоксе, вам, вероятно, не повезло, так как вам нужно поместить поля для первого и последнего элемента Flex в каждой строке. Если вы не можете заранее предсказать, какие элементы окажутся на какой строке, вы не сможете надежно использовать центрирование на основе поля по главной оси для замены justify-contentсвойства.

Майкл Бенджамин
источник
4
Да, это лучшее решение, и спасибо за предоставление дополнительной ценной информации.
jejacks0n
1
Следует отметить, что это не работает в IE11. Фон будет обрезан.
Даниэль
2
@Daniel, я только что проверил код в IE11. Нет ничего недоступного На самом деле, проблема, описанная в вопросе, даже не существует в IE11. Возможно, вы имеете в виду переполнение текста, происходящее только в IE11. Это еще одна проблема для другого вопроса.
Майкл Бенджамин
11
Чтобы исправить проблему в IE11: добавьте align-items: flex-startв контейнер flex и оставьте margin: autoдля элемента flex.
Евгений Фиделин
2
Это не работает для меня при использовании flex-direction: column;
Стефан
22

Ну, как сказал бы закон Мерфи, чтение, которое я сделал после публикации этого вопроса, привело к нескольким результатам - не полностью решенным, но, тем не менее, несколько полезным.

Я немного поиграл с min-height перед публикацией, но не знал о внутренних ограничениях размеров, которые являются довольно новыми для спецификации.

http://caniuse.com/#feat=intrinsic-width

Добавление min-height: min-contentв область flexbox действительно решает проблему в Chrome, а с помощью префиксов поставщиков также исправляются Opera и Safari, хотя Firefox остается нерешенной.

min-height: -moz-min-content; // not implemented
min-height: -webkit-min-content // works for opera and safari
min-height: min-content // works for chrome

Все еще ищу идеи о Firefox и другие потенциальные решения.

jejacks0n
источник
Я просто хотел сказать, что это уже работает для меня в Firefox. Так что решение с минимальным содержанием было идеальным.
пудгереем
@pudgereyem Я думаю, они реализовали это тогда. Другое решение с margin: autoостановками не flex-basisработает для меня, тогда как этот ответ решил обе проблемы.
Мартин Доусон
Действительно блестящее решение. Я не забочусь об Edge или IE, так что это прекрасно работает для меня!
Ohgodwhy
18

Мне удалось осуществить это всего с 3 контейнерами. Хитрость заключается в том, чтобы отделить контейнер flexbox от контейнера, который управляет прокруткой. Наконец, поместите все в корневой контейнер, чтобы центрировать все это. Вот основные стили для создания эффекта:

CSS:

.root {
  display: flex;
  justify-content: center;
  align-items: center;
}

.scroll-container {
  margin: auto;
  max-height: 100%;
  overflow: auto;
}

.flex-container {
  display: flex;
  flex-direction: column;
  justify-content: center;
}

HTML:

<div class="root">
  <div class="scroll-container">
    <div class="flex-container">
      <p>Lorem ipsum dolor sit amet.</p>
    </div>
  </div>
</div>

Я создал демо здесь: https://jsfiddle.net/r5jxtgba/14/

colinbr96
источник
Спасибо за советы прокрутки контейнера, я искал два дня для исправления моего ***** прокрутки содержимого !!!
artSx
помните, не дают flex: 1 1 autoк scroll-container. Я делал это по привычке и попал в проблему.
Амир Хоссейн
1
Jsfiddle показывает, что он не работает, когда вы добавляете больше содержимого в контейнер.
bplittle
4

Я думаю, что нашел решение. Работает с большим количеством текста и небольшим количеством текста . Вам не нужно указывать ширину чего-либо, и это должно работать в IE8.

.wrap1 {
  position: fixed;
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
  background: rgba(0, 0, 0, 0.5);
  overflow-y: auto;
}
.wrap2 {
  display: table;
  width: 100%;
  height: 100%;
  text-align: center;
}
.wrap3 {
  vertical-align: middle;
  display: table-cell;
}
.wrap4 {
  margin: 10px;
}
.dialog {
  text-align: left;
  background-color: white;
  padding: 5px;
  border-radius: 3px;
  margin: auto;
  display: inline-block;
  box-shadow: 2px 2px 4px rgba(0, 0, 0, .5);
}
<div class="wrap1">
  <div class="wrap2">
    <div class="wrap3">
      <div class="wrap4">
        <div class="dialog">
          <p>Lorem ipsum dolor sit amet.</p>
        </div>
      </div>
    </div>
  </div>
</div>

mpen
источник
Это лучшее решение для старых браузеров. Большое спасибо!
Даниэль
5
Вау, это много оберток.
Натан Артур
1
Вау, я часами пытался добиться этого. (При добавлении анимации все другие методы не работают в мобильном Chrome. Это не так).
falsePockets
1

Согласно MDN, safeтеперь значение может быть предоставлено свойствам, подобным align-itemsи justify-content. Это описано следующим образом:

Если размер элемента выходит за пределы контейнера выравнивания, элемент выравнивается, как если бы был режим выравнивания start.

Таким образом, это может быть использовано следующим образом.

.rule
{
    display: flex;
    flex-direction: row;
    justify-content: center;
    align-items: safe center;
}

Тем не менее, неясно, насколько сильно он поддерживает браузер, я не смог найти никаких примеров его использования, и у меня были некоторые проблемы с ним. Упоминание здесь, чтобы привлечь к нему больше внимания.

Крис Талман
источник
7 июня 2018 года и до сих пор не реализовано в Chrome.
Амир Хоссейн
Согласно (текущим) страницам MDN, «безопасные» и «небезопасные» все еще доступны только для Firefox (ну, Safari и большинство мобильных браузеров имеют неизвестную поддержку - я бы проигнорировал и предположил, что поддержка не будет).
JaMiT
MDN сообщает о поддержке Firefox, но когда я тестировал ее в Firefox, она, похоже, не работала. jsbin.com/pimoqof/1/edit?html,css,output
Оливер Джозеф Эш
Июнь 2020 года и не в большинстве браузеров, согласно caniuse
den232
0

Мне также удалось сделать это с помощью дополнительного контейнера

HTML

<div class="modal-container">
  <div class="modal">
    <div class="content-container">
       <div class="content">
         <p>Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.</p>
        </div>
      </div>
  </div>  
</div>

CSS

.modal-container {
  display: flex;
  justify-content: center;
  align-items: center;
  position: fixed;
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
  background-color: black;
}

.modal {
  display: flex;
  justify-content: center;
  align-items: center;
  background-color: #aaa;
  height: 80%;
  width: 90%;
}

.content-container {
  background-color: blue;
  max-height: 100%;
  overflow: auto;
  padding:0;
}

.content {
  display: flex;
  background-color: red;
  padding: 5px;
  width: 900px;
  height: 300px;
}

в jsfiddle> https://jsfiddle.net/Nash171/cpf4weq5/

измените значения .content ширина / высота и посмотрите

Надеше Пейрис
источник
0

2 Контейнер Flex Метод с таблицей нейтрализация испытания IE8-9, гибкие работы в IE10,11. Редактировать: отредактировано для обеспечения вертикального центрирования при минимальном содержании, добавлена ​​устаревшая поддержка.

Как объясняет Майкл, проблема заключается в том, что высота наследуется от размера области просмотра, что приводит к переполнению дочерних элементов. https://stackoverflow.com/a/33455342/3500688

что-то более простое и используйте flex для поддержки макета во всплывающем контейнере (контент):

#popup {
position: fixed;
top: 0;
left: 0;
right: 0;
min-height: 100vh;
background-color: rgba(0,0,0,.25);
margin: auto;
overflow: auto;
height: 100%;
bottom: 0;
display: flex;
align-items: flex-start;
box-sizing:border-box;
padding:2em 20px;
}
.container {
background-color: #fff;
margin: auto;
border: 1px solid #ccc;
border-radius: 4px;
background: #fff;
/* width: 100%; */
max-width: 500px;
padding: 10px;
    /* display: flex; */
    /* flex-wrap: wrap; */
}
		<!--[if lt IE 10]>
<style>
	  #popup {
			display: table;
			width:100%;
		}
		.iewrapper {
			display: table-cell;
			vertical-align: middle;
		}
	</style>
	<![endif]-->
<div id="popup">
	<!--[if lt IE 10]>
<div class="iewrapper">
<![endif]-->
    <div class="container">
        <p class="p3">Test</p>
    <p class="p3">Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.</p>
    <p class="p3">Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.</p>
    </div>
	<!--[if lt IE 10]>
<div class="iewrapper">
<![endif]-->
</div>

Silverandrew
источник