Мне очень жаль за этот вопрос, потому что я уже видел здесь много подобных вопросов, но до сих пор не могу понять.
Я хотел бы создать элемент overlay
с элементами управления для элемента display
, где элементы управления расположены вертикально и выровнены по правому и нижнему краю экрана. Существует один элемент фиксированного размера buttons
, содержащий некоторые элементы управления, а затем элемент динамического размера info
, который появляется только тогда, когда некоторые части дисплея активны. info
всегда содержит кнопку закрытия и некоторую информацию о динамической высоте. Я бы хотел, чтобы контейнер info
всегда сжимался до своего содержимого. Однако, если высота содержимого слишком велика и содержащий элемент info
будет выше, чем оставшееся вертикальное пространство контейнера overlay
, я бы хотел, чтобы содержимое можно было прокручивать.
Я думал, что просто использую гибкий контейнер и атрибуты overflow-y
, но, похоже, это не поможет. Кажется, что переполнение срабатывает только в том случае, если родительский контейнер имеет определенную высоту, но в моем случае родительский контейнер является динамическим, то есть он должен расти до определенной высоты, а затем останавливаться, пока содержимое становится прокручиваемым.
Это была моя попытка:
const info = document.querySelector(".info");
const content = document.querySelector(".content");
document.querySelector("#open-info").addEventListener("click", () => {
info.style.display = "flex";
});
document.querySelector("#close-info").addEventListener("click", () => {
info.style.display = "none";
});
document.querySelector("#increase-height").addEventListener("click", () => {
content.style.height = `${content.clientHeight + 30}px`;
});
document.querySelector("#decrease-height").addEventListener("click", () => {
content.style.height = `${content.clientHeight - 30}px`;
});
.display {
position: relative;
width: 400px;
height: 300px;
background-color: gray;
}
.overlay {
position: absolute;
display: flex;
width: 100%;
height: 100%;
top: 0;
left: 0;
flex-direction: column;
justify-content: flex-end;
align-items: flex-end;
}
.info {
display: flex;
flex-direction: column;
justify-content: flex-end;
align-items: flex-end;
flex-shrink: 0;
background-color: orange;
padding: 10px;
max-height: 230px;
/* overflow works, but fixed size is undesirable, as the remaining space in main-axis direction should be used up */
/* max-height: 100%; overflow doesn't work, as it refers to parent's height, not to remaining available space in main-axis direction*/
}
.info-content-wrapper {
padding: 5px;
overflow-x: hidden;
overflow-y: auto;
}
.content {
width: 80px;
height: 150px;
background-color: yellow;
}
.controls {
background-color: lightblue;
padding: 5px;
flex: 0 0 auto;
}
<div class = "display">
<div class = "overlay">
<div class = "info">
<button id = "close-info">Close</button>
<div class = "info-content-wrapper">
<div class = "content"></div>
</div>
</div>
<div class = "controls">
<button id = "open-info">Open info</button>
<button id = "increase-height">+</button>
<button id = "decrease-height">-</button>
</div>
</div>
</div>
В примере вы можете использовать кнопки, чтобы скрыть/показать информацию, а также увеличить/уменьшить высоту контента. Я использовал фиксированный max-height: 230px
на .info
, чтобы продемонстрировать, как это должно работать. Однако вместо использования фиксированного max-height
следует использовать оставшееся вертикальное пространство гибкого контейнера. Но когда я использую max-height: 100%
, он (согласно определению) будет относиться к общей высоте родительского гибкого контейнера. Если я вложу его дальше (например, внедрив обертку вокруг внутреннего HTML .info
) и установлю max-height
этого элемента на 100%
, это все равно не сработает.
Мне кажется, что ответ должен быть очень простым, но я не могу найти решение, используя только гибкую компоновку и не прибегая к обходным путям с помощью calc
. Я чувствую себя очень глупо по этому поводу и был бы очень рад помощи!
Я скомпилировал этот фрагмент кода, который вы можете попробовать:
<!DOCTYPE html>
<html lang = "en">
<head>
<meta charset = "UTF-8">
<meta name = "viewport" content = "width=device-width, initial-scale=1.0">
<style>
.display {
position: relative;
width: 400px;
height: 300px;
background-color: gray;
}
.overlay {
position: absolute;
display: flex;
width: 100%;
height: 100%;
top: 0;
left: 0;
flex-direction: column;
justify-content: flex-end;
align-items: flex-end;
}
.info {
display: none; /* Initially hidden */
flex-shrink: 0;
background-color: orange;
padding: 10px;
max-height: 230px; /* Shrink to content */
}
.info-content-wrapper {
padding: 5px;
overflow-y: auto; /* Scrollable if content exceeds height */
}
.content {
width: 80px;
height: 150px;
background-color: yellow;
}
.controls {
background-color: lightblue;
padding: 5px;
flex: 0 0 auto;
}
</style>
</head>
<body>
<div class = "display">
<div class = "overlay">
<div class = "info">
<button id = "close-info">Close</button>
<div class = "info-content-wrapper">
<div class = "content"></div>
</div>
</div>
<div class = "controls">
<button id = "open-info">Open info</button>
<button id = "increase-height">+</button>
<button id = "decrease-height">-</button>
</div>
</div>
</div>
<script>
const info = document.querySelector(".info");
const content = document.querySelector(".content");
document.querySelector("#open-info").addEventListener("click", () => {
info.style.display = "flex";
});
document.querySelector("#close-info").addEventListener("click", () => {
info.style.display = "none";
});
document.querySelector("#increase-height").addEventListener("click", () => {
content.style.height = `${content.clientHeight + 30}px`;
});
document.querySelector("#decrease-height").addEventListener("click", () => {
content.style.height = `${content.clientHeight - 30}px`;
});
</script>
</body>
</html>
Спасибо за фрагмент! К сожалению, он ведет себя не совсем так, как мне хотелось, потому что контейнер .info
не должен иметь фиксированного max-height
, а вместо этого использовать оставшееся вертикальное пространство.
Просто удалите .info { flex-shrink: 0; }
и добавьте .info { overflow: hidden; }
или .info { min-height: 0 }
, чтобы сделать этот блок сжимаемым:
const info = document.querySelector(".info");
const content = document.querySelector(".content");
document.querySelector("#open-info").addEventListener("click", () => {
info.style.display = "flex";
});
document.querySelector("#close-info").addEventListener("click", () => {
info.style.display = "none";
});
document.querySelector("#increase-height").addEventListener("click", () => {
content.style.height = `${content.clientHeight + 30}px`;
});
document.querySelector("#decrease-height").addEventListener("click", () => {
content.style.height = `${content.clientHeight - 30}px`;
});
.display {
position: relative;
width: 400px;
height: 300px;
background-color: gray;
}
.overlay {
position: absolute;
display: flex;
width: 100%;
height: 100%;
top: 0;
left: 0;
flex-direction: column;
justify-content: flex-end;
align-items: flex-end;
}
.info {
display: flex;
flex-direction: column;
justify-content: flex-end;
align-items: flex-end;
/* flex-shrink: 0; */
background-color: orange;
padding: 10px;
/* max-height: 230px; */
overflow: hidden;
}
.info-content-wrapper {
padding: 5px;
overflow-x: hidden;
overflow-y: auto;
}
.content {
width: 80px;
height: 150px;
background-color: yellow;
}
.controls {
background-color: lightblue;
padding: 5px;
flex: 0 0 auto;
}
<div class = "display">
<div class = "overlay">
<div class = "info">
<button id = "close-info">Close</button>
<div class = "info-content-wrapper">
<div class = "content"></div>
</div>
</div>
<div class = "controls">
<button id = "open-info">Open info</button>
<button id = "increase-height">+</button>
<button id = "decrease-height">-</button>
</div>
</div>
</div>
Спасибо большое, похоже это именно то, что мне нужно! По какой-то причине я не думал, что дело в способности .info
сжиматься, хотя в ретроспективе это кажется совершенно очевидным. Спасибо!
Не могли бы вы уточнить, является ли элемент
<div class = "content">
просто примером заполнителя для самого контента? Другими словами, должно ли что-либо, содержащееся в<div class = "info-content-wrapper">
, быть прокручиваемым, или реальный контент должен быть вложен в элемент<div class = "content">
?