Появление белой области при увеличении и смещении textarea

Я захотел повторить textarea как у chatgpt (при переходе на новую строку он увеличивается, но не вниз, а вверх) и когда я перехожу на новую строку в textarea он увеличивается и смещается вверх, а внизу страницы появляется белая область, которая увеличивается с каждой новой строкой в textarea (относится только к тем строкам, при которых textarea увеличивается и смещается).

Скрины: Нормальный вид сайта Вид сайта с белой областью

Референс: Пустрой textarea textarea с текстом textarea с полосой прокрутки

Режим разработчика:

Область textarea с введённым текстом Область section Код:

document.getElementById("promptarea").addEventListener("input", function() {
    var maxLength = 10;
    var lines = this.value.split("\n");

    // Предыдущая высота textarea
    var prevHeight = this.clientHeight;

    // Обрабатываем каждую строку
    for (var i = 0; i < lines.length; i++) {
        // Если строка длиннее maxLength, обрезаем её и добавляем перенос строки
        if (lines[i].length > maxLength) {
            lines[i] = lines[i].substring(0, maxLength) + "\n";
        }
    }

    // Обновляем значение textarea
    this.value = lines.join("\n");

    // Устанавливаем высоту textarea в зависимости от содержимого
    this.style.height = "";
    var newHeight = Math.min(this.scrollHeight, 200);
    this.style.height = newHeight + "px";

    // Вычисляем смещение
    var offset = 0;
    if (newHeight !== prevHeight) {
        offset = newHeight - prevHeight;
    }

    // Применяем смещение
    this.style.top = parseFloat(getComputedStyle(this).top) - offset + "px";
    
});
@import url('https://fonts.googleapis.com/css2?family=Grape+Nuts&display=swap');
*{
    margin: 0px;
    padding: 0px;
}
.material-symbols-outlined {
  font-variation-settings:
  'FILL' #682b2b,
  'wght' 400,
  'GRAD' 0,
  'opsz' 24
}
body {
    background-repeat: no-repeat;
    background-size: cover;    
    background-attachment: scroll;
    min-height: 100vh;
    min-width: 100vw;
    display: inline-block;
}
.header{
    background-color: #adadad;
    width: 80vw;
    height: 10vh;
    justify-content: flex-end;
    position: relative;
    left: 20vw;
    display: flex;
}
.nav{
    text-align: center;
    width: 60%;
    position: absolute;
    margin-top: 3vh;
    left: 30%;
    top: 0.4vh;
    display: block;
    z-index: 1;
}

.main{
    background-color: #626262;
    width: 100vw;
    height: 90vh;
}
.aside{
    color: #fff;
    background-color: #000;
    width: 20vw;
    height: 100vh;
    position: absolute;
}
.section {
    background-color: #414141;
    width: 80vw;
    height: 10vh;
    position: relative;
    bottom: -80vh;
    left: 20vw;
}

nav a{
    transition: .3s;
    font-family: 'Grape Nuts', calibri;
    display: inline-block;
    text-decoration: none;
    color: #000;
    border-radius: 5px;
    font-size: 3vh;
    display: inline;
    padding: 0 20px;
    background-color: #5b5a5a;

}
nav a:hover{
    transition: .3s;
    color: #fff;
    background-color: #000;
}
#button{
    height: 3vh;
    margin: 47vh auto;
    display: block;
}
#menu {
    display: inline-block;
    font-size: 10vh;
    line-height: 1;
    z-index: 2;
    width: 100px;
    height: 100px;
}
 
#menu:hover{
    color: #ff0000; 
    cursor: pointer;
}
.section textarea{
    position: relative;
    height: 4vh;
    margin-top: 3vh;
    width: 85%; 
    margin-left: 3%;
    margin-right: 3%;
    resize: none;
    border-radius: 4px;
    overflow: hidden;
    font-size: 16pt;
    overflow: auto;
}

#prompt{
    transition: .3s;
    border: none;
    color: inherit;
    background-color: transparent;
    cursor: pointer;
    position: absolute;
    left: calc(85% + 3% - 28pt);
    top: 35%;
    color: #000000;
}
/* .section{
    background: #741818;
} */
.section textarea:placeholder-shown ~ #prompt{
    transition: .3s;
    border: none;
    color: inherit;
    background-color: transparent;
    cursor: default;
    position: absolute;
    left: calc(85% + 3% - 28pt);
    top: 35%;
    color: #cccccc;
}
<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="../css/stylesheet.css">
    <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@24,400,0,0" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <aside class="aside">
        <div class="dialogs">
            <button type="button" id="button">Текст</button>
        </div>
    </aside>
    <header class="header">
        <div class="material-symbols-outlined menu-icon" id="menu">
            menu
        </div>
    </header>
<nav class="nav">
    <a href="html.htm">Главная</a>
    <a href="#">Диалоги</a>
    <a href="#">О нас</a>
</nav>
    <main class="main">
        <section class="section">
            <textarea id="promptarea" name="" cols="30" rows="10" placeholder="Ваше сообщение..."></textarea>
            <button class="material-symbols-outlined" id="prompt"> prompt_suggestion </button>
        </section>
    </main>
    <script src="../js/talkpage.js"></script>
</body>
</html>


Ответы (1 шт):

Автор решения: Grundy

Как было указано - проблема в использовании position:relative;. В этом случае место под новую высоту продолжает выделяться.

Для решения достаточно изменить position на absolute у textarea.

document.getElementById("promptarea").addEventListener("input", function() {
    var maxLength = 10;
    var lines = this.value.split("\n");

    // Предыдущая высота textarea
    var prevHeight = this.clientHeight;

    // Обрабатываем каждую строку
    for (var i = 0; i < lines.length; i++) {
        // Если строка длиннее maxLength, обрезаем её и добавляем перенос строки
        if (lines[i].length > maxLength) {
            lines[i] = lines[i].substring(0, maxLength) + "\n";
        }
    }

    // Обновляем значение textarea
    this.value = lines.join("\n");

    // Устанавливаем высоту textarea в зависимости от содержимого
    this.style.height = "";
    var newHeight = Math.min(this.scrollHeight, 200);
    this.style.height = newHeight + "px";

    // Вычисляем смещение
    var offset = 0;
    if (newHeight !== prevHeight) {
        offset = newHeight - prevHeight;
    }

    // Применяем смещение
    this.style.top = parseFloat(getComputedStyle(this).top) - offset + "px";
    
});
@import url('https://fonts.googleapis.com/css2?family=Grape+Nuts&display=swap');
*{
    margin: 0px;
    padding: 0px;
}
.material-symbols-outlined {
  font-variation-settings:
  'FILL' #682b2b,
  'wght' 400,
  'GRAD' 0,
  'opsz' 24
}
body {
    background-repeat: no-repeat;
    background-size: cover;    
    background-attachment: scroll;
    min-height: 100vh;
    min-width: 100vw;
    display: inline-block;
}
.header{
    background-color: #adadad;
    width: 80vw;
    height: 10vh;
    justify-content: flex-end;
    position: relative;
    left: 20vw;
    display: flex;
}
.nav{
    text-align: center;
    width: 60%;
    position: absolute;
    margin-top: 3vh;
    left: 30%;
    top: 0.4vh;
    display: block;
    z-index: 1;
}

.main{
    background-color: #626262;
    width: 100vw;
    height: 90vh;
}
.aside{
    color: #fff;
    background-color: #000;
    width: 20vw;
    height: 100vh;
    position: absolute;
}
.section {
    background-color: #414141;
    width: 80vw;
    height: 10vh;
    position: relative;
    bottom: -80vh;
    left: 20vw;
}

nav a{
    transition: .3s;
    font-family: 'Grape Nuts', calibri;
    display: inline-block;
    text-decoration: none;
    color: #000;
    border-radius: 5px;
    font-size: 3vh;
    display: inline;
    padding: 0 20px;
    background-color: #5b5a5a;

}
nav a:hover{
    transition: .3s;
    color: #fff;
    background-color: #000;
}
#button{
    height: 3vh;
    margin: 47vh auto;
    display: block;
}
#menu {
    display: inline-block;
    font-size: 10vh;
    line-height: 1;
    z-index: 2;
    width: 100px;
    height: 100px;
}
 
#menu:hover{
    color: #ff0000; 
    cursor: pointer;
}
.section textarea{
    position: absolute;
    height: 4vh;
    margin-top: 3vh;
    width: 85%; 
    margin-left: 3%;
    margin-right: 3%;
    resize: none;
    border-radius: 4px;
    overflow: hidden;
    font-size: 16pt;
    overflow: auto;
}

#prompt{
    transition: .3s;
    border: none;
    color: inherit;
    background-color: transparent;
    cursor: pointer;
    position: absolute;
    left: calc(85% + 3% - 28pt);
    top: 35%;
    color: #000000;
}
/* .section{
    background: #741818;
} */
.section textarea:placeholder-shown ~ #prompt{
    transition: .3s;
    border: none;
    color: inherit;
    background-color: transparent;
    cursor: default;
    position: absolute;
    left: calc(85% + 3% - 28pt);
    top: 35%;
    color: #cccccc;
}
<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="../css/stylesheet.css">
    <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@24,400,0,0" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <aside class="aside">
        <div class="dialogs">
            <button type="button" id="button">Текст</button>
        </div>
    </aside>
    <header class="header">
        <div class="material-symbols-outlined menu-icon" id="menu">
            menu
        </div>
    </header>
<nav class="nav">
    <a href="html.htm">Главная</a>
    <a href="#">Диалоги</a>
    <a href="#">О нас</a>
</nav>
    <main class="main">
        <section class="section">
            <textarea id="promptarea" name="" cols="30" rows="10" placeholder="Ваше сообщение..."></textarea>
            <button class="material-symbols-outlined" id="prompt"> prompt_suggestion </button>
        </section>
    </main>
    <script src="../js/talkpage.js"></script>
</body>
</html>

Также можно немного упростить код, и не рассчитывать top. Для этого достаточно привязать textarea к нижнему краю, а не к верхнему, в этом случае позиция всегда одинаковая и достаточно пересчитать только высоту.

document.getElementById("promptarea").addEventListener("input", function() {
    var maxLength = 10;
    var lines = this.value.split("\n");

    // Предыдущая высота textarea
    var prevHeight = this.clientHeight;

    // Обрабатываем каждую строку
    for (var i = 0; i < lines.length; i++) {
        // Если строка длиннее maxLength, обрезаем её и добавляем перенос строки
        if (lines[i].length > maxLength) {
            lines[i] = lines[i].substring(0, maxLength) + "\n";
        }
    }

    // Обновляем значение textarea
    this.value = lines.join("\n");

    // Устанавливаем высоту textarea в зависимости от содержимого
    this.style.height = "";
    var newHeight = Math.min(this.scrollHeight, 200);
    this.style.height = newHeight + "px";    
});
@import url('https://fonts.googleapis.com/css2?family=Grape+Nuts&display=swap');
*{
    margin: 0px;
    padding: 0px;
}
.material-symbols-outlined {
  font-variation-settings:
  'FILL' #682b2b,
  'wght' 400,
  'GRAD' 0,
  'opsz' 24
}
body {
    background-repeat: no-repeat;
    background-size: cover;    
    background-attachment: scroll;
    min-height: 100vh;
    min-width: 100vw;
    display: inline-block;
}
.header{
    background-color: #adadad;
    width: 80vw;
    height: 10vh;
    justify-content: flex-end;
    position: relative;
    left: 20vw;
    display: flex;
}
.nav{
    text-align: center;
    width: 60%;
    position: absolute;
    margin-top: 3vh;
    left: 30%;
    top: 0.4vh;
    display: block;
    z-index: 1;
}

.main{
    background-color: #626262;
    width: 100vw;
    height: 90vh;
}
.aside{
    color: #fff;
    background-color: #000;
    width: 20vw;
    height: 100vh;
    position: absolute;
}
.section {
    background-color: #414141;
    width: 80vw;
    height: 10vh;
    position: relative;
    bottom: -80vh;
    left: 20vw;
}

nav a{
    transition: .3s;
    font-family: 'Grape Nuts', calibri;
    display: inline-block;
    text-decoration: none;
    color: #000;
    border-radius: 5px;
    font-size: 3vh;
    display: inline;
    padding: 0 20px;
    background-color: #5b5a5a;

}
nav a:hover{
    transition: .3s;
    color: #fff;
    background-color: #000;
}
#button{
    height: 3vh;
    margin: 47vh auto;
    display: block;
}
#menu {
    display: inline-block;
    font-size: 10vh;
    line-height: 1;
    z-index: 2;
    width: 100px;
    height: 100px;
}
 
#menu:hover{
    color: #ff0000; 
    cursor: pointer;
}
.section textarea{
    position: absolute;
    height: 4vh;
    margin-bottom: 3vh;
    bottom: 0;
    width: 85%; 
    margin-left: 3%;
    margin-right: 3%;
    resize: none;
    border-radius: 4px;
    overflow: hidden;
    font-size: 16pt;
    overflow: auto;
}

#prompt{
    transition: .3s;
    border: none;
    color: inherit;
    background-color: transparent;
    cursor: pointer;
    position: absolute;
    left: calc(85% + 3% - 28pt);
    top: 35%;
    color: #000000;
}
/* .section{
    background: #741818;
} */
.section textarea:placeholder-shown ~ #prompt{
    transition: .3s;
    border: none;
    color: inherit;
    background-color: transparent;
    cursor: default;
    position: absolute;
    left: calc(85% + 3% - 28pt);
    top: 35%;
    color: #cccccc;
}
<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="../css/stylesheet.css">
    <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@24,400,0,0" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <aside class="aside">
        <div class="dialogs">
            <button type="button" id="button">Текст</button>
        </div>
    </aside>
    <header class="header">
        <div class="material-symbols-outlined menu-icon" id="menu">
            menu
        </div>
    </header>
<nav class="nav">
    <a href="html.htm">Главная</a>
    <a href="#">Диалоги</a>
    <a href="#">О нас</a>
</nav>
    <main class="main">
        <section class="section">
            <textarea id="promptarea" name="" cols="30" rows="10" placeholder="Ваше сообщение..."></textarea>
            <button class="material-symbols-outlined" id="prompt"> prompt_suggestion </button>
        </section>
    </main>
    <script src="../js/talkpage.js"></script>
</body>
</html>

→ Ссылка