Я подготовил простую тестовую веб-страницу на Github (используя файл main.css) для своего вопроса:
В вертикальном макете flexbox я пытаюсь использовать ResizeObserver, чтобы наблюдать за родительским элементом div с помощью flex-grow:1, а затем сохранять соотношение сторон 1:1 на его дочернем элементе холста.
Причина, по которой я пытаюсь сохранить соотношение сторон холста, заключается в том, что в моем реальном приложении холст PixiJS встроен в приложение ReactJS, и если я просто масштабирую элемент холста, чтобы заполнить родительский элемент div, тогда содержимое PixiJS растягивается :
К сожалению, элемент parent
div выталкивает элемент hint
div за нижнюю часть экрана –
Я думаю, что в моем коде не хватает чего-то незначительного, порекомендуйте исправление:
const parentElement = document.getElementById("parent");
const childElement = document.getElementById("child");
const resizeObserver = new ResizeObserver((entries) => {
for (let entry of entries) {
const { width, height } = entry.contentRect;
const minDimension = Math.min(width, height);
console.info(
`parent: ${width} x ${height} -> child: ${minDimension} x ${minDimension}`
);
childElement.style.width = `${minDimension}px`;
childElement.style.height = `${minDimension}px`;
}
});
resizeObserver.observe(parentElement);
html,
body {
margin: 0;
padding: 0;
overflow: hidden;
}
.flexRoot {
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: stretch;
width: 100%;
height: 100vh;
}
/* the parent holds: status, canvas, hint */
.parent {
border: 4px solid red;
flex-grow: 1;
}
canvas {
width: 1020px;
height: 1020px;
background-color: yellow;
border: 4px green dotted;
box-sizing: border-box;
}
.hint,
.status {
background: lightblue;
font-style: italic;
text-align: center;
flex-grow: 0;
}
<div class = "flexRoot">
<div class = "status">Game #1 Score1:Score2</div>
<div class = "parent" id = "parent">
<canvas id = "child"></canvas>
</div>
<div class = "hint">A game hint to do this and that...</div>
</div>
Да, я пробовал, чтобы CSS и элемент холста сохраняли один и тот же жестко запрограммированный размер 1020 x 1020 пикселей. Таким образом, часть холста не отображается в небольших окнах браузера.
Чтобы убедиться, что размер .parent
определяется .flexRoot
вместо #child
, он не должен допускать переполнения:
.parent {
overflow: hidden;
}
Необязательно: холст центрируется с помощью flex
.
const parentElement = document.getElementById("parent");
const childElement = document.getElementById("child");
const resizeObserver = new ResizeObserver((entries) => {
for (let entry of entries) {
const {
width,
height
} = entry.contentRect;
const minDimension = Math.min(width, height);
console.info(
`parent: ${width} x ${height} -> child: ${minDimension} x ${minDimension}`
);
childElement.style.width = `${minDimension}px`;
childElement.style.height = `${minDimension}px`;
}
});
resizeObserver.observe(parentElement);
html,
body {
margin: 0;
padding: 0;
overflow: hidden;
}
.flexRoot {
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: stretch;
width: 100%;
height: 100vh;
}
/* the parent holds: status, canvas, hint */
.parent {
border: 4px solid red;
flex-grow: 1;
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
}
canvas {
width: 1020px;
height: 1020px;
background-color: yellow;
border: 4px green dotted;
box-sizing: border-box;
}
.hint,
.status {
background: lightblue;
font-style: italic;
text-align: center;
flex-grow: 0;
}
<div class = "flexRoot">
<div class = "status">Game #1 Score1:Score2</div>
<div class = "parent" id = "parent">
<canvas id = "child"></canvas>
</div>
<div class = "hint">A game hint to do this and that...</div>
</div>
Спасибо, ваше решение работает отлично, поэтому overflow: hidden;
не позволит родительскому div исчезнуть с экрана? Я только что нашел другое решение: вместо этого установить position: absolute;
для элемента холста. Опубликую это как ответ здесь.
Правильно, расположение absolute
имеет аналогичный эффект: #child
«ускользает» от #parent
и больше не может его растянуть.
Это больше не нарушает макет! 😀 Однако ваш подход мне нравится больше, потому что в нем меньше Javascript-кода.
Не могли бы вы взглянуть на мой дополнительный вопрос? Я добавил горизонтальный гибкий контейнер, и теперь мой макет снова сломан: stackoverflow.com/q/78397794/165071
Похоже, на него уже ответили.
Я нашел решение, установив position: absolute;
для элемента холста, как показано в моем коде ниже:
const parentElement = document.getElementById("parent");
const childElement = document.getElementById("child");
const resizeObserver = new ResizeObserver((entries) => {
for (let entry of entries) {
const { width, height } = entry.contentRect;
const minDimension = Math.min(width, height);
const maxDimension = Math.max(width, height);
const diff = Math.floor((maxDimension - minDimension) / 2);
const paddingLeft = width > height ? diff : 0;
const paddingTop = width < height ? diff : 0;
childElement.style.width = `${minDimension}px`;
childElement.style.height = `${minDimension}px`;
childElement.style.transform = `translate(${paddingLeft}px, ${paddingTop}px)`;
}
});
html,
body {
margin: 0;
padding: 0;
overflow: hidden;
}
.flexRoot {
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: stretch;
height: 100vh;
}
/* the parent holds: status, canvas, hint */
.parent {
border: 4px solid red;
flex: 1;
}
canvas {
position: absolute;
width: 1020px;
height: 1020px;
background-color: yellow;
border: 4px green dotted;
box-sizing: border-box;
}
.hint,
.status {
background: lightblue;
font-style: italic;
text-align: center;
}
<div class = "flexRoot">
<div class = "status">Game #1 Score1:Score2</div>
<div class = "parent" id = "parent">
<canvas id = "child"></canvas>
</div>
<div class = "hint">A game hint to do this and that...</div>
</div>
Встроенный код здесь, на Stackoverflow, по какой-то причине не запускается, но обновленный код на Github работает хорошо...
почему бы не использовать свойство CSS «соотношение сторон: 1;» ?