Підтримуйте співвідношення сторін Div, але заповнюйте ширину та висоту екрана в CSS?


122

У мене є веб-сайт, який має фіксований співвідношення сторін приблизно 16:9пейзаж, як на відео.

Я хочу, щоб його було по центру і розширено, щоб заповнити наявну ширину та доступну висоту, але ніколи не збільшуватись з обох боків.

Наприклад:

  1. Висока і тонка сторінка матиме вміст, що розтягується на повну ширину, зберігаючи пропорційну висоту.
  2. Коротка широка сторінка матиме вміст, що розтягується на повну висоту, пропорційну ширину.

Я дивився на два способи:

  1. Використовуйте зображення з правильним співвідношенням сторін, щоб розгорнути контейнер div, але я не міг змусити його поводитися однаково в основних браузерах.
  2. Встановлення пропорційної нижньої прокладки, але це працює лише відносно ширини і ігнорує висоту. Він просто збільшується з шириною і відображає вертикальні смуги прокрутки.

Я знаю, що ви могли зробити це з JS досить легко, але мені хотілося б чистого CSS рішення.

Будь-які ідеї?


sitepoint.com/… Установіть контейнер-div наposition: relative (default) height: 0 padding-<top/bottom>: H/W*100%
Ujjwal Singh

Відповіді:


280

Використовуйте нові одиниці огляду CSS vw та vh(ширина вікна перегляду / висота вікна перегляду)

ПІДМОГА

Змініть розмір вертикально та горизонтально, і ви побачите, що елемент завжди заповнює максимальний розмір вікна перегляду, не порушуючи співвідношення та без смуг прокрутки!

(ЧИСТО) CSS

div
{
    width: 100vw; 
    height: 56.25vw; /* height:width ratio = 9/16 = .5625  */
    background: pink;
    max-height: 100vh;
    max-width: 177.78vh; /* 16/9 = 1.778 */
    margin: auto;
    position: absolute;
    top:0;bottom:0; /* vertical center */
    left:0;right:0; /* horizontal center */
}

Якщо ви хочете використовувати максимум скажімо 90% ширини та висоти вікна перегляду: FIDDLE

Також досить хороша підтримка браузера: IE9 +, FF, Chrome, Safaricaniuse


1
Це дійсно приємне чисте рішення. Я б в ідеалі міг зробити підтримку браузера трохи далі назад. Я думаю, що в старому браузері ви просто матимете мінімальну ширину / висоту і встановите його так - якби у нього були смуги прокрутки, так і буде
Генрі Гібсон

8
Гм .. спасибі за те, що врятували мені 2 дні роботи та нескінченну кількість розладів користувачів. 1000+, якби міг.
Schoening

2
Ви просто заощадили мені стільки часу. Неодмінно дякую
Ділан Геттей

1
На жаль, в останній час IOS версія не підтримує , або зламані реалізації видових одиниць ( vh, vw, vmin, vmax). Однак існує рішення , яке використовує медіа-запити для націлювання на пристрої iOS.
Тім

1
я тебе люблю. чудове рішення!
Гюттемберг

20

Просто переформулюйте Danieldвідповідь у меншій суміші для подальшого використання:

// Mixin for ratio dimensions    
.viewportRatio(@x, @y) {
  width: 100vw;
  height: @y * 100vw / @x;
  max-width: @x / @y * 100vh;
  max-height: 100vh;
}

div {

  // Force a ratio of 5:1 for all <div>
  .viewportRatio(5, 1);

  background-color: blue;
  margin: 0;
  position: absolute;
  top: 0; right: 0; bottom: 0; left: 0;
}

11

Використовуйте мультимедійний запит CSS @media разом із блоками огляду CSS vw та vhадаптуйте до співвідношення сторін вікна перегляду. Це має перевагу в оновленні інших властивостей, як-от font-sizeтеж.

Ця скрипка демонструє фіксований співвідношення сторін для діва та текст, що точно відповідає його масштабу.

Початковий розмір заснований на повній ширині:

div {
  width: 100vw; 
  height: calc(100vw * 9 / 16);

  font-size: 10vw;

  /* align center */
  margin: auto;
  position: absolute;
  top: 0px; right: 0px; bottom: 0px; left: 0px;

  /* visual indicators */
  background:
    url(data:image/gif;base64,R0lGODlhAgAUAIABAB1ziv///yH5BAEAAAEALAAAAAACABQAAAIHhI+pa+EPCwA7) repeat-y center top,
    url(data:image/gif;base64,R0lGODlhFAACAIABAIodZP///yH5BAEAAAEALAAAAAAUAAIAAAIIhI8Zu+nIVgEAOw==) repeat-x left center,
    silver;
}

Потім, коли вікно перегляду більше, ніж бажане співвідношення сторін, перейдіть до висоти як базовий показник:

/* 100 * 16/9 = 177.778 */
@media (min-width: 177.778vh) {
  div {
    height: 100vh;
    width: calc(100vh * 16 / 9);

    font-size: calc(10vh * 16 / 9);
  }
}

Це дуже подібне до max-widthта max-height підходу від @Danield, просто більш гнучким.


7

Моє первісне запитання для цього полягало в тому, як обидва мають елемент фіксованого аспекту, але точно вписати його в зазначений контейнер, що робить його трохи непомітним. Якщо ви просто хочете, щоб окремий елемент підтримував співвідношення сторін, це набагато простіше.

Найкращий спосіб, який я натрапив, - це надати елементу нульову висоту, а потім використати відсоткове нижнє дно, щоб надати йому висоту. Відсоток прокладки завжди пропорційний ширині елемента, а не його висоті, навіть якщо його верхній або нижній накладки.

Властивості прокладки W3C

Таким чином, використовуючи, що ви можете надати елементу процентну ширину, щоб він сидів у контейнері, а потім набивання, щоб вказати співвідношення сторін або, іншими словами, співвідношення між його шириною та висотою.

.object {
    width: 80%; /* whatever width here, can be fixed no of pixels etc. */
    height: 0px;
    padding-bottom: 56.25%;
}
.object .content {
    position: absolute;
    top: 0px;
    left: 0px;
    height: 100%;
    width: 100%;
    box-sizing: border-box;
    -moz-box-sizing: border-box;
    padding: 40px;
}

Так у наведеному вище прикладі об'єкт займає 80% ширини контейнера, і тоді його висота становить 56,25% від цього значення. Якби ширина була 160 пікселів, то нижня підкладка, і, таким чином, висота буде 90 пікселів - це аспект 16: 9.

Тут невелика проблема, яка може не бути проблемою для вас, полягає в тому, що всередині вашого нового об’єкта немає природного простору. Якщо вам потрібно прикласти якийсь текст, наприклад, і цей текст повинен приймати власні значення вкладок, вам потрібно додати контейнер всередину і вказати там властивості.

Також vw та vh одиниці не підтримуються у деяких старих браузерах, тому прийнята відповідь на моє запитання може бути неможливою для вас, і вам, можливо, доведеться використовувати щось більш lo-fi.


Щоб уникнути використання додаткової розмітки тут, ви можете додати елемент, використовуючи :: до або :: після, і надати цьому елементу висоту 0 та нижню частину подушки відносно ширини об'єктів та 0 власної ширини. Це матиме такий же ефект, але з меншою розміткою, і зробить повну область об'єкта корисною для розміщення вмісту, не потребуючи контейнера.
Генрі Гібсон

6

Я розумію, що ви запитували, що вам хотілося б CSSконкретного рішення. Щоб зберегти співвідношення сторін, вам потрібно розділити висоту на потрібне співвідношення сторін. 16: 9 = 1,7777777777778.

Щоб отримати правильну висоту для контейнера, вам слід розділити поточну ширину на 1.777777777778. Оскільки ви не можете перевірити widthконтейнер на справедливий CSSабо розділити на відсоток CSS, це неможливо без JavaScript( наскільки мені відомо).

Я написав робочий сценарій, який збереже бажане співвідношення сторін.

HTML

<div id="aspectRatio"></div>

CSS

body { width: 100%; height: 100%; padding: 0; margin: 0; }
#aspectRatio { background: #ff6a00; }

JavaScript

window.onload = function () {
    //Let's create a function that will scale an element with the desired ratio
    //Specify the element id, desired width, and height
    function keepAspectRatio(id, width, height) {
        var aspectRatioDiv = document.getElementById(id);
        aspectRatioDiv.style.width = window.innerWidth;
        aspectRatioDiv.style.height = (window.innerWidth / (width / height)) + "px";
    }

    //run the function when the window loads
    keepAspectRatio("aspectRatio", 16, 9);

    //run the function every time the window is resized
    window.onresize = function (event) {
        keepAspectRatio("aspectRatio", 16, 9);
    }
}

Ви можете використовувати functionще раз, якщо хочете відобразити щось інше з іншим співвідношенням, використовуючи

keepAspectRatio(id, width, height);

Дякую за вашу відповідь. Робити це за сценарієм досить просто, але я дуже хотів рішення на основі CSS. Я хочу по-справжньому швидкого надійного чуйного рішення, і я вважаю, що події зміни розміру часом у різних браузерах трохи відстають. Ви перетворюєте свою трансформацію трохи після того, як змінився розмір браузера, тому це не дає найкращого досвіду користувача. Хочете щось, що відображає момент, коли браузер змінює розмір, отже, чистий CSS.
Генрі Гібсон

1
@Henry Gibson Сценарій був протестований у Chrome, FF, IE, Opera та Safari. Всі працюють швидко і надійно навіть у старих версіях браузерів. Кожен браузер запускає власні події. window.onresizeзапускається в момент, коли браузер змінює розмір.
MCSharp

пам’ятайте, що кінцеві користувачі не
змінюють

3

Існує тепер новий CSS властивість , певне для вирішення цієї проблеми : object-fit.

http://docs.webplatform.org/wiki/css/properties/object-fit

Підтримки веб-переглядачів все ще дещо бракує ( http://caniuse.com/#feat=object-fit ) - наразі працює певною мірою в більшості браузерів, окрім Microsoft, - але для цього питання саме це було потрібно для цього питання.


1

Відповідь Даніельда хороша, але її можна використовувати лише тоді, коли div заповнить весь огляд або за допомогою трохиcalc , можна використовувати, якщо ширина та висота іншого вмісту у вікні перегляду відомі.

Однак, поєднуючи margin-bottomхитрість із методом у вищезгаданій відповіді, проблему можна звести до просто необхідності знати висоту іншого вмісту. Це корисно, якщо у вас заголовок фіксованої висоти, але ширина бічної панелі, наприклад, не відома.

body {
  margin: 0;
  margin-top: 100px; /* simulating a header */
}

main {
  margin: 0 auto;
  max-width: calc(200vh - 200px);
}

section {
  padding-bottom: 50%;
  position: relative;
}

div {
  position:absolute;
  background-color: red;
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
}
<main>
  <section>
    <div></div>
  </section>
</main>

Ось він знаходиться у jsfiddle з використанням scss , що робить більш очевидним, звідки беруться значення.


0

На основі відповіді Даніеля я написав цю комбінацію SASS з інтерполяцією ( #{}) для iframe відео YouTube, який знаходиться у модальному діалоговому вікні Bootstrap:

@mixin responsive-modal-wiframe($height: 9, $width: 16.5,
                                $max-w-allowed: 90, $max-h-allowed: 60) {
  $sides-adjustment: 1.7;

  iframe {
    width: #{$width / $height * ($max-h-allowed - $sides-adjustment)}vh;
    height: #{$height / $width * $max-w-allowed}vw;
    max-width: #{$max-w-allowed - $sides-adjustment}vw;
    max-height: #{$max-h-allowed}vh;
  }

  @media only screen and (max-height: 480px) {
    margin-top: 5px;
    .modal-header {
      padding: 5px;
      .modal-title {font-size: 16px}
    }
    .modal-footer {display: none}
  }
}

Використання:

.modal-dialog {
  width: 95vw; // the modal should occupy most of the screen's available space
  text-align: center; // this will center the titles and the iframe

  @include responsive-modal-wiframe();
}

HTML:

<div class="modal">
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
        <h4 class="modal-title">Video</h4>
      </div>
      <div class="modal-body">
        <iframe src="https://www.youtube-nocookie.com/embed/<?= $video_id ?>?rel=0" frameborder="0"
          allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture"
          allowfullscreen></iframe>
      </div>
      <div class="modal-footer">
        <button class="btn btn-danger waves-effect waves-light"
          data-dismiss="modal" type="button">Close</button>
      </div>
    </div>
  </div>
</div>

Це завжди буде відображати відео без тих чорних частин, які youtube додає до рамки кадрів, коли ширина чи висота не пропорційні відео. Примітки:

  • $sides-adjustment - це невелике регулювання для компенсації крихітної частини цих чорних деталей, що з’являються з боків;
  • у пристроях дуже малої висоти (<480 пікселів) стандартний модал займає багато місця, тому я вирішив:
    1. приховати .modal-footer;
    2. регулювати позиціонування .modal-dialog;
    3. зменшити розміри .modal-header .

Після багатьох тестів це зараз для мене працює бездоганно.


-1

тут рішення, засноване на рішенні @Danield, яке працює навіть у діві.

У цьому прикладі я використовую Angular, але він може швидко перейти до ванільної JS або іншої основи.

Основна ідея - просто перемістити рішення @Danield у порожній кадр iframe та скопіювати розміри після зміни розміру вікна iframe.

Ця рамка повинна відповідати розмірам з її батьківським елементом.

https://stackblitz.com/edit/angular-aspect-ratio-by-iframe?file=src%2Findex.html

Ось кілька скріншотів:

введіть тут опис зображення

введіть тут опис зображення

введіть тут опис зображення

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.