#html #css
#HTML #css
Вопрос:
Я пытаюсь div
центрировать изображение на экране. У этого div должно быть определенное width
и height
когда оно помещается в доступное пространство окна, но оно должно уменьшаться, чтобы соответствовать, когда доступного пространства окна недостаточно, но также, сохраняя исходное соотношение сторон.
Я просмотрел множество примеров, которые работают для уменьшения width
, но ни один из них не работает для обоих width
и height
не изменяет размер окна.
Вот мой текущий CSS:
* {
border: 0;
padding: 0;
margin: 0;
}
.stage_wrapper {
width: 100vw;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
background: gray;
}
.stage {
width: 960px;
height: 540px;
max-width: 90%;
max-height: 90%;
display: flex;
justify-content: center;
align-items: center;
background: chocolate;
object-fit: contain; /* I know this is for images, it's an example of what I'm looking for */
}
И мой текущий HTML:
<div class="stage_wrapper">
<div class="stage">
<p>Some text</p>
</div>
</div>
Это показывает центрированный div
объект с фиксированным width
значением 960 пикселей и фиксированным height
значением 540 пикселей. Он никогда не должен быть больше этого.
Затем, если я изменю размер своего окна на меньший width
или height
меньший, div
элемент успешно уменьшается — за исключением того, что он не поддерживает исходное соотношение сторон, и это то, что я ищу. Я хочу, чтобы он реагировал на изменения в обоих width
и height
.
Возможно ли это вообще?
Ответ №1:
Свойство aspect-ratio
ref теперь имеет хорошую поддержку, поэтому вы можете использовать приведенное ниже:
body {
height: 100vh;
margin: 0;
display: flex;
justify-content: center;
align-items: center;
background: gray;
}
.stage {
--r: 960 / 540;
aspect-ratio: var(--r);
width:min(90%, min(960px, 90vh*(var(--r))));
display: flex;
justify-content: center;
align-items: center;
background:
/* this gradient is a proof that the ratio is maintained since the angle is fixed */
linear-gradient(30deg,red 50%,transparent 50%),
chocolate;
}
<div class="stage">
<p>Some text</p>
</div>
Старый ответ
Вот идея с использованием модуля просмотра и clamp()
. Это своего рода if else, чтобы проверить, больше или меньше ширина экрана, чем высота (с учетом соотношения), и на основе результата мы выполняем вычисления.
В приведенном ниже коде с есть две переменные cv
, ch
и только одна из них будет равна 1
- Если это
cv
так, то ширина больше, поэтому мы устанавливаем высоту,cv
и ширина будет логически зависеть от этой высотыcv/ratio
- Если это
ch
так, то высота больше, поэтому мы устанавливаем ширину,cv
и высота будет логически зависеть от этой шириныch/ratio
В clamp()
я использую 1vh
/ 1vw
что я умножаю на 90
, что эквивалентно вашему 90%
, чтобы иметь 90vh
/ 90vw
body {
height: 100vh;
margin: 0;
display: flex;
justify-content: center;
align-items: center;
background: gray;
}
.stage {
--r: calc(960 / 540);
--cv: clamp(0px,(100vw - 100vh*var(--r))*10000,1vh);
--ch: clamp(0px,(100vh*var(--r) - 100vw)*10000,1vw);
height: calc((var(--cv) var(--ch)/var(--r)) * 90 );
width: calc((var(--ch) var(--cv)*var(--r)) * 90 );
max-width: 960px;
max-height: 540px; /* OR calc(960px/var(--r)) */
display: flex;
justify-content: center;
align-items: center;
background:
/* this gradient is a proof that the ratio is maintained since the angle is fixed */
linear-gradient(30deg,red 50%,transparent 50%),
chocolate;
}
<div class="stage">
<p>Some text</p>
</div>
Теоретически зажим можно упростить до:
--cv: clamp(0px,(1vw - 1vh*var(--r)),1vh);
--ch: clamp(0px,(1vh*var(--r) - 1vw),1vw);
Но чтобы избежать каких-либо проблем с округлением и не попадать в значения, как 0.x
я считаю, большое значение, чтобы убедиться, что оно всегда будет привязано к 1
, если положительное
Обновить
Похоже, в Firefox есть ошибка, поэтому вот другая версия того же кода:
body {
height: 100vh;
margin: 0;
display: flex;
justify-content: center;
align-items: center;
background: gray;
}
.stage {
--r: calc(960 / 540);
--cv: clamp(0px,(100vw - 100vh*var(--r))*100,90vh);
--ch: clamp(0px,(100vh*var(--r) - 100vw)*100,90vw);
height: calc((var(--cv) var(--ch)/var(--r)) );
width: calc((var(--ch) var(--cv)*var(--r)) );
max-width: 960px;
max-height: 540px; /* OR calc(960px/var(--r)) */
display: flex;
justify-content: center;
align-items: center;
background:
/* this gradient is a proof that the ratio is maintained since the angle is fixed */
linear-gradient(30deg,red 50%,transparent 50%),
chocolate;
}
<div class="stage">
<p>Some text</p>
</div>
Комментарии:
1. Это отлично работает, большое вам спасибо! Этот вид CSS действительно новый для меня. Знаете ли вы, какую обратную совместимость я могу ожидать от этого?
2. @FranciscoZarabozo Я думаю, что только IE будет иметь проблемы с моим кодом, что неудивительно, но у вас не должно быть проблем с другими браузерами. теперь хорошо поддерживаются переменные clamp и CSS.
3. @TemaniAfif Это действительно умно! Однако у меня возникли небольшие проблемы с выполнением кода. Не могли бы вы подробнее рассказать о том, что
--cv
и--ch
есть? Даже определение полных имен переменных помогло бы. Спасибо!4. @LandonSchropp Я уже подробно описываю, что представляют собой обе переменные 🙂 .. имя не имеет значения, я могу называть их
a
иb
. Вам просто нужно понять логику, которую я описываю.5. @TemaniAfif Вы нигде не говорите в своем сообщении, что
--cv
--ch
представляют переменные and . Почему вы выбрали эти имена? Что они означают? Я пытаюсь понять вашу логику, но это сложно, потому что вы не объясняете, почему вы выбираете эти переменные. Было бы проще с четкими именами для ваших переменных. medium.com/coding-skills /…
Ответ №2:
Любое решение, использующее vw
amp; vh
предполагает, что ваш контейнер является областью просмотра. Но что, если вам нужен элемент, в котором почтовые ящики подходят для любого контейнера?
Другими словами, вам нужно поведение object-fit: contain
для элемента, который не является <img>
or <video>
.
Вам нужен контейнер, который центрируется как по вертикали, так и по горизонтали:
#container {
display: flex;
align-items: center;
justify-content: center;
}
и содержащийся в нем объект с фиксированным aspect-ratio
, который растягивается либо на его width
, либо height
на 100%
:
#object {
aspect-ratio: 16/9;
overflow: hidden;
[dimension]: 100%;
}
где [dimension]
width
, если контейнер высокий, и height
в противном случае.
Если вы заранее не знаете, будет ли он высоким или нет, потребуется немного javascript, чтобы проверить высоту и решить, какое измерение растянуть.
function update() {
const isTall = container.clientWidth / container.clientHeight < aspectRatio;
object.style.width = isTall ? '100%' : 'auto';
object.style.height = isTall ? 'auto' : '100%';
}
new ResizeObserver(update).observe(container);
Я не думаю, что это переключение размеров может быть выполнено в чистом CSS без javascript.
Вот демонстрация.
Ответ №3:
Возможно, используйте этот CSS:
.stage_wrapper {
width: 100vw;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
background: gray;
}
.stage {
width: 50vw;
height: 40vw;
max-width: 90%;
max-height: 90%;
display: flex;
justify-content: center;
align-items: center;
background: chocolate;
object-fit: contain; /* I know this is for images, it's an example of what I'm looking for */
}
Вы можете настроить код, если хотите, чтобы он был больше или меньше, но это позволит вашему div иметь фиксированное соотношение сторон.
Комментарии:
1. Похоже, это не работает только при уменьшении высоты окна.