Programming

div의 종횡비를 유지하지만 CSS에서 화면 너비와 높이를 채우시겠습니까?

procodes 2020. 8. 10. 20:58
반응형

div의 종횡비를 유지하지만 CSS에서 화면 너비와 높이를 채우시겠습니까?


16:9동영상처럼 가로 세로 비율이 고정 된 사이트를 모아 놓았습니다 .

나는 그것을 중앙에 놓고 사용 가능한 너비와 사용 가능한 높이를 채우기 위해 확장하고 싶지만 양쪽에서 더 커지지 않도록합니다.

예를 들면 :

  1. 길고 얇은 페이지에는 비례 높이를 유지하면서 전체 너비로 콘텐츠가 늘어납니다.
  2. 짧은 폭의 페이지에는 비례하는 너비로 전체 높이로 콘텐츠가 늘어납니다.

내가 살펴본 두 가지 방법이 있습니다.

  1. 적절한 가로 세로 비율의 이미지를 사용하여 컨테이너를 확장 div했지만 주요 브라우저에서 동일한 방식으로 작동하도록 만들 수 없습니다.
  2. 비례 하단 패딩을 설정하지만 너비에 대해서만 상대적으로 작동하고 높이를 무시합니다. 너비에 따라 계속 커지고 세로 스크롤 막대가 표시됩니다.

JS로 쉽게 할 수 있다는 것을 알고 있지만 순수한 CSS 솔루션을 원합니다.

어떤 아이디어?


새로운 CSS 뷰포트 단위 vwvh(뷰포트 너비 / 뷰포트 높이) 사용

깡깡이

수직 및 수평으로 크기를 조정하면 요소가 비율을 깨지 않고 스크롤바없이 항상 최대 뷰포트 크기를 채운다는 것을 알 수 있습니다!

(순수) 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 */
}

* {
  margin: 0;
  padding: 0;
}
div {
  width: 100vw;
  height: 56.25vw;
  /* 100/56.25 = 1.778 */
  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 */
}
<div></div>

뷰포트의 너비와 높이의 최대 90 %를 사용하려면 : FIDDLE

* {
  margin: 0;
  padding: 0;
}
div {
  width: 90vw;
  /* 90% of viewport vidth */
  height: 50.625vw;
  /* ratio = 9/16 * 90 = 50.625 */
  background: pink;
  max-height: 90vh;
  max-width: 160vh;
  /* 16/9 * 90 = 160 */
  margin: auto;
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
}
<div></div>

또한 브라우저 지원도 꽤 좋습니다 : IE9 +, FF, Chrome, Safari- caniuse


Danield추가 사용을 위해 LESS 믹스 인에서의 답변을 재구성 합니다.

// 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;
}

CSS 뷰포트 단위함께 CSS 미디어 쿼리를 사용하고 뷰포트 의 종횡비에 맞게 조정합니다. 이렇게하면과 같은 다른 속성도 업데이트 할 수 있습니다.@media vwvhfont-size

이 바이올린 은 div의 고정 된 종횡비와 크기가 정확히 일치하는 텍스트를 보여줍니다.

초기 크기는 전체 너비를 기준으로합니다.

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);
  }
}

이것은 @Danield max-widthand max-height 접근 방식매우 유사하며 더 유연합니다.


이것에 대한 나의 원래 질문은 두 가지 모두 고정 된 측면의 요소를 갖는 방법이지만 지정된 컨테이너 내에 정확히 맞추는 방법이었습니다. 개별 요소가 종횡비를 유지하기 만하면 훨씬 쉽습니다.

내가 만난 가장 좋은 방법은 요소에 높이를 0으로 지정한 다음 백분율 padding-bottom을 사용하여 높이를 지정하는 것입니다. 백분율 패딩은 항상 요소의 너비에 비례하며 위쪽 또는 아래쪽 패딩이더라도 높이가 아닙니다.

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;
}

So in the above example the object takes 80% of the container width, and then its height is 56.25% of that value. If it's width was 160px then the bottom padding, and thus the height would be 90px - a 16:9 aspect.

The slight problem here, which may not be an issue for you, is that there is no natural space inside your new object. If you need to put some text in for example and that text needs to take it's own padding values you need to add a container inside and specify the properties in there.

Also vw and vh units aren't supported on some older browsers, so the accepted answer to my question might not be possible for you and you might have to use something more lo-fi.


I understand that you asked that you would like a CSS specific solution. To keep the aspect ratio, you would need to divide the height by the desired aspect ratio. 16:9 = 1.777777777778.

To get the correct height for the container, you would need to divide the current width by 1.777777777778. Since you can't check the width of the container with just CSS or divide by a percentage is CSS, this is not possible without JavaScript (to my knowledge).

I've written a working script that will keep the desired aspect ratio.

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);
    }
}

You can use the function again if you'd like to display something else with a different ratio by using

keepAspectRatio(id, width, height);

There is now a new CSS property specified to address this: object-fit.

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

Browser support is still somewhat lacking (http://caniuse.com/#feat=object-fit) - currently works to some extent in most browsers except Microsoft - but given time it is exactly what was required for this question.


Danield's answer is good, but it can only be used when the div fills the whole viewport, or by using a bit of calc, can be used if the width and height of the other content in the viewport is known.

However, by combining the margin-bottom trick with the method in the aforementioned answer, the problem can be reduced to just having to know the height of the other content. This is useful if you have a fixed height header, but the width of the sidebar, for example, is not known.

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>

Here it is in a jsfiddle using scss, which makes it more obvious where the values come from.


Based on Daniel's answer, I wrote this SASS mixin with interpolation (#{}) for a youtube video's iframe that is inside a Bootstrap modal dialog:

@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}
  }
}

Usage:

.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>

This will always display the video without those black parts that youtube adds to the iframe when the width or height is not proportional to the video. Notes:

  • $sides-adjustment is a slight adjustment to compensate a tiny part of these black parts showing up on the sides;
  • in very low height devices (< 480px) the standard modal takes up a lot of space, so I decided to:
    1. hide the .modal-footer;
    2. adjust the positioning of the .modal-dialog;
    3. reduce the sizes of the .modal-header.

After a lot of testing, this is working flawlessly for me now.

참고URL : https://stackoverflow.com/questions/20590239/maintain-aspect-ratio-of-div-but-fill-screen-width-and-height-in-css

반응형