divのアスペクト比を維持しながら、CSSで画面の幅と高さを塗りつぶしますか?


122

16:9ビデオのように、ほぼ横長に固定されたアスペクト比を持つ、まとめるサイトがあります。

利用可能な幅と利用可能な高さを満たすために、それを中央に配置して拡大させたいですが、どちらの側でも大きくなることはありません。

例えば:

  1. 縦長の薄いページでは、高さを維持しながらコンテンツを全幅に拡大します。
  2. 短い幅のページでは、コンテンツが高さいっぱいに広がり、幅が比例します。

私が見てきた2つの方法があります。

  1. 正しいアスペクト比の画像を使用してコンテナを拡張divしますが、主要なブラウザ間で同じように動作させることができませんでした。
  2. 比例した下パディングを設定しますが、これは幅に対して相対的にのみ機能し、高さは無視します。幅が広くなるにつれて、垂直スクロールバーが表示されます。

私はあなたがJSでこれを非常に簡単に行うことができることを知っています、しかし私は純粋なCSSソリューションが欲しいです。

何か案は?


sitepoint.com/…コンテナーdivをposition: relative (default) height: 0 padding-<top/bottom>: H/W*100%
Ujjwal Singhに

回答:


279

新しいCSSビューポート単位 vwvh(ビューポートの幅/ビューポートの高さ)を使用する

FIDDLE

垂直方向と水平方向のサイズを変更すると、要素は常に比率を壊すことなく、またスクロールバーなしで最大ビューポートサイズを満たします。

(純粋)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、Safari- caniuse


1
これは本当に素晴らしいクリーンなソリューションです。理想的には、少し前にブラウザーサポートを使用することもできます。古いブラウザでは、幅/高さの最小値を設定し、それに設定します-スクロールバーがある場合はそうする
Henry Gibson

8
うーん.. 2日間の作業と無数のユーザーの不満を節約してくれてありがとう。できれば1000以上。
2014年

2
あなたは私をそんなに時間を節約しました。本当にありがとうございました。
ディランガッティ2014

1
残念ながら、最近のiOSバージョンはサポートしていない、またはビューポート単位の壊れた実装を持ちます(vhvwvminvmax)。ただし、メディアクエリを使用してiOSデバイスを対象とする回避策があります。
Tim

1
わたしは、あなたを愛しています。素晴らしい解決策!
グッテンベルク2014

20

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

11

使用するCSSメディアクエリを @media一緒にCSSビューポート単位 vwvhビューポートのアスペクト比に適応します。これには、などの他のプロパティも更新するという利点がありfont-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);
  }
}

これは、への静脈に非常に似ているmax-widthmax-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%です。幅が160pxの場合、下のパディング、つまり高さは90px-16:9アスペクトになります。

ここでの問題ではないかもしれないわずかな問題は、新しいオブジェクトの内部に自然な空間がないことです。たとえば、テキストを入れる必要があり、そのテキストが独自のパディング値を取る必要がある場合は、内部にコンテナーを追加し、そこにプロパティを指定する必要があります。

また、vwユニットとvhユニットは一部の古いブラウザではサポートされていないため、私の質問に対する回答は受け入れられない可能性があり、さらにローファイを使用する必要がある場合があります。


ここで余分なマークアップを使用しないようにするには、:: beforeまたは:: afterを使用して要素を追加し、その要素に0の高さと、オブジェクトの幅との相対的なパディングボトムと、0の独自の幅を指定します。これは同じ効果がありますが、マークアップが少なく、コンテナを必要とせずにオブジェクト領域全体を使用してコンテンツを配置できます。
ヘンリーギブソン

6

あなたがしたいことをあなたが尋ねたことを理解しました CSS特定の解決策アスペクト比を維持するには、高さを目的のアスペクト比で割る必要があります。16:9 = 1.777777777778。

コンテナの正しい高さを取得するには、現在の幅を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が必要です。
Henry Gibson

1
@Henry GibsonスクリプトはChrome、FF、IE、Opera、Safariでテストされています。古いバージョンのブラウザでも、すべてがスムーズに動作し、信頼できます。すべてのブラウザが独自のイベントを発生させます。window.onresizeブラウザがサイズを変更した瞬間に発生します。
MCSharp

エンドユーザーは、開発者と同じくらいブラウザのサイズを変更しないことに
注意


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>

ここでは、scssを使用するjsfiddleにあります。これにより、値の取得元がより明確になります。


0

ダニエルの答えに基づいて、私は#{}ブートストラップモーダルダイアログ内にあるYouTubeビデオのiframeに対して、補間()を使用してこのSASSミックスインを作成しました。

@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がiframeに追加する黒い部分なしでビデオが常に表示されます。ノート:

  • $sides-adjustment 側面に現れるこれらの黒い部分のごく一部を補正するためのわずかな調整です。
  • 高さが非常に低いデバイス(<480px)では、標準のモーダルが多くのスペースを必要とするため、次のようにしました。
    1. 隠す .modal-footerます。
    2. の位置を調整します .modal-dialogます。
    3. のサイズを減らし.modal-headerます。

多くのテストを行った結果、これは現在、問題なく機能しています。


-1

ここでは、div内でも機能する@Danieldソリューションに基づくソリューションを示します。

その例では、Angularを使用していますが、すぐにバニラJSまたは別のフレームワークに移行できます。

主なアイデアは、@ Danieldソリューションを空のiframe内に移動し、iframeウィンドウサイズの変更後に寸法をコピーすることです。

そのiframeは、その親要素と寸法を合わせる必要があります。

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

ここにいくつかのスクリーンショット:

ここに画像の説明を入力してください

ここに画像の説明を入力してください

ここに画像の説明を入力してください

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.