J'ai un site à mettre en place qui a un ratio d'aspect fixe d'environ 16:9
paysage, comme une vidéo.
Je veux qu'il soit centré et développé pour remplir la largeur disponible et la hauteur disponible, mais jamais pour devenir plus grand de chaque côté.
Par exemple:
J'ai étudié deux méthodes:
div
, mais je ne pouvais pas le faire se comporter de la même manière sur les principaux navigateurs. Je sais que vous pouvez le faire facilement avec JS, mais j'aimerais une solution CSS pure.
Des idées?
Il existe maintenant une nouvelle propriété CSS spécifiée pour adresser ceci: object-fit
.
http://docs.webplatform.org/wiki/css/properties/object-fit
La prise en charge des navigateurs fait toujours défaut ( http://caniuse.com/#feat=object-fit ) - fonctionne actuellement dans une certaine mesure dans la plupart des navigateurs, à l'exception de Microsoft - mais, avec le temps, c'est exactement ce qui était requis pour cette question .
Utilisez les nouvelles unités de fenêtres CSSvw
et vh
(largeur de la fenêtre/hauteur de la fenêtre)
Redimensionnez verticalement et horizontalement et vous verrez que l'élément remplira toujours la taille maximale de la fenêtre sans casser le rapport et sans barres de défilement!
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>
Si vous souhaitez utiliser au maximum, par exemple, 90% de la largeur et de la hauteur de la fenêtre: 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>
En outre, le support du navigateur est également très bon: IE9 +, FF, Chrome, Safari- caniuse
Reformulez simplement la réponse de Danield
dans un mixin LESS, pour une utilisation ultérieure:
// 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;
}
Ma question initiale était de savoir comment intégrer à la fois un élément d'aspect fixe, mais l'adapter exactement à l'intérieur d'un conteneur spécifié, ce qui le rend un peu délicat. Si vous voulez simplement qu'un élément individuel maintienne son format d'image, c'est beaucoup plus facile.
La meilleure méthode que j'ai rencontrée est de donner à un élément une hauteur nulle et d'utiliser ensuite un pourcentage de remplissage pour le bas. Le pourcentage de remplissage est toujours proportionnel à la largeur d'un élément et non à sa hauteur, même s'il est supérieur ou inférieur.
Vous pouvez donc attribuer à un élément une largeur en pourcentage dans un conteneur, puis un remplissage pour spécifier le rapport de format ou, en d’autres termes, la relation entre la largeur et la hauteur.
.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;
}
Ainsi, dans l'exemple ci-dessus, l'objet prend 80% de la largeur du conteneur, puis sa hauteur correspond à 56,25% de cette valeur. Si sa largeur était de 160px, le rembourrage du bas correspondrait donc à une hauteur de 90px - un aspect 16: 9.
Le petit problème ici, qui peut ne pas être un problème pour vous, est qu'il n'y a pas d'espace naturel à l'intérieur de votre nouvel objet. Par exemple, si vous devez insérer du texte et que ce texte doit prendre ses propres valeurs de remplissage, vous devez ajouter un conteneur à l'intérieur et spécifier les propriétés qu'il contient.
De plus, les unités vw et vh ne sont pas prises en charge sur certains navigateurs plus anciens. Par conséquent, la réponse acceptée à ma question pourrait ne pas vous être possible et vous devrez peut-être utiliser quelque chose de plus lo-fi.
Utilisez un requête de média CSS@media
avec les unités de fenêtres de vues CSSvw
et vh
pour s'adapter au rapport de format de la fenêtre d'affichage. Cela présente l'avantage de mettre à jour d'autres propriétés, telles que font-size
.
Ce violon illustre le rapport de format fixe de la div et le texte dont l'échelle correspond exactement.
La taille initiale est basée sur toute la largeur:
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;
}
Ensuite, lorsque la fenêtre est plus large que le format d'image souhaité, passez à la hauteur comme mesure de base:
/* 100 * 16/9 = 177.778 */
@media (min-width: 177.778vh) {
div {
height: 100vh;
width: calc(100vh * 16 / 9);
font-size: calc(10vh * 16 / 9);
}
}
Cela ressemble beaucoup au max-width
et au max-height
approche de @Danield, mais plus flexible.
Je comprends que vous ayez demandé à souhaiter une solution spécifique à CSS
. Pour conserver les proportions, vous devrez diviser la hauteur par les proportions souhaitées. 16: 9 = 1,777777777778.
Pour obtenir la hauteur correcte pour le conteneur, vous devez diviser la largeur actuelle par 1,777777777778. Puisque vous ne pouvez pas vérifier la width
du conteneur avec seulement CSS
ou diviser par un pourcentage est CSS
, ceci n'est pas possible sans JavaScript
(à ma connaissance).
J'ai écrit un script de travail qui conservera le format d'image souhaité.
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);
}
}
Vous pouvez utiliser à nouveau function
si vous souhaitez afficher autre chose avec un rapport différent en utilisant
keepAspectRatio(id, width, height);
La réponse de Danield est bonne, mais elle ne peut être utilisée que si la div remplit toute la fenêtre, ou en utilisant un peu de calc
, si la largeur et la hauteur de l'autre contenu de la fenêtre sont connues.
Cependant, en combinant l'astuce margin-bottom
avec la méthode de la réponse susmentionnée, le problème peut être réduit à la simple nécessité de connaître la hauteur de l'autre contenu. Ceci est utile si vous avez un en-tête de hauteur fixe, mais la largeur de la barre latérale, par exemple, n'est pas connue.
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>
Ici, il est dans un jsfiddle en utilisant scss , ce qui le rend plus évident d'où viennent les valeurs.
Basé sur La réponse de Daniel , j'ai écrit ce mix SASS avec interpolation (#{}
) pour l'iframe d'une vidéo youtube qui se trouve dans une boîte de dialogue modale 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}
}
}
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">×</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>
Cela affichera toujours la vidéo sans les parties noires que youtube ajoute à l'iframe lorsque la largeur ou la hauteur n'est pas proportionnelle à la vidéo. Remarques:
$sides-adjustment
est un léger ajustement pour compenser une infime partie de ces parties noires apparaissant sur les côtés;.modal-footer
;.modal-dialog
;.modal-header
.Après de nombreux tests, cela fonctionne parfaitement pour moi maintenant.