Не вдається прокрутити до верхнього елемента, який переповнює контейнер


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 поводиться правильно, якщо ви коментуєте вставний css для вендерів IE10 - я ще не турбував тестування в IE11, але припускаю, що поведінка відповідає відповідності IE10 .

Будь-які ідеї були б добре. Посилання на відомі проблеми або міркування такої поведінки також були б корисними.

Відповіді:


478

Проблема

Flexbox робить центрування дуже легким.

Просто приклавши align-items: centerта justify-content: centerдо гнучких контейнерів, ваш елемент (і) згину буде розташований по центру вертикально та горизонтально.

Однак при цьому методі існує проблема, коли гнучка деталь більша, ніж гнучка ємність.

Як зазначається в питанні, коли гнучкий предмет переповнює контейнер, верх стає недоступним.

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

Для горизонтального переповнення лівий розділ стає недоступним (або правий розділ, мовами RTL).

Ось приклад з контейнером LTR, який містить justify-content: centerтри гнучкі елементи:

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

Дивіться нижню частину цієї відповіді для пояснення такої поведінки.


Рішення №1

Щоб вирішити цю проблему , замість цього використовуйте автоматичні поля поля flexboxjustify-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 :

4.4. Вирівнювання переповнення: safeта unsafeключові слова та обмеження безпеки прокрутки

Коли [гнучка деталь] більша, ніж [гнучка ємність], вона переповниться. Деякі режими вирівнювання, якщо їх буде застосовано в цій ситуації, можуть спричинити втрату даних: наприклад, якщо вміст бічної панелі в центрі, при переповненні вони можуть надіслати частину своїх полів повз початковий край огляду, на який неможливо прокрутити .

Для управління цією ситуацією можна чітко вказати режим вирівнювання переповнення . Unsafeвирівнювання вшановує заданий режим вирівнювання у ситуаціях переповнення, навіть якщо це спричиняє втрату даних, тоді як safeвирівнювання змінює режим вирівнювання у ситуаціях переповнення, намагаючись уникнути втрати даних.

Поведінка за замовчуванням полягає в тому, щоб містити об'єкт вирівнювання в області прокрутки, хоча на момент написання ця функція безпеки ще не реалізована.

safe

Якщо розмір [flex item] переповнює [flex контейнер], замість [flex item] вирівнюється так, як якщо б режим вирівнювання був [ flex-start].

unsafe

Незалежно від відносних розмірів [гнучкої деталі] та [гнучких контейнерів], задане значення вирівнювання враховується.

Примітка: Модуль вирівнювання коробки призначений для використання в декількох моделях компонування коробки, а не просто гнучкий. Отже, у викладі специфікації вище, терміни в дужках насправді говорять про "вирівнювання предмета", "контейнер вирівнювання" та " start". Я використовував специфічні терміни, щоб зосередити увагу на цій конкретній проблемі.


Пояснення щодо обмеження прокрутки з MDN:

Міркування про гнучкі елементи

Властивості вирівнювання Flexbox роблять "справжнє" центрування, на відміну від інших методів центрування у CSS. Це означає, що гнучкі елементи залишаться в центрі, навіть якщо вони переповнюють гнучку ємність.

Іноді це може бути проблематично, якщо вони переповнюють верхній край сторінки або лівий край [...], оскільки ви не можете прокрутити до цієї області, навіть якщо там вміст!

У майбутньому випуску властивості вирівнювання будуть розширені, щоб мати можливість і "безпечного".

Наразі, якщо це викликає занепокоєння, ви можете замість цього використовувати поле для досягнення центрування, оскільки вони відповідатимуть "безпечним" способом і зупинятимуть центрування, якщо вони переповняться.

Замість використання align-властивостей просто покладіть autoполя на гнучкі елементи, які ви хочете відцентрувати.

Замість justify-властивостей поставте автоматичні поля на зовнішніх краях першого та останнього гнучких елементів у контейнері 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
Це не працює для мене при використанні флекс-напрямку: стовпець;
Стефан

22

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

Я трохи пограв з мінімальною висотою перед публікацією, але не знав про властиві обмеження розміру, які є досить новими для специфікації.

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 та інших потенційних рішень.


Я просто хотів сказати, що це вже працює для мене у Firefox. Тож рішення із мінімальним вмістом було ідеальним.
pudgereyem

@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/


THX для підказок-контейнерів прокрутки, я шукав з двох днів, щоб виправити вміст ***** прокрутки !!!
artSx

пам'ятайте, не дають flex: 1 1 autoдо scroll-container. Я робив це за звичкою і потрапив у проблему.
AmirHossein

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>


Це найкраще рішення для застарілих браузерів. Велике спасибі!
Даніель

5
Нічого собі, це багато обгортань.
Натан Артур

1
Нічого собі, я витратив години, намагаючись досягти цього. (Усі інші методи виходять з ладу в мобільному хромі, коли ви додаєте анімацію. Це не так) Дякую soooo!
falsePockets

1

Згідно з MDN, safeтепер значення можна надати таким властивостям, як align-itemsі justify-content. Це описано так:

Якщо розмір елемента переповнює контейнер вирівнювання, замість цього елемент вирівнюється так, як ніби в режимі вирівнювання start.

Отже, він може бути використаний наступним чином.

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

Однак незрозуміло, якою є підтримка браузера, я не міг знайти жодних прикладів його використання, і у мене виникли деякі проблеми з цим. Згадування тут, щоб привернути до нього більше уваги.


7 червня 2018 року і досі не реалізовано в хромі.
AmirHossein

Відповідно до (поточних) сторінок MDN, "безпечний" та "небезпечний" на сьогоднішній день залишаються лише Firefox (ну, Safari та більшість мобільних браузерів невідомо підтримують - я б його відіграв у безпеці та не мав підтримки).
JaMiT

MDN повідомляє про підтримку Firefox, але коли я тестував її в Firefox, здається, це не працює. jsbin.com/pimoqof/1/edit?html,css,output
Олівер Джозеф Еш

Червень 2020 року і не в більшості браузерів, згідно з канюзою
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/

змінити значення вмісту ширини / висоти і див


0

2 Метод Flex Container Flex з тестовим запасом IE8-9, flex працює в 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>

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.