How to make one element shrink while two other elements stay the same

How to make one element shrink while two other elements stay the same

async function main() {
    const numStudents = Number(await new Modal('a\n\na\n\na\n\na\n\na\n\na', 'info', 'How many students do you have?', 'Cancel', 'Submit').response());
    const numGrades = Number(await new Modal('', 'info', 'How many grades does each student have?', 'Cancel', 'Submit').response());
}

class Modal {
    constructor(bodyText, type = 'info', headerText = null, footerText = 'Close', prompt = null, closeable = true) {
        this.type = type;
        if (headerText === null) {
            switch (this.type) {
                case 'success':
                    this.headerText = 'Success!';
                    break;
                case 'info':
                    this.headerText = 'Information';
                    break;
                case 'warning':
                    this.headerText = 'Warning!'
                    break;
                case 'error':
                    this.headerText = 'An error has occurred';
                    break;
                default:
                    this.headerText = 'Notification';
            }
        } else {
            this.headerText = headerText;
        }
        this.bodyText = bodyText;
        this.footerText = footerText;
        this.closeable = closeable;
        this.prompt = prompt;
        this.create();
        this.open();
    }

    create() {
        this.dialog = document.createElement('dialog');

        const header = document.createElement('header');
        header.classList.add(this.type, 'background');
        if (this.closeable) {
            const closeButton = document.createElement('button');
            closeButton.classList.add('close');
            closeButton.innerText = '×';
            header.appendChild(closeButton);
        }
        const headerText = document.createElement('h3');
        headerText.innerText = this.headerText;
        header.appendChild(headerText);
        this.dialog.appendChild(header);

        const form = document.createElement('form');
        form.method = 'dialog';

        const body = document.createElement('main');
        this.bodyText.split('\n\n').forEach((paragraph) => {
            const p = document.createElement('p');
            p.innerText = paragraph;
            body.appendChild(p);
        });
        if (this.prompt !== null) {
            this.input = document.createElement('input');
            this.input.placeholder = ' ';
            this.input.autofocus = true;
            const p = document.createElement('p');
            p.appendChild(this.input);
            body.appendChild(p);
        }
        form.appendChild(body);

        const footer = document.createElement('footer');
        footer.classList.add(this.type, 'text');
        const hiddenSubmitButton = document.createElement('button');
        hiddenSubmitButton.value = 'submit';
        hiddenSubmitButton.hidden = true;
        footer.appendChild(hiddenSubmitButton);
        const closeButton = document.createElement('button');
        closeButton.classList.add(this.type, 'text', 'animated');
        closeButton.innerText = this.footerText;
        footer.appendChild(closeButton);
        if (this.prompt === null) {
            closeButton.autofocus = true;
        } else {
            const submitButton = document.createElement('button');
            submitButton.classList.add(this.type, 'background', 'animated');
            submitButton.innerText = this.prompt;
            submitButton.value = 'submit';
            footer.appendChild(submitButton);
        }
        form.appendChild(footer);

        this.dialog.addEventListener('close', (event) => {
            this.close(event.target.returnValue);
        });
        this.dialog.appendChild(form);
        document.body.appendChild(this.dialog);
    }

    open() {
        this.dialog.showModal();
    }

    close(returnValue) {
        if (this.prompt !== null) {
            if (returnValue === '') {
                this.responseValue = null;
                if (this.rejectPromise !== undefined) {
                    this.rejectPromise('User canceled prompt');
                }
            } else {
                this.responseValue = this.input.value;
                if (this.rejectPromise !== undefined) {
                    this.resolvePromise(this.responseValue);
                }
            }
        }
    }

    response() {
        this.promise = new Promise((resolve, reject) => {
            if (this.responseValue !== undefined) {
                if (this.responseValue === null) {
                    reject('User canceled prompt')
                } else {
                    resolve(this.responseValue);
                }
            } else {
                this.resolvePromise = resolve;
                this.rejectPromise = reject;
            }
        });
        return this.promise;
    }
}

main();
:root {
    --error: #c00;
    --error-dark: #900;
    --error-light: #f00;
    --info: #36c;
    --info-dark: #039;
    --info-light: #69f;
    --muted: #ddd;
    --muted-dark: #888;
    --muted-light: #eee;
    --success: #0c0;
    --success-dark: #090;
    --success-light: #0f0;
    --warning: #cc0;
    --warning-dark: #990;
    --warning-light: #ff0;
}

body {
    font-family: Arial, Helvetica, sans-serif;
}

button {
    border: 2px solid;
    border-radius: 10px;
    cursor: pointer;
    margin: 1em 0.5em;
    padding: 10px 15px;
    transition: transform 1s;
}

button:active {
    transform: scale(90%);
}

button.animated {
    background-color: transparent;
    overflow: hidden;
    position: relative;
    transition: color 0.3s, border-color 0.3s, transform 0.2s;
    z-index: 1;
}

button.animated:hover {
    border-color: transparent;
}

button.animated::after {
    border: 0;
    border-radius: 50%;
    content: "";
    height: 200%;
    left: -50%;
    opacity: 0;
    position: absolute;
    transform: scale(0.1);
    transform-origin: center;
    transition: opacity 0.3s, transform 0.3s;
    top: -50%;
    width: 200%;
    z-index: -1;
}

button.animated:hover::after {
    opacity: 1;
    transform: scale(1);
}

input {
    border: 0;
    font: inherit;
    letter-spacing: normal;
    margin: 0;
    padding: 0;
}

input:focus, input:placeholder-shown {
    box-shadow: 0 2px 0 var(--muted);
    outline: none;
}

dialog {
    background-color: white;
    border: 0;
    border-radius: 10px;
    box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
    opacity: 0;
    outline: none;
    padding: 0;
    transform: scale(0);
    transition: all 0.4s allow-discrete;
    width: 50%;
}

dialog:open {
    opacity: 1;
    transform: scale(1);
}

@starting-style {
    dialog:open {
        opacity: 0;
        transform: scale(0);
    }
}

dialog::backdrop {
    background-color: rgba(0, 0, 0, 0);
    transition: all 0.4s allow-discrete;
}

dialog:open::backdrop {
    background-color: rgba(0, 0, 0, 0.4);
}

@starting-style {
    dialog:open::backdrop {
        background-color: rgba(0, 0, 0, 0);
    }
}

dialog header, dialog main, dialog footer {
    display: flow-root;
    padding: 0 1em;
    text-align: center;
}

dialog header {
    background-color: black;
    color: white;
}

dialog main, dialog footer {
    background-color: white;
    color: black;
}

dialog form {
    display: flex;
    flex-direction: column;
}

dialog header, dialog footer {
    flex: initial;
}

dialog main {
    flex: 1 1 auto;
    overflow-y: auto;
}

.close {
    aspect-ratio: 1 / 1;
    background-color: rgba(0, 0, 0, 0);
    border: 0;
    border-radius: 50%;
    box-sizing: border-box;
    color: var(--muted);
    font-size: 1.2em;
    font-weight: bold;
    height: 1.2em;
    margin: 0;
    padding: 0;
    position: absolute;
    right: 0.5rem;
    top: 0.5rem;
    user-select: none;
}

.close:hover,
.close:focus {
    background-color: rgba(255, 255, 255, 0.2);
    color: white;
}

.success.text, .info.text, .warning.text, .error.text, button.animated.success.background::after, button.animated.info.background::after, button.animated.warning.background::after, button.animated.error.background::after {
    background-color: white;
}

.success.background, .info.background, warning.background, error.background, button.animated.success.text:hover, button.animated.info.text:hover, button.animated.warning.text:hover, button.animated.error.text:hover {
    color: white;
}

button.animated.success.text, button.animated.info.text, button.animated.warning.text, button.animated.error.text {
    border-color: var(--muted);
}

.success.text, button.animated.success.background:hover {
    color: var(--success);
}

.success.background, button.animated.success.text::after {
    background-color: var(--success);
}

button.animated.success.text:hover, button.animated.success.background {
    border-color: var(--success);
} 

.info.text, button.animated.info.background:hover {
    color: var(--info);
}

.info.background, button.animated.info.text::after {
    background-color: var(--info);
}

button.animated.info.text:hover, button.animated.info.background {
    border-color: var(--info);
}

.warning.text, button.animated.warning.background:hover {
    color: var(--warning);
}

.warning.background, button.animated.warning.text::after {
    background-color: var(--warning);
}

button.animated.warning.text:hover, button.animated.warning.background {
    border-color: var(--warning);
}

.error.text, button.animated.error.background:hover {
    color: var(--error);
}

.error.background, button.animated.error.text::after {
    background-color: var(--error);
}

button.animated.error.text:hover, button.animated.error.background {
    border-color: var(--error);
}

I have a modal, as you can easily see in the link. When you resize the window until a scroll bar appears, you will see that the scroll bar appears for the entire modal. If you look closely, you can observe that the modal consists of a header (obviously), a main (the body text), and a footer (the button(s) at the bottom). I want the header and footer to act like a header and footer by only having the main portion have a scroll bar. How do I do this?

Answer

Since your grid is mainly a column layout , you may use grid instead flex and set the rows to auto and 1fr for the one supposed to fill the remaining space and scroll if needed.

Below a snippet with a couple of grid and overflow rules to make main scroll:

async function main() {
  const numStudents = Number(await new Modal('a\n\na\n\na\n\na\n\na\n\na', 'info', 'How many students do you have?', 'Cancel', 'Submit').response());
  const numGrades = Number(await new Modal('', 'info', 'How many grades does each student have?', 'Cancel', 'Submit').response());
}

class Modal {
  constructor(bodyText, type = 'info', headerText = null, footerText = 'Close', prompt = null, closeable = true) {
    this.type = type;
    if (headerText === null) {
      switch (this.type) {
        case 'success':
          this.headerText = 'Success!';
          break;
        case 'info':
          this.headerText = 'Information';
          break;
        case 'warning':
          this.headerText = 'Warning!'
          break;
        case 'error':
          this.headerText = 'An error has occurred';
          break;
        default:
          this.headerText = 'Notification';
      }
    } else {
      this.headerText = headerText;
    }
    this.bodyText = bodyText;
    this.footerText = footerText;
    this.closeable = closeable;
    this.prompt = prompt;
    this.create();
    this.open();
  }

  create() {
    this.dialog = document.createElement('dialog');

    const header = document.createElement('header');
    header.classList.add(this.type, 'background');
    if (this.closeable) {
      const closeButton = document.createElement('button');
      closeButton.classList.add('close');
      closeButton.innerText = '×';
      header.appendChild(closeButton);
    }
    const headerText = document.createElement('h3');
    headerText.innerText = this.headerText;
    header.appendChild(headerText);
    this.dialog.appendChild(header);

    const form = document.createElement('form');
    form.method = 'dialog';

    const body = document.createElement('main');
    this.bodyText.split('\n\n').forEach((paragraph) => {
      const p = document.createElement('p');
      p.innerText = paragraph;
      body.appendChild(p);
    });
    if (this.prompt !== null) {
      this.input = document.createElement('input');
      this.input.placeholder = ' ';
      this.input.autofocus = true;
      const p = document.createElement('p');
      p.appendChild(this.input);
      body.appendChild(p);
    }
    form.appendChild(body);

    const footer = document.createElement('footer');
    footer.classList.add(this.type, 'text');
    const hiddenSubmitButton = document.createElement('button');
    hiddenSubmitButton.value = 'submit';
    hiddenSubmitButton.hidden = true;
    footer.appendChild(hiddenSubmitButton);
    const closeButton = document.createElement('button');
    closeButton.classList.add(this.type, 'text', 'animated');
    closeButton.innerText = this.footerText;
    footer.appendChild(closeButton);
    if (this.prompt === null) {
      closeButton.autofocus = true;
    } else {
      const submitButton = document.createElement('button');
      submitButton.classList.add(this.type, 'background', 'animated');
      submitButton.innerText = this.prompt;
      submitButton.value = 'submit';
      footer.appendChild(submitButton);
    }
    form.appendChild(footer);

    this.dialog.addEventListener('close', (event) => {
      this.close(event.target.returnValue);
    });
    this.dialog.appendChild(form);
    document.body.appendChild(this.dialog);
  }

  open() {
    this.dialog.showModal();
  }

  close(returnValue) {
    if (this.prompt !== null) {
      if (returnValue === '') {
        this.responseValue = null;
        if (this.rejectPromise !== undefined) {
          this.rejectPromise('User canceled prompt');
        }
      } else {
        this.responseValue = this.input.value;
        if (this.rejectPromise !== undefined) {
          this.resolvePromise(this.responseValue);
        }
      }
    }
  }

  response() {
    this.promise = new Promise((resolve, reject) => {
      if (this.responseValue !== undefined) {
        if (this.responseValue === null) {
          reject('User canceled prompt')
        } else {
          resolve(this.responseValue);
        }
      } else {
        this.resolvePromise = resolve;
        this.rejectPromise = reject;
      }
    });
    return this.promise;
  }
}

main();
:root {
  --error: #c00;
  --error-dark: #900;
  --error-light: #f00;
  --info: #36c;
  --info-dark: #039;
  --info-light: #69f;
  --muted: #ddd;
  --muted-dark: #888;
  --muted-light: #eee;
  --success: #0c0;
  --success-dark: #090;
  --success-light: #0f0;
  --warning: #cc0;
  --warning-dark: #990;
  --warning-light: #ff0;
}

body {
  font-family: Arial, Helvetica, sans-serif;
}

button {
  border: 2px solid;
  border-radius: 10px;
  cursor: pointer;
  margin: 1em 0.5em;
  padding: 10px 15px;
  transition: transform 1s;
}

button:active {
  transform: scale(90%);
}

button.animated {
  background-color: transparent;
  overflow: hidden;
  position: relative;
  transition: color 0.3s, border-color 0.3s, transform 0.2s;
  z-index: 1;
}

button.animated:hover {
  border-color: transparent;
}

button.animated::after {
  border: 0;
  border-radius: 50%;
  content: "";
  height: 200%;
  left: -50%;
  opacity: 0;
  position: absolute;
  transform: scale(0.1);
  transform-origin: center;
  transition: opacity 0.3s, transform 0.3s;
  top: -50%;
  width: 200%;
  z-index: -1;
}

button.animated:hover::after {
  opacity: 1;
  transform: scale(1);
}

input {
  border: 0;
  font: inherit;
  letter-spacing: normal;
  margin: 0;
  padding: 0;
}

input:focus,
input:placeholder-shown {
  box-shadow: 0 2px 0 var(--muted);
  outline: none;
}

dialog {
  background-color: white;
  border: 0;
  border-radius: 10px;
  box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
  opacity: 0;
  outline: none;
  padding: 0;
  transform: scale(0);
  transition: all 0.4s allow-discrete;
  width: 50%;
  display: grid;
  grid-template-rows: auto 1fr;
  overflow: hidden;
  min-height:12em;
}

dialog:open {
  opacity: 1;
  transform: scale(1);
}

@starting-style {
  dialog:open {
    opacity: 0;
    transform: scale(0);
  }
}

dialog::backdrop {
  background-color: rgba(0, 0, 0, 0);
  transition: all 0.4s allow-discrete;
}

dialog:open::backdrop {
  background-color: rgba(0, 0, 0, 0.4);
}

@starting-style {
  dialog:open::backdrop {
    background-color: rgba(0, 0, 0, 0);
  }
}

dialog header,
dialog main,
dialog footer {
  display: flow-root;
  padding: 0 1em;
  text-align: center;
}

dialog header {
  background-color: black;
  color: white;
}

dialog main,
dialog footer {
  background-color: white;
  color: black;
}

dialog form {
  display: grid;
  grid-template-rows: 1fr auto;
  overflow: hidden;
}

dialog header,
dialog footer {
  flex: initial;
}

dialog main {
  overflow-y: auto;
}

.close {
  aspect-ratio: 1 / 1;
  background-color: rgba(0, 0, 0, 0);
  border: 0;
  border-radius: 50%;
  box-sizing: border-box;
  color: var(--muted);
  font-size: 1.2em;
  font-weight: bold;
  height: 1.2em;
  margin: 0;
  padding: 0;
  position: absolute;
  right: 0.5rem;
  top: 0.5rem;
  user-select: none;
}

.close:hover,
.close:focus {
  background-color: rgba(255, 255, 255, 0.2);
  color: white;
}

.success.text,
.info.text,
.warning.text,
.error.text,
button.animated.success.background::after,
button.animated.info.background::after,
button.animated.warning.background::after,
button.animated.error.background::after {
  background-color: white;
}

.success.background,
.info.background,
warning.background,
error.background,
button.animated.success.text:hover,
button.animated.info.text:hover,
button.animated.warning.text:hover,
button.animated.error.text:hover {
  color: white;
}

button.animated.success.text,
button.animated.info.text,
button.animated.warning.text,
button.animated.error.text {
  border-color: var(--muted);
}

.success.text,
button.animated.success.background:hover {
  color: var(--success);
}

.success.background,
button.animated.success.text::after {
  background-color: var(--success);
}

button.animated.success.text:hover,
button.animated.success.background {
  border-color: var(--success);
}

.info.text,
button.animated.info.background:hover {
  color: var(--info);
}

.info.background,
button.animated.info.text::after {
  background-color: var(--info);
}

button.animated.info.text:hover,
button.animated.info.background {
  border-color: var(--info);
}

.warning.text,
button.animated.warning.background:hover {
  color: var(--warning);
}

.warning.background,
button.animated.warning.text::after {
  background-color: var(--warning);
}

button.animated.warning.text:hover,
button.animated.warning.background {
  border-color: var(--warning);
}

.error.text,
button.animated.error.background:hover {
  color: var(--error);
}

.error.background,
button.animated.error.text::after {
  background-color: var(--error);
}

Enjoyed this article?

Check out more content on our blog or follow us on social media.

Browse more articles