Nie można przewinąć do góry elementu elastycznego, który przepełnia pojemnik

259

Tak więc, próbując stworzyć użyteczny modal za pomocą Flexboksa, znalazłem coś, co wydaje się być problemem przeglądarki i zastanawiam się, czy jest znana poprawka lub obejście - lub pomysły, jak to rozwiązać.

To, co próbuję rozwiązać, ma dwa aspekty. Po pierwsze, uzyskanie okna modalnego wyśrodkowanego pionowo, co działa zgodnie z oczekiwaniami. Drugi polega na przewijaniu okna modalnego - zewnętrznie, więc całe okno modalne przewija się, a nie zawartość w nim zawarta (jest to tak, że możesz mieć listy rozwijane i inne elementy interfejsu użytkownika, które mogą wychodzić poza granice modalu - jak niestandardowy selektor dat itp.)

Jednak łącząc pionowe centrowanie z paskami przewijania, górna część modalu może stać się niedostępna, gdy zacznie się przepełniać. W powyższym przykładzie możesz zmienić rozmiar, aby wymusić przepełnienie, a dzięki temu możesz przewinąć do dołu modalu, ale nie do góry (pierwszy akapit jest ucięty).

Oto link do przykładowego kodu (bardzo uproszczony)

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
}

Te efekty (bieżące) Firefox, Safari, Chrome i Opera. Ciekawie zachowuje się poprawnie w IE10, jeśli komentujesz w css z prefiksem IE10 vender - jeszcze nie zawracałem sobie głowy testowaniem w IE11, ale zakładam, że zachowanie pasuje do IE10 .

Wszelkie pomysły byłyby dobre. Przydatne byłyby również linki do znanych problemów lub uzasadnienia tego zachowania.

jejacks0n
źródło

Odpowiedzi:

478

Problem

Flexbox sprawia, że ​​centrowanie jest bardzo łatwe.

Po prostu nakładając align-items: centeri justify-content: centerna elastyczny pojemnik, twoje elastyczne przedmioty będą wyśrodkowane pionowo i poziomo.

Istnieje jednak problem z tą metodą, gdy element elastyczny jest większy niż pojemnik elastyczny.

Jak zauważono w pytaniu, gdy element elastyczny przepełnia pojemnik, blat staje się niedostępny.

wprowadź opis zdjęcia tutaj

W przypadku przepełnienia poziomego lewa sekcja staje się niedostępna (lub prawa sekcja w językach RTL).

Oto przykład, w którym pojemnik LTR ma justify-content: centeri trzy elastyczne elementy:

wprowadź opis zdjęcia tutaj

Zobacz na dole tej odpowiedzi wyjaśnienie tego zachowania.


Rozwiązanie nr 1

Aby rozwiązać ten problem, użyj automatycznych marginesów Flexbox zamiast justify-content.

Dzięki automarginesom przepełniony elastyczny element można wyśrodkować w pionie i poziomie, nie tracąc dostępu do żadnej jego części.

Zamiast tego kodu na kontenerze Flex:

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

Użyj tego kodu na elemencie flex:

.flex-item {
    margin: auto;
}

wprowadź opis zdjęcia tutaj

Zmienione demo


Rozwiązanie nr 2 (jeszcze nie zaimplementowane w większości przeglądarek)

Dodaj safewartość do reguły wyrównywania słów kluczowych, w ten sposób:

justify-content: safe center

lub

align-self: safe center

Ze specyfikacji modułu CSS Box Alignment Module :

4.4 Przepełnienie Ustawienie: safei unsafesłowa kluczowe i limitów bezpieczeństwa przewijania

Gdy [elastyczny element] jest większy niż [elastyczny pojemnik], przepełni się. Niektóre tryby wyrównania, jeśli są honorowane w tej sytuacji, mogą powodować utratę danych: na przykład, jeśli zawartość paska bocznego jest wyśrodkowana, po przepełnieniu mogą wysyłać część swoich pól poza krawędź początkową rzutni, której nie można przewinąć do .

Aby kontrolować tę sytuację, można jawnie określić tryb wyrównania przepełnienia . Unsafewyrównanie honoruje określony tryb wyrównania w sytuacjach przepełnienia, nawet jeśli powoduje utratę danych, natomiast safewyrównanie zmienia tryb wyrównania w sytuacjach przepełnienia, aby uniknąć utraty danych.

Domyślnym zachowaniem jest umieszczenie przedmiotu wyrównania w przewijalnym obszarze, chociaż w chwili pisania tej funkcji bezpieczeństwa nie jest jeszcze zaimplementowana.

safe

Jeśli rozmiar [elementu elastycznego] przepełnia [element elastycznego pojemnika], [element elastyczny] jest zamiast tego wyrównywany, jakby trybem wyrównania był [ flex-start].

unsafe

Bez względu na względne rozmiary [elementu elastycznego] i [elastycznego pojemnika] podana wartość wyrównania jest honorowana.

Uwaga: Moduł wyrównania skrzynek jest przeznaczony do stosowania w wielu modelach układów skrzynek, a nie tylko flex. Tak więc w powyższym fragmencie specyfikacji wyrażenia w nawiasach faktycznie mówią „temat wyrównania”, „pojemnik wyrównania” i „ start”. Użyłem terminów specyficznych dla flex, aby skupić się na tym konkretnym problemie.


Objaśnienie ograniczenia przewijania z MDN:

Uwagi dotyczące elementów elastycznych

Właściwości wyrównania Flexbox wykonują „prawdziwe” centrowanie, w przeciwieństwie do innych metod centrowania w CSS. Oznacza to, że elementy elastyczne pozostaną wyśrodkowane, nawet jeśli przepełnią pojemnik elastyczny.

Może to czasem być problematyczne, jeśli przekroczą górną krawędź strony lub lewą krawędź [...], ponieważ nie można przewinąć do tego obszaru, nawet jeśli jest tam zawartość!

W przyszłej wersji właściwości wyrównania zostaną rozszerzone o opcję „bezpieczną”.

Na razie, jeśli jest to problem, możesz zamiast tego użyć marginesów, aby uzyskać centrowanie, ponieważ zareagują one w „bezpieczny” sposób i przestaną centrować, jeśli się przepełnią.

Zamiast korzystać z align-właściwości, po prostu umieść automarginesy na elementach elastycznych, które chcesz wyśrodkować.

Zamiast justify-właściwości umieść automatyczne marginesy na zewnętrznych krawędziach pierwszego i ostatniego elementu elastycznego w kontenerze elastycznym.

Te automarże będą „flex” i zakładają przestrzeń resztki, centrowanie wyginanie elementów, gdy istnieje resztki przestrzeni, a przejście na normalnym zestrojeniu kiedy nie.

Jeśli jednak próbujesz zastąpić justify-contentoparte na marginesach centrowanie w wieloliniowym urządzeniu Flexbox, prawdopodobnie nie masz szczęścia, ponieważ musisz umieścić marginesy na pierwszym i ostatnim elemencie flex w każdej linii. O ile nie możesz przewidzieć z góry, które przedmioty znajdą się w której linii, nie możesz wiarygodnie użyć centrowania opartego na marginesie w głównej osi, aby zastąpić justify-contentwłaściwość.

Michael Benjamin
źródło
4
Tak, to lepsze rozwiązanie i dziękuję za dostarczenie dodatkowego cennego wglądu.
jejacks0n
1
Należy zauważyć, że nie działa w IE11. Tło zostanie obcięte.
Daniel
2
@Daniel, właśnie przetestowałem kod w IE11. Nic nie jest niedostępne. W rzeczywistości problem opisany w pytaniu nie istnieje nawet w IE11. Być może mówisz o przepełnieniu tekstu występującym tylko w IE11. To kolejny problem na inne pytanie.
Michael Benjamin
11
Aby naprawić problem w IE11: dodaj align-items: flex-startdo kontenera Flex i zachowaj margin: autoelement Flex.
Eugene Fidelin,
2
To nie działa dla mnie, gdy używam flex-direction: column;
Stefan
22

Cóż, zgodnie z prawem Murphy'ego, lektura, którą zrobiłem po opublikowaniu tego pytania, dała kilka wyników - nie do końca rozwiązanych, ale mimo to nieco przydatnych.

Bawiłem się trochę z minimalną wysokością przed opublikowaniem, ale nie byłem świadomy wewnętrznych ograniczeń rozmiaru, które są dość nowe w specyfikacji.

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

Dodanie min-height: min-contentdo obszaru Flexbox rozwiązuje problem w Chrome, a dzięki prefiksom dostawców rozwiązuje także Operę i Safari, chociaż Firefox pozostaje nierozwiązany.

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

Wciąż szukam pomysłów na Firefoksa i innych potencjalnych rozwiązań.

jejacks0n
źródło
Chciałem tylko powiedzieć, że działa już dla mnie w przeglądarce Firefox. Tak więc rozwiązanie z minimalną zawartością było idealne.
pudgereyem 11.04.17
@pudgereyem Wydaje mi się, że wtedy to zaimplementowali. Inne rozwiązanie margin: autoprzestało flex-basisdla mnie działać, podczas gdy ta odpowiedź rozwiązała oba problemy.
Martin Dawson,
Rzeczywiście genialne rozwiązanie. Nie obchodzi mnie Edge ani IE, więc działa to dla mnie idealnie!
Ohgodwhy
18

Udało mi się to z zaledwie 3 pojemnikami. Sztuczka polega na oddzieleniu kontenera Flexbox od kontenera sterującego przewijaniem. Na koniec umieść wszystko w pojemniku głównym, aby wszystko wyśrodkować. Oto niezbędne style do stworzenia efektu:

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>

Stworzyłem tutaj demo: https://jsfiddle.net/r5jxtgba/14/

colinbr96
źródło
dzięki za wskazówki przewijania kontenera, szukałem od dwóch dni, aby naprawić moją ***** przewijaną zawartość !!!
artSx
pamiętaj, nie daję flex: 1 1 autodo scroll-container. Robiłem to z przyzwyczajeniem i miałem problem.
AmirHossein
Jsfiddle pokazuje, że nie działa, gdy dodasz więcej zawartości do kontenera.
bplittle
4

Myślę, że znalazłem rozwiązanie. Działa z dużą ilością tekstu i małym tekstem . Nie musisz określać żadnych szerokości i powinno to działać w 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
źródło
To najlepsze rozwiązanie dla starszych przeglądarek. Dziękuję Ci bardzo!
Daniel
5
Wow, to dużo owinięć.
Nathan Arthur
1
Wow, spędziłem godziny próbując to osiągnąć. (Wszystkie inne metody zawodzą w mobilnym chrome po dodaniu animacji. To nie działa) Dziękuję bardzo!
falsePockets
1

Zgodnie z MDN safewartość można teraz nadać właściwościom takim jak align-itemsi justify-content. Jest to opisane w następujący sposób:

Jeśli rozmiar elementu przepełnia kontener wyrównania, element jest wyrównany tak, jakby był tryb wyrównania start.

Tak więc można go użyć w następujący sposób.

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

Jednak nie jest jasne, ile obsługuje przeglądarki, nie mogłem znaleźć żadnych przykładów jej użycia i sam miałem z tym pewne problemy. Wspominając o tym tutaj, aby zwrócić na to większą uwagę.

Chris Talman
źródło
7 czerwca 2018 r. I nadal nie zaimplementowane w chrome.
AmirHossein
Według (obecnych) stron MDN, „bezpieczne” i „niebezpieczne” są w tym momencie tylko Firefoxem (cóż, Safari i większość przeglądarek mobilnych mają nieznane wsparcie - zagrałbym to bezpiecznie i zakładam brak wsparcia).
JaMiT,
MDN zgłasza obsługę Firefoksa, ale kiedy przetestowałem go w Firefoksie, nie działało. jsbin.com/pimoqof/1/edit?html,css,output
Oliver Joseph Ash
Czerwiec 2020 i nie w większości przeglądarek, według caniuse
den232
0

Udało mi się to również zrobić przy użyciu dodatkowego kontenera

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;
}

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

zmień wartości szerokości / wysokości zawartości i zobacz

Nadeesh Peiris
źródło
0

2 Metoda Flex kontenera z testem zastępowania tabeli IE8-9, flex działa w IE10,11. Edycja: Edytowane w celu zapewnienia pionowego centrowania przy minimalnej zawartości, dodano obsługę starszych wersji.

Problem wynika z dziedziczenia wysokości z rozmiaru okienka ekranu, co powoduje przepełnienie dzieci, jak odpowiedział Michael. https://stackoverflow.com/a/33455342/3500688

coś prostszego i użyj flex, aby zachować układ w kontenerze wyskakującym (zawartość):

#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
źródło