Home > front end >  CSS: General way to make an element fill its container?
CSS: General way to make an element fill its container?

Time:12-12

How can we make a margin element fill a flexbox item that is not itself a flexbox?

An element (even a nested one with margins) can easily fill its container using position: absolute -- if it's not inside a flexbox item. Why does this not work for an element inside a flexbox item?

<main>
  <nav>NAV</nav>
  <section>
    <div>DIV</div>
  </section>
</main>


<style>

html, body {
  position:absolute; top:0; left:0; right:0; bottom:0;
  margin: 0;
}

main {
  position:absolute; top:0; left:0; right:0; bottom:0;
  display: flex;
}

nav {
  flex-basis: 250px;
  background-color: #eee;
}

section {
  flex-basis: 100%;
  background-color: #ccc;
  margin: 10px;
}

div {
  /* position:absolute; top:0; left:0; right:0; bottom:0; */
  /* why doesn't the above line work? */

  background-color: #cfc;
  margin: 10px;
}

</style>

There are many similar-looking questions like this one and this one that don't really apply to items inside flexboxes or items with margin. There are loads of special-case solutions like align-self: stretch, height: 100% and box-sizing: border-box that just don't work in this example because of the nested margin or the fact that the flexboxes themselves aren't nested. The problems with these one-off hacks go on and on...

So what is the general method to fill a flexbox item? What is the issue with position:absolute here? What is the most general way to make an element fill its container?

CodePudding user response:

<main>
  <nav>NAV</nav>
  <section>
    <div>DIV</div>
  </section>
</main>


<style>

html, body {
  position:absolute; top:0; left:0; right:0; bottom:0;
  margin: 0;
  min-height: 100%;
}

main {
  position:absolute; top:0; left:0; right:0; bottom:0;
  display: flex;
  min-height: 100%;
}

nav {
  flex-basis: 250px;
  background-color: #eee;
}

section {
  flex-basis: 100%;
  background-color: #ccc;
  margin: 10px;
  display: flex;
}

div {
  /* position:absolute; top:0; left:0; right:0; bottom:0; */
  /* why doesn't the above line work? */

  background-color: #cfc;
  margin: 10px;
  flex: 1;
}

</style>

CodePudding user response:

Below is an idea you might find worth exploring? I put the nav as a sibling of main rather than a child. That's not necessary for the CSS but the structure makes most sense. Ideally, you have header, nav``main,footer, possibly an aside as well. You really want to avoid all that absolute positioning. It does not play well on mobile phone - imagine what happens if you put a textbox or textarea on your page and a mobile user clicks on it and the soft-keyboard pops up.

body {
  display: grid;
  grid-template-columns: [left] 196px [main] 1fr [right];
  grid-template-rows: [top] 1fr [bottom];
  grid-gap: 4px;
  outline: 1px dashed #616161;
  min-height: 100vh;
  min-width: 0;
}
body > nav {
  outline: 1px dashed red;
  grid-column-start: left;
  grid-column-end: main;
  grid-row-start: top;
  grid-row-end: bottom;
}
body > main {
  outline: 1px dashed blue;
  grid-column-start: main;
  grid-column-end: right;
  grid-row-start: top;
  grid-row-end: bottom;
  display: flex;
  flex-flow: column nowrap;
}
section {
  flex: 1 1 auto;
  display: flex;
  flex-flow: column nowrap;
}
div {
  flex: 1 1 auto;
  margin: 4px;
  outline: 1px dotted green;
  min-height: auto;
}
<nav>NAV</nav>
<main>
  <section>
    <div>DIV</div>
  </section>
</main>

  • Related