Search code examples
javascriptcsslayoutflexbox

Can I using CSS effectively achieve max-width=100% and max-height=100% without parent having explicit/fixed width and height, alternative approach?


Intro

There are already plenty of questions and answers explaining how max-width and max-height works (this one for example). Basically, if the parent is unrestricted so is the child. OK, fine, but...

Question

...But is there any other way where I could restrict size of the child to whatever size of parent would have if child was not present at all?

...
   <div class="parent"> <!-- size determined by it's parent flexbox -->
      <div class="child">
         <!-- could have large content --> 
      </div>
   </div>
...
.child {
    max-height: 100%; /* not working as needed if parent is unrestricted */
    max-width: 100%; /* not working as needed parent is unrestricted */
    overflow: auto; /* handle oversized content */
}

Context / requirements

  • Page design/layout is top-to-bottom slicing with nested layers of horizontal and vertical flexboxes
  • Whole body should never have vertical nor horizontal scroll
  • Generally, size of some child is determined by size of its parent (100% or less or fill remaining)
  • At some nested level I have parent div that has correct size determined by top-to-down nesting and I know that inner content could be larger size.
    • that larger size should be addressed with inner scrolling in case of overflow
  • Point where my parent and child meet is transition point where different layout strategies meet
    • everything "above" parent is top-to-bottom layout, meaning parent size influencing child size (higher level in DOM dictates size of lower levels)
    • everything "below" child is bottom-to-top layout, meaning child size influencing parent size (lower level in DOM dictates size of upper level)
    • meet point between those two different worlds addressed by scroll if needed

My current workaround

Since I was unable to get desired behaviour using CSS, I have failover to JS by changing child's max-width and max-height to parent's width and height (in pixels) during child is hidden (display: none;). I first hide child to see what would be the size of parent, then restrict size of child, and then show child back.

See JS function refreshMaxWidthAndHeight(wrapper) in JSFiddle demo what I'm actually doing.

Cons of this approach:

  • it's messy
  • it must be triggered each time when something changes (any collapse/expand, content change, viewport size change, etc...)
    • it's hard to exhaustively cover all cases, probably safest would be to use periodic setInterval and do checks constantly
  • in case if child content is large/heavy performance of hide->measure->show approach is not great and it causes visible flicker

JSFiddle demo example

JSFiddle demo Although this demo is very much simplified version of my situation, I've deliberately left in some extra layers of design slicing to demonstrate:

  • why it's not possible to have hardcoded size limits
  • dynamics of collapsing/expanding some portions of page

NOTE current behaviour of demo is exactly behaviour that I'm trying to achieve

EDIT:

Here is Broken behaviour JSFiddle which demonstrates undesired behaviour, it's basically the same as JSFiddle above but with JS workaround that alters max-width and max-height being commented-out.

Note how whole layout breaks when large tables are being displayed.

Questions

  • Are there any other approaches beside using max-width/max-height?
  • Is it possible to avoid need to tweak CSS with JS on every relevant content change?
  • Any pointers or search terms about how other devs are handling similar layout situations?
    • I'm thinking about last point of Context / requirements section where I've described top-to-bottom vs bottom-to-top meet point

Solution

  • Doesn't it boil down to keeping the container size no matter its content? After all your overall layout is determined top-down as you said. So you should not have to recalculate anything if something in the inner layout changes and hence neither should you have to limit the inner content at all in width or height. Just let it overflow:

    outer layout <-> layout boundary <-> inner layout
    

    Does https://jsfiddle.net/conv1eau/ recreate your problem or is this too simple?