Как сохранить соотношение сторон 1:1 для дочернего элемента холста?

Я подготовил простую тестовую веб-страницу на 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 «соотношение сторон: 1;» ?

Ji aSH 27.04.2024 15:23

Да, я пробовал, чтобы CSS и элемент холста сохраняли один и тот же жестко запрограммированный размер 1020 x 1020 пикселей. Таким образом, часть холста не отображается в небольших окнах браузера.

Alexander Farber 27.04.2024 15:39
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
2
69
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Чтобы убедиться, что размер .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; для элемента холста. Опубликую это как ответ здесь.

Alexander Farber 27.04.2024 15:49

Правильно, расположение absolute имеет аналогичный эффект: #child «ускользает» от #parent и больше не может его растянуть.

hedfol 27.04.2024 18:24

Это больше не нарушает макет! 😀 Однако ваш подход мне нравится больше, потому что в нем меньше Javascript-кода.

Alexander Farber 27.04.2024 19:00

Не могли бы вы взглянуть на мой дополнительный вопрос? Я добавил горизонтальный гибкий контейнер, и теперь мой макет снова сломан: stackoverflow.com/q/78397794/165071

Alexander Farber 28.04.2024 20:10

Похоже, на него уже ответили.

hedfol 29.04.2024 11:36

Я нашел решение, установив 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 работает хорошо...

Другие вопросы по теме