4

I want to create a chat using CSS grid and ran into the problem that I cannot combine align-self: end; and overflow-y: auto;.

The ul holds all the messages and should be aligned to the bottom, so that even when there is only one message, it appears on the bottom.

The header and the footer of the chat are fixed and you only scroll through the messages (like Whats App and similar applications).

I created this pen with some messages. The messages go through the header and it never allows me to scroll.

html,
body {
  margin: 0;
  height: 100%;
}

#chat {
  display: grid;
  height: inherit;
  grid-template-rows: 50px auto 50px;
}

header,
footer {
  background: #4081ff;
}

ul {
  overflow-y: auto;
  align-self: end;
}
<section id="chat">
  <header>header</header>
  <ul>
    <li>Message 1</li>
    <li>Message 1</li>
    <li>Message 1</li>
    <li>Message 1</li>
    <li>Message 1</li>
    <li>Message 1</li>
    <li>Message 1</li>
    <li>Message 1</li>
    <li>Message 1</li>
    <li>Message 1</li>
    <li>Message 1</li>
    <li>Message 1</li>
    <li>last message</li>
  </ul>
  <footer>footer</footer>
</section>
Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
Michael
  • 499
  • 4
  • 16

2 Answers2

3

This appears to be a bug.

Analysis

You are using align-self: end to pin the middle grid item (ul) to the bottom of the row. That fails to render a vertical scrollbar.

I tried various alternatives:

  1. I made the ul grid item a flex container with flex-direction: column and justify-content: flex-end.

  2. I made the ul grid item a flex container with flex-direction: column and applied margin-top: auto to the first li flex item.

  3. I tried switching from

    grid-template-rows: 50px auto 50px
    

    to

    grid-template-rows: 50px 1fr 50px
    

Nothing worked. In all cases, the browser failed to generate a vertical scrollbar.

However, in all cases, when there is no "end" alignment (in other words, the grid item is aligned to the default "start" position), vertical scroll works fine.

Because the scrollbar works in "start" but fails in "end", I think it's fair to call this a bug.

Here's the same problem in flexbox: Can't get vertical scrollbar with justify-content: flex-end


Solution #1: Chrome only

If you make the ul grid item a (nested) grid container with align-content: end, that seems to work in Chrome, but not Firefox and Edge. I didn't test in Safari, IE11 or other browsers.

#chat {
  display: grid;
  height: 100vh;
  grid-template-rows: 50px 1fr 50px;
}

ul {
  overflow-y: auto;
  display: grid;
  align-content: end;
}

header,
footer {
  background: #4081ff;
}

body {
  margin: 0;
}
<section id="chat">
  <header>header</header>
  <ul>
    <li>Message 1</li>
    <li>Message 1</li>
    <li>Message 1</li>
    <li>Message 1</li>
    <li>Message 1</li>
    <li>Message 1</li>
    <li>Message 1</li>
    <li>Message 1</li>
    <li>Message 1</li>
    <li>Message 1</li>
    <li>Message 1</li>
    <li>Message 1</li>
    <li>last message</li>
  </ul>
  <footer>footer</footer>
</section>

revised codepen


Solution #2: All browsers

This solution takes advantage of the fact that vertical scroll works fine with items in the start position. You can insert another li or, even better, a pseudo-element (as they are considered grid items when applied to grid containers). This li will be empty and set to occupy all free space, which will pin the actual items to the bottom.

#chat {
  display: grid;
  height: 100vh;
  grid-template-rows: 50px auto 50px;
}

ul {
  overflow-y: auto;
  display: grid;
  grid-template-rows: 1fr; /* applies to the first row, the only explicit row;
                              all subsequent rows, which are implicit rows, will
                              take `grid-auto-rows: auto` by default */
}

ul::before {
  content: "";
  border: 1px dashed red; /* demo only */
}

header,
footer {
  background: #4081ff;
}

body {
  margin: 0;
}
<section id="chat">
  <header>header</header>
  <ul>
    <li>Message 1</li>
    <li>Message 1</li>
    <li>Message 1</li>
    <li>Message 1</li>
    <li>Message 1</li>
    <li>Message 1</li>
    <li>Message 1</li>
    <li>Message 1</li>
    <li>Message 1</li>
    <li>Message 1</li>
    <li>Message 1</li>
    <li>Message 1</li>
    <li>last message</li>
  </ul>
  <footer>footer</footer>
</section>

revised codepen

Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
2

My solution with scrollbar. I added additional div.

https://codepen.io/anon/pen/zWaRJY

<section id="chat">
  <header>header</header>
  <div id="content">
  <ul>
    <li>Message 1</li>
    <li>Message 1</li>
    <li>Message 1</li>
    <li>Message 1</li>
    <li>Message 1</li>
    <li>Message 1</li>
    <li>Message 1</li>
    <li>Message 1</li>
    <li>Message 1</li>
    <li>Message 1</li>
    <li>Message 1</li>
    <li>Message 1</li>
    <li>last message</li>
  </ul>
  </div>
  <footer>footer</footer>
</section>

html, body {
  margin: 0;
  height: 100%;
}

#chat {
  display: grid;
  height: inherit;
  grid-template-rows: 50px auto 50px;
}

header, footer {
  background: #4081ff;
}

#content {
  overflow-y: auto;
}

ul {
  display: flex;
  flex-direction: column;
  justify-content: end;
  min-height: 100%;
  margin: 0;
}
serek
  • 103
  • 11