-1

I have a sidebar menu with variable size. It has a random amount of menuheaders and items. After this menu a <div> should cover the remaining height.

I tried this solution and it would work, but there is a padding on the <div class="menucell"> element (grey space in the fiddle).

How can I remove this padding? Or are there better solutions for this task?

The obligatory fiddle

.menurow {
    display: table-row;
    vertical-align: top;
    box-sizing: border-box;
}

.menucell {
    display: table-cell;
    padding: 0;
    vertical-align: top;
}

.menu {
    position: fixed;
    display: table;
    box-sizing: border-box;
    width: 300px;
    height: calc(100vh - 20px);
    background-color: rgba(0, 0, 0, 0.1);
}

.menuSubheader {
    height: 15px;
    padding: 8px 5px 8px 15px;
    font-size: 12px;
    line-height: 15px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    cursor: pointer;
    position: relative;
    background-color: rgba(0, 0, 255, 0.3);
}

.itemList {
    width: 300px;
    height: auto;
    z-index: 80;
    background-color: rgba(0, 0, 255, 0.1);
}

.item {
    height: 15px;
    padding: 5px 5px 5px 15px;
    background-color: rgba(255, 255, 255, 0.8);
}

.buffer {
    width: 300px;
    margin-top: 10px;
    overflow: hidden;
    text-align: center;
    display: table-cell;
    align-content: center;
    vertical-align: middle;
    color: rgba(211, 47, 47, 0.5);
    background-color: rgba(211, 47, 47, 0.1);
    border: 2px dashed rgba(211, 47, 47, 0.3);
}
<div class="menu">
    <div class="menurow">
        <div class="menucell">
            <div class="menuSubheader"><span>Header1</span></div>
            <div class="itemList">
                <div class="item"><span>Item</span></div>
                <div class="item"><span>Item</span></div>
                <div class="item"><span>Item</span></div>
            </div>
            <div class="menuSubheader"><span>Header2</span></div>
            <div class="itemList">
                <div class="item"><span>Item</span></div>
                <div class="item">
                   <span>Item</span>
                </div>
            </div>
            <div class="menuSubheader" data-visible="false"><span>Header3</span></div>
            <div class="itemList">
                <div class="item"><span>Item</span></div>
                <div class="item"><span>Item</span></div>
                <div class="item"><span>Item</span></div>
            </div>
        </div>
    </div>
    <div class="buffer">
      <span>please fill parent height</span>
    </div>
</div>
Gehtnet
  • 443
  • 10
  • 25

2 Answers2

3

Flex is indeed the easiest way.

.menu {
  min-height: 100vh;/* or height */
  display: flex;
  flex-direction: column;
}

.buffer {
  flex: 1;
}

flex-grow:1; or flex:1 shorthand is what you need to apply to .buffer ;)

This defines the ability for a flex item to grow if necessary. It accepts a unitless value that serves as a proportion. It dictates what amount of the available space inside the flex container the item should take up.

demo below

.menurow {}

.menucell {}

.menu {
  width: 300px;
  padding: 5px;
  background-color: rgba(0, 0, 0, 0.1);
  min-height: 100vh;/* here ============= or height */
  display: flex;/* here ============= */
  flex-direction: column;/* here =================*/
  box-sizing: border-box;
}

.menuSubheader {
  height: 30px;
  padding: 8px 5px 8px 15px;
  font-size: 18px;
  line-height: 30px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  cursor: pointer;
  position: relative;
  background-color: rgba(0, 0, 255, 0.3);
}

.itemList {
  width: 300px;
  background-color: rgba(0, 0, 255, 0.1);
}

.item {
  height: 35px;
  padding: 5px 5px 5px 15px;
  background-color: rgba(255, 255, 255, 0.8);
}

.buffer {
  flex: 1;/* here ====================== */
  color: rgba(211, 47, 47, 0.5);
  background-color: rgba(211, 47, 47, 0.1);
  border: 2px dashed rgba(211, 47, 47, 0.3);
}

/* demo purpose */
.flex-center {
  display: flex;
  flex-flow: column;
  align-items: center;
  justify-content: center;
}
<div class="menu">
  <div class="menurow">
    <div class="menucell">
      <div class="menuSubheader"><span>Header1</span></div>
      <div class="itemList">
        <div class="item"><span>Item</span></div>
        <div class="item"><span>Item</span></div>
        <div class="item"><span>Item</span></div>
      </div>
    </div>
  </div>
  <div>And so on ....</div>
  <div class="buffer flex-center">
    <span>please fill parent height</span>
  </div>
</div>

If you still want to use the table display, you need to write a little more CSS to start with, you have to mind essentially the container and its direct children :

.menu {
  display: table;
  table-layout: fixed; /* to avoid expanding over width set */
  height: 100vh; /* acts like min-height */
}
.menurow {
  display: table-row;
  height: 1%;/* it will expand to fit content */
}

.menucell {
  display: table-cell; 
}
.buffer {
  height: 100%;
}

Demo below

.menu {
  display: table;
  table-layout: fixed; /* to avoid expanding over width set */
  height: 100vh; /* acts like min-height */
}
.menurow {
  display: table-row;
  height: 1%;/* it will expand to fit content */
}

.menucell {
  display: table-cell; 
}
.buffer {
  height: 100%;/* will expand within space left */
}

.menu {
  width: 300px;
  padding: 5px;
  background-color: rgba(0, 0, 0, 0.1);
  box-sizing: border-box;
}

.menuSubheader {
  height: 30px;
  padding: 8px 5px 8px 15px;
  font-size: 18px;
  line-height: 30px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  cursor: pointer;
  position: relative;
  background-color: rgba(0, 0, 255, 0.3);
}

.itemList {
  width: 300px;
  background-color: rgba(0, 0, 255, 0.1);
}

.item {
  height: 35px;
  padding: 5px 5px 5px 15px;
  background-color: rgba(255, 255, 255, 0.8);
}

.buffer {
  color: rgba(211, 47, 47, 0.5);
  background-color: rgba(211, 47, 47, 0.1);
  border: 2px dashed rgba(211, 47, 47, 0.3);
}

/* demo purpose */
.cell-center {
  display: table-cell;
  vertical-align: middle;
  text-align: center;
}
body {
margin:0;
}
<div class="menu">
  <div class="menurow">
    <div class="menucell">
      <div class="menuSubheader"><span>Header1</span></div>
      <div class="itemList">
        <div class="item"><span>Item</span></div>
        <div class="item"><span>Item</span></div>
        <div class="item"><span>Item</span></div>
      </div>
    </div>
  </div>
  <div class="menurow">And so on ....</div>
  <div class="menurow buffer cell-center">
    <span>please fill parent height</span>
  </div>
</div> 

Play snippets in full page mode to test behavior

G-Cyrillus
  • 101,410
  • 14
  • 105
  • 129
1

Try flexboxes :) Positioning is really cooler than tables and old hacks:

https://jsfiddle.net/5L9331m1/1/

What I did:

  • switch your .menu display to flex
  • add .menu flex-direction to column
  • add .buffer height: 100%
  • set the buffer element into the menu element.

Anyway, check this out: https://css-tricks.com/snippets/css/a-guide-to-flexbox/

Hope this helps!

PS: I just fixed the problem with the vertical padding, but you certainly can refactor your whole menu with flexboxes ;)

sjahan
  • 5,720
  • 3
  • 19
  • 42