So, in attempting to make a useful modal using flexbox, I found what seems to be a browser issue and am wondering if there is a known fix or workaround -- or ideas on how to resolve it.
The thing I'm trying to solve, has two aspects. First, getting the modal window vertically centered, which works as expected. The second is to get the modal window to scroll -- externally, so the whole modal window scrolls, not the contents within it (this is so you can have dropdowns and other UI elements that can extend outside of the bounds of the modal -- like a custom date picker, etc.)
However, when combining the vertical centering with scroll bars, the top of the modal can become inaccessible as it begins to overflow. In the above example, you can resize to force the overflow, and in doing so it allows you to scroll to the bottom of the modal, but not to the top (first paragraph is cut off).
Here's the link to the example code (highly simplified)
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 }
This effects (current) Firefox, Safari, Chrome, and Opera.. It does interestingly behave correctly in IE10 if you comment in the IE10 vender prefixed css -- I did not bother testing in IE11 yet, but assume the behavior matches that of IE10.
Any ideas would be good. Links to known issues, or reasoning behind this behavior would also be useful.
You can use the flex-grow property to force an item to fill the remaining space on the main axis of a flex container. The item will expand as much as possible and occupy the free area.
To change this, set the min-width or min-height property.” This means that a flex item with a long word won't shrink below its minimum content size. To fix this, we can either use an overflow value other than visible , or we can set min-width: 0 on the flex item.
Flexbox makes centering very easy.
By simply applying align-items: center
and justify-content: center
to the flex container, your flex item(s) will be vertically and horizontally centered.
However, there is a problem with this method when the flex item is bigger than the flex container.
As noted in the question, when the flex item overflows the container the top becomes inaccessible.
For horizontal overflow, the left section becomes inaccessible (or right section, in RTL languages).
Here's an example with an LTR container having justify-content: center
and three flex items:
See the bottom of this answer for an explanation of this behavior.
To fix this problem use flexbox auto margins, instead of justify-content
.
With auto
margins, an overflowing flex item can be vertically and horizontally centered without losing access to any part of it.
So instead of this code on the flex container:
#flex-container { align-items: center; justify-content: center; }
Use this code on the flex item:
.flex-item { margin: auto; }
Revised Demo
Add the safe
value to your keyword alignment rule, like this:
justify-content: safe center
or
align-self: safe center
From the CSS Box Alignment Module specification:
4.4. Overflow Alignment: the
safe
andunsafe
keywords and scroll safety limitsWhen the [flex item] is larger than the [flex container], it will overflow. Some alignment modes, if honored in this situation, may cause data loss: for example, if the contents of a sidebar are centered, when they overflow they may send part of their boxes past the viewport’s start edge, which can’t be scrolled to.
To control this situation, an overflow alignment mode can be explicitly specified.
Unsafe
alignment honors the specified alignment mode in overflow situations, even if it causes data loss, whilesafe
alignment changes the alignment mode in overflow situations in an attempt to avoid data loss.The default behavior is to contain the alignment subject within the scrollable area, though at the time of writing this safety feature is not yet implemented.
safe
If the size of the [flex item] overflows the [flex container], the [flex item] is instead aligned as if the alignment mode were [
flex-start
].
unsafe
Regardless of the relative sizes of the [flex item] and [flex container], the given alignment value is honored.
Note: The Box Alignment Module is for use across multiple box layout models, not just flex. So in the spec excerpt above, the terms in brackets actually say "alignment subject", "alignment container" and "start
". I used flex-specific terms to keep the focus on this particular problem.
Flexbox's alignment properties do "true" centering, unlike other centering methods in CSS. This means that the flex items will stay centered, even if they overflow the flex container.
This can sometimes be problematic, however, if they overflow past the top edge of the page, or the left edge [...], as you can't scroll to that area, even if there is content there!
In a future release, the alignment properties will be extended to have a "safe" option as well.
For now, if this is a concern, you can instead use margins to achieve centering, as they'll respond in a "safe" way and stop centering if they overflow.
Instead of using the
align-
properties, just putauto
margins on the flex items you wish to center.Instead of the
justify-
properties, put auto margins on the outside edges of the first and last flex items in the flex container.The
auto
margins will "flex" and assume the leftover space, centering the flex items when there is leftover space, and switching to normal alignment when not.However, if you're trying to replace
justify-content
with margin-based centering in a multi-line flexbox, you're probably out of luck, as you need to put the margins on the first and last flex item on each line. Unless you can predict ahead of time which items will end up on which line, you can't reliably use margin-based centering in the main axis to replace thejustify-content
property.
Well, as Murphy's Law would have it, the reading I did after posting this question resulted in a few results -- not completely resolved, but somewhat useful nonetheless.
I played around with min-height a bit before posting, but was not aware of the intrinsic sizing constraints that are fairly new to the spec.
http://caniuse.com/#feat=intrinsic-width
Adding a min-height: min-content
to the flexbox area does resolve the issue in Chrome, and with vendor prefixes also fixes Opera and Safari, though Firefox remains unresolved.
min-height: -moz-min-content; // not implemented min-height: -webkit-min-content // works for opera and safari min-height: min-content // works for chrome
Still looking for ideas on Firefox, and other potential solutions.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With