wake-up-neo.net

Seitenverhältnis von div, aber Füllbreite und -höhe in CSS beibehalten?

Ich habe eine Website, die ein festes Seitenverhältnis von ungefähr 16:9 Landschaft hat, wie ein Video. 

Ich möchte, dass es zentriert und erweitert wird, um die verfügbare Breite und die verfügbare Höhe zu füllen, aber auf keiner Seite größer werden. 

Zum Beispiel:

  1. Bei einer großen und dünnen Seite würde sich der Inhalt über die gesamte Breite erstrecken, während eine proportionale Höhe beibehalten wird.
  2. Eine kurze breite Seite würde den Inhalt über die gesamte Höhe mit proportionaler Breite ausdehnen.

Es gibt zwei Methoden, nach denen ich gesucht habe:

  1. Verwenden Sie ein Bild mit dem richtigen Seitenverhältnis, um einen Container zu erweitern, div, aber ich kann es nicht dazu bringen, dass es sich in den meisten Browsern genauso verhält. 
  2. Einstellen einer proportionalen unteren Auffüllung, die jedoch nur relativ zur Breite funktioniert und die Höhe ignoriert. Mit der Breite wird es immer größer und es werden vertikale Bildlaufleisten angezeigt.

Ich weiß, dass Sie dies mit JS problemlos tun könnten, aber ich hätte gerne eine reine CSS-Lösung.

Irgendwelche Ideen?

95
Henry Gibson

Es wurde jetzt eine neue CSS-Eigenschaft angegeben, um dies zu beheben: object-fit.

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

Browserunterstützung fehlt immer noch etwas ( http://caniuse.com/#feat=object-fit ) - funktioniert derzeit in den meisten Browsern mit Ausnahme von Microsoft in gewissem Umfang - aber mit der Zeit war dies genau das, was für diese Frage erforderlich war .

1
Henry Gibson

Verwenden Sie die neuen CSS-Ansichtsfenster-Einheitenvw und vh (Breite des Ansichtsfensters/Höhe des Ansichtsfensters).

GEIGE

Ändern Sie die Größe in vertikaler und horizontaler Richtung. Sie werden sehen, dass das Element immer die maximale Größe des Ansichtsfensters ausfüllt, ohne das Verhältnis zu beeinträchtigen und ohne Bildlaufleisten.

(PURE) 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>

Wenn Sie maximal 90% Breite und Höhe des Ansichtsfensters verwenden möchten: GEIGE 

* {
  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>

Auch die Browser-Unterstützung ist ziemlich gut: IE9 +, FF, Chrome, Safari- caniuse

237
Danield

Umformulieren Sie einfach die Antwort von Danield in einem LESS-Mixin zur weiteren Verwendung:

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

Meine ursprüngliche Frage dazu war, wie man ein Element mit einem festen Aspekt hat, das aber genau in einen bestimmten Container passt, was es etwas fummelig macht. Wenn Sie einfach möchten, dass ein einzelnes Element das Seitenverhältnis beibehält, ist es viel einfacher. 

Die beste Methode, die ich gefunden habe, besteht darin, einem Element eine Höhe von Null zu geben und dann die prozentuale Auffüllung unten zu verwenden, um ihm die Höhe zu geben. Die prozentuale Auffüllung ist immer proportional zur Breite eines Elements und nicht zu seiner Höhe, selbst wenn die Auffüllung oben oder unten ist. 

W3C Polsterungseigenschaften

Wenn Sie also verwenden, können Sie einem Element eine prozentuale Breite zuweisen, um es in einem Container zu platzieren, und dann das Seitenverhältnis auffüllen, oder anders ausgedrückt, das Verhältnis zwischen Breite und Höhe.

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

Im obigen Beispiel nimmt das Objekt 80% der Containerbreite ein, und seine Höhe beträgt dann 56,25% dieses Werts. Wenn die Breite 160px betrug, war die untere Polsterung und somit die Höhe 90px - ein 16: 9-Aspekt.

Das kleine Problem, das für Sie möglicherweise kein Problem ist, besteht darin, dass sich in Ihrem neuen Objekt kein natürlicher Raum befindet. Wenn Sie beispielsweise Text eingeben müssen und dieser Text seine eigenen Füllwerte verwenden muss, müssen Sie einen Container hinzufügen und die Eigenschaften dort angeben.

Vw- und vh-Einheiten werden auch von einigen älteren Browsern nicht unterstützt. Daher ist die akzeptierte Antwort auf meine Frage für Sie möglicherweise nicht möglich, und Sie müssen möglicherweise etwas mehr Lo-Fi verwenden.

7
Henry Gibson

Verwenden Sie eine CSS-Medienabfrage@media zusammen mit den CSS-Ansichtsfenstereinheitenvw und vh, um das Seitenverhältnis des Ansichtsfensters anzupassen. Dies hat den Vorteil, dass auch andere Eigenschaften wie font-size aktualisiert werden.

Diese Geige zeigt das feste Seitenverhältnis für das div und den Text, der genau mit seiner Skalierung übereinstimmt.

Anfangsgröße basiert auf der vollen Breite:

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

Wenn das Ansichtsfenster breiter als das gewünschte Seitenverhältnis ist, wechseln Sie als Basismaß auf Höhe:

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

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

Dies ist dem max-width- und max-heightAnsatz von @Danield sehr ähnlich, nur flexibler.

6
Paul

Ich verstehe, dass Sie gefragt haben, ob Sie eine CSS-spezifische Lösung wünschen. Um das Seitenverhältnis beizubehalten, müssen Sie die Höhe durch das gewünschte Seitenverhältnis teilen. 16: 9 = 1,777777777778.

Um die korrekte Höhe für den Container zu erhalten, müssen Sie die aktuelle Breite durch 1.777777777778 teilen. Da Sie die width des Containers nicht nur mit CSS prüfen können oder durch einen Prozentsatz dividieren ist CSS, ist dies ohne JavaScript (meines Wissens) nicht möglich.

Ich habe ein Arbeitsskript geschrieben, das das gewünschte Seitenverhältnis beibehält.

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

Sie können die Variable function erneut verwenden, wenn Sie etwas anderes mit einem anderen Verhältnis anzeigen möchten 

keepAspectRatio(id, width, height);
5
MCSharp

Die Antwort von Danield ist gut, aber sie kann nur verwendet werden, wenn das div das gesamte Ansichtsfenster ausfüllt, oder durch Verwendung von calc, wenn Breite und Höhe des anderen Inhalts im Ansichtsfenster bekannt sind.

Durch Kombinieren des margin-bottom-Tricks mit dem Verfahren in der oben genannten Antwort kann das Problem jedoch reduziert werden, indem man nur die Höhe des anderen Inhalts kennen muss. Dies ist nützlich, wenn Sie eine Kopfzeile mit fester Höhe haben, die Breite der Seitenleiste jedoch nicht bekannt ist.

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>

Hier wird jsfiddle mit scss verwendet, was es deutlicher macht, woher die Werte kommen.

1
Cameron Martin

Basierend auf Daniels Antwort habe ich dieses SASS-Mixin mit Interpolation (#{}) für den iframe eines Youtube-Videos geschrieben, der sich in einem modifizierten Bootstrap-Dialog befindet:

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

Verwendungszweck:

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

Dies zeigt immer das Video ohne die schwarzen Teile an, die youtube zum iframe hinzufügt, wenn die Breite oder Höhe nicht proportional zum Video ist. Anmerkungen:

  • $sides-adjustment ist eine geringfügige Anpassung, um einen kleinen Teil dieser schwarzen Teile zu kompensieren, die an den Seiten sichtbar sind.
  • bei Geräten mit geringer Höhe (<480px) nimmt der Standardmodal viel Platz in Anspruch. Ich entschied mich daher für Folgendes:
    1. verstecken Sie den .modal-footer;
    2. passen Sie die Position des .modal-dialog an.
    3. reduzieren Sie die Größe des .modal-header.

Nach vielen Tests funktioniert das jetzt einwandfrei für mich.

0
CPHPython