Maintenir le ratio d'aspect d'un div avec CSS

je veux créer un div qui peut changer sa largeur/hauteur que la largeur de la fenêtre change.

y a-t-il des règles CSS3 qui permettraient à la hauteur de changer en fonction de la largeur, tout en maintenant son format ?

je sais que je peux le faire via JavaScript, mais je préférerais utiliser seulement CSS.

div keeping aspect ratio according to width of window

826
demandé sur Cees Timmerman 2009-09-30 03:11:05

19 réponses

il suffit de créer un emballage <div> avec une valeur en pourcentage pour padding-bottom , comme ceci:

div {
  width: 100%;
  padding-bottom: 75%;
  background: gold; /** <-- For the demo **/
}
<div></div>

il en résultera un <div> avec une hauteur égale à 75% de la largeur de son conteneur (un rapport d'aspect 4:3).

cela repose sur le fait que pour le rembourrage:

Le pourcentage est calculé par rapport à la largeur de la boîte du bloc contenant [...] (source: w3.org , c'est moi qui souligne)

Padding-bottom valeurs pour les autres ratios d'aspect et de 100% de la largeur :

aspect ratio  | padding-bottom value
--------------|----------------------
    16:9      |       56.25%
    4:3       |       75%
    3:2       |       66.66%
    8:5       |       62.5%

placer le contenu dans la div:

afin de conserver le format d'image de la div et d'empêcher son contenu de l'étirer, vous devez ajouter un absolument positionné enfant et l'étirer aux bords de l'emballage avec:

div.stretchy-wrapper {
  position: relative;
}

div.stretchy-wrapper > div {
  position: absolute;
  top: 0; bottom: 0; left: 0; right: 0;
}

Voici une démo et une autre " plus en profondeur démo

1112
répondu Web_Designer 2018-09-30 05:17:02

vw unités:

vous pouvez utiliser vw pour les unités largeur et hauteur de l'élément. Cela permet de conserver le rapport d'aspect de l'élément, basé sur la largeur du support.

vw: 1 / 100ème de la largeur du viewport. [ MDN ]

vous pouvez également utiliser vh pour la hauteur du viewport, ou même vmin / vmax pour utiliser la plus petite/plus grande des dimensions du viewport (discussion ici ).

exemple: rapport d'aspect 1: 1

div {
  width: 20vw;
  height: 20vw;
  background: gold;
}
<div></div>

Pour les autres formats, vous pouvez utiliser le tableau suivant pour calculer la valeur de la hauteur en fonction de la largeur de l'élément :

aspect ratio  |  multiply width by
-----------------------------------
     1:1      |         1
     1:3      |         3
     4:3      |        0.75
    16:9      |       0.5625

exemple: grille 4x4 de square divs

body {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
}
div {
  width: 23vw;
  height: 23vw;
  margin: 0.5vw auto;
  background: gold;
}
<div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div>

voici un Fiddle avec cette démo et voici une solution pour faire un grille responsive De carrés avec le contenu verticaly et horizontalement centré .


prise en charge du Navigateur pour vh/vw unités est IE9+ voir canIuse pour plus d'info

337
répondu web-tiki 2017-09-10 03:40:11

j'ai trouvé un moyen de faire cela en utilisant CSS, mais vous devez être prudent car il peut changer selon le flux de votre propre site web. Je l'ai fait afin d'intégrer la vidéo avec un rapport d'aspect constant dans une partie de la largeur fluide de mon site web.

dites que vous avez une vidéo intégrée comme celle-ci:

<object>
     <param ... /><param ... />...
     <embed src="..." ...</embed>
</object>

vous pourriez alors placer tout cela à l'intérieur d'une div avec une classe" vidéo". Cette classe de vidéo sera probablement l'élément fluide de votre site web tel que, par lui-même, il n'a pas de contraintes directes de hauteur, mais quand vous redimensionnez le navigateur, il va changer en largeur en fonction du flux du site web. Ce serait l'élément que vous essayez probablement d'obtenir votre vidéo embarquée dans tout en maintenant un certain format ratio de la vidéo.

pour ce faire, j'ai placé une image avant l'objet embarqué dans la classe" video " div.

!!! La partie importante est que l'image a le correct rapport d'aspect que vous souhaitez maintenir. Aussi, assurez-vous que la taille de l'image est au moins aussi grande que la plus petite que vous attendez de la vidéo (ou ce que vous maintenez le A. R. de) pour obtenir basé sur votre mise en page. Cela évitera tout problème potentiel dans la résolution de l'image lorsqu'elle est redimensionnée en pourcentage. Par exemple, si vous souhaitez maintenir un rapport d'aspect de 3:2, Ne vous contentez pas d'utiliser une image 3px par 2px. Il peut fonctionner dans certaines circonstances, mais je ne l'ai pas testé, et il serait sans doute bonne idée pour éviter.

vous devriez probablement déjà avoir une largeur minimale comme ceci défini pour les éléments fluides de votre site web. Si non, c'est une bonne idée de le faire afin d'éviter de découper des éléments ou d'avoir chevauchement lorsque la fenêtre du navigateur est trop petit. Il est préférable d'avoir une barre de défilement à un moment donné. Le plus petit dans la largeur une page web devrait obtenir est quelque part autour de ~ 600px (y compris les colonnes de largeur fixe) parce que les résolutions d'écran ne viennent pas plus petit à moins vous avez affaire à des sites téléphoniques conviviaux. !!!

j'utilise un png complètement transparent, mais je ne pense pas que cela finisse par avoir de l'importance si vous le faites correctement. Comme ceci:

<div class="video">
     <img class="maintainaspectratio" src="maintainaspectratio.png" />
     <object>
          <param ... /><param ... />...
          <embed src="..." ...</embed>
     </object>
</div>

Maintenant, vous devriez être en mesure d'ajouter CSS similaire à ce qui suit:

div.video { ...; position: relative; }
div.video img.maintainaspectratio { width: 100%; }
div.video object { position: absolute; top: 0px; left: 0px; width: 100%; height: 100%; }
div.video embed {width: 100%; height: 100%; }

assurez-vous que vous supprimez également toute déclaration explicite de hauteur ou de largeur à l'intérieur de l'objet et les étiquettes intégrées qui sont habituellement fournies avec le code de copie/d'intégration collé.

la façon dont il fonctionne dépend des propriétés de position de l'élément de classe vidéo et l'élément que vous voulez avoir maintenir un certain rapport d'aspect. Il tire profit de la façon dont une image maintiendra son bon rapport d'aspect lorsqu'elle est redimensionnée dans un élément. Il indique à tout ce qui est dans l'élément video class de profiter pleinement de l'immobilier fourni par l'image dynamique en forçant sa largeur/hauteur à 100% de l'élément video class étant ajusté par l'image.

Plutôt cool, hein?

Vous pourriez avoir à jouer avec elle un peu pour qu'il fonctionne avec votre propre conception, mais cela fonctionne étonnamment bien pour moi. L'idée générale est là.

25
répondu forgo 2014-05-26 04:53:38

pour ajouter à la réponse de Web_Designer, le <div> aura une hauteur (entièrement composée de rembourrage de fond) de 75% de la largeur de son contenant l'élément . Voici un bon résumé: http://mattsnider.com/css-using-percent-for-margin-and-padding / . Je ne sais pas pourquoi il devrait en être ainsi, mais c'est comment il est.

si vous voulez que votre div soit une largeur autre que 100%, vous avez besoin d'un autre div d'enrubannage largeur:

div.ar-outer{
    width: 60%; /* container; whatever width you want */
    margin: 0 auto; /* centered if you like */
}
div.ar {
    width:100%; /* 100% of width of container */
    padding-bottom: 75%; /* 75% of width of container */
    position:relative;
}
div.ar-inner {
    position: absolute;
    top: 0; bottom: 0; left: 0; right: 0;
}

j'ai utilisé quelque chose de similaire au truc de L'image D'Elliot récemment pour me permettre d'utiliser les requêtes médias CSS pour servir un fichier logo différent en fonction de la résolution de l'appareil, mais encore échelle proportionnellement comme un <img> ferait naturellement (je mets le logo comme image de fond à un transparent .png avec le bon rapport d'aspect). Mais la solution de Web_Designer m'économiserait une requête http.

13
répondu nabrown78 2012-05-06 17:35:13

Elliot m'a inspiré cette solution-merci:

aspectratio.png est un fichier PNG complètement transparent avec la taille de votre format préféré, dans mon cas 30x10 pixels.

HTML

<div class="eyecatcher">
  <img src="/img/aspectratio.png"/>
</div>

CSS3

.eyecatcher img {
  width: 100%;
  background-repeat: no-repeat;
  background-size: 100% 100%;
  background-image: url(../img/autoresized-picture.jpg);
}

s'il vous Plaît note: background-size est un css3-fonction qui pourrait ne pas fonctionner avec votre cible-les navigateurs. Vous pouvez vérifier l'interopérabilité (f.e. sur caniuse.com ).

13
répondu florianb 2014-05-13 14:09:25

comme indiqué dans ici w3schools.com et quelque peu répété dans ce réponse acceptée , valeurs de remplissage en pourcentages (je souligne):

indique le rembourrage en pourcentage de la largeur du contenant l'élément

Ergo, un exemple correct d'un DIV responsive qui conserve un format 16:9 est le suivant:

CSS

.parent {
    position: relative;
    width: 100%;
}
.child {
    position: relative;
    padding-bottom: calc(100% * 9 / 16);
}
.child > div {
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
}

HTML

<div class="parent">
    <div class="child">
        <div>Aspect is kept when resizing</div>
    </div>
</div>

Démo sur JSFiddle

10
répondu Marc A 2017-05-23 12:03:09

en me basant sur vos solutions, j'ai fait un truc:

lorsque vous l'utilisez, votre HTML ne sera que

<div data-keep-ratio="75%">
    <div>Main content</div>
</div>

pour l'utiliser de cette façon faire: CSS:

*[data-keep-ratio] {
    display: block;
    width: 100%;
    position: relative;
}
*[data-keep-ratio] > * {
    position: absolute;
    left: 0;
    right: 0;
    top: 0;
    bottom: 0;
}

et js (jQuery)

$('*[data-keep-ratio]').each(function(){ 
    var ratio = $(this).data('keep-ratio');
    $(this).css('padding-bottom', ratio);
});

et ayant ceci vous venez de mettre attr data-keep-ratio à hauteur/largeur et c'est tout.

9
répondu pie6k 2016-10-17 07:24:03

vous pouvez utiliser un svg. Rendre la position du conteneur/de l'enveloppe relative, placer le svg d'abord en position statique, puis placer le contenu en position absolue (haut: 0; gauche:0; droite: 0; bas:0;)

exemple avec des proportions 16: 9:

de l'image.svg: (peut être inliné dans src)

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 9" width="16" height="9"/>

CSS:

.container {
  position: relative;
}
.content {
  position: absolute;
  top:0; left:0; right:0; bottom:0;
}

HTML:

<div class="container">
  <img style="width: 100%" src="image.svg" />
  <div class="content"></div>
</div>

notez que inline svg ne semble pas fonctionne, mais vous pouvez urlencode le svg et l'intégrer dans l'attribut img src comme ceci:

<img src="data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2016%209%22%20width%3D%2216%22%20height%3D%229%22%2F%3E" style="width: 100%;" />
6
répondu Maciej Krawczyk 2016-10-05 05:38:03

Comme @web-tiki montrent déjà une façon d'utiliser vh / vw , j'ai aussi besoin d'un moyen de centrer dans l'écran, voici un code d'extrait pour 9:16 portrait.

.container {
  width: 100vw;
  height: calc(100vw * 16 / 9);
  transform: translateY(calc((100vw * 16 / 9 - 100vh) / -2));
}

translateY gardera ce centre dans l'écran. calc(100vw * 16 / 9) est la hauteur prévue pour 9/16. (100vw * 16 / 9 - 100vh) est la hauteur de débordement, donc, tirer vers le haut overflow height/2 le gardera au centre de l'écran.

Pour le paysage, et de garder 16:9 , vous montrez utilisation

.container {
  width: 100vw;
  height: calc(100vw * 9 / 16);
  transform: translateY(calc((100vw * 9 / 16 - 100vh) / -2));
}

le rapport 9/16 est facile à changer, pas besoin de prédéfini 100:56.25 ou 100:75 .Si vous voulez vous assurer de la hauteur d'abord, vous devez changer la largeur et la hauteur, par exemple height:100vh;width: calc(100vh * 9 / 16) pour 9:16 portrait.

si vous souhaitez adapter pour différentes tailles d'écran, vous pouvez également intérêt

  • background-size cover / contain
    • style ci-dessus est similaire à contenir, dépend du rapport largeur: hauteur.
  • object-fit
    • couvrir/pour contenir img/vidéo tag
  • @media (orientation: portrait) / @media (orientation: landscape)
    • requête média pour portrait / landscape pour changer le rapport.
5
répondu wener 2017-11-01 02:40:25

SCSS est la meilleure solution dans mon cas; en utilisant un attribut de données:

[data-aspect-ratio] {
    display: block;
    max-width: 100%;
    position: relative;

    &:before {
        content: '';
        display: block;
    }

    > * {
        display: block;
        height: 100%;
        left: 0;
        position: absolute;
        top: 0;
        width: 100%;
    }
}
[data-aspect-ratio="3:1"]:before {
    padding-top: 33.33%;
}
[data-aspect-ratio="2:1"]:before {
    padding-top: 50%;
}
[data-aspect-ratio="16:9"]:before {
    padding-top: 56.25%;
}
[data-aspect-ratio="3:2"]:before {
    padding-top: 66.66%;
}
[data-aspect-ratio="4:3"]:before {
    padding-top: 75%;
}
[data-aspect-ratio="1:1"]:before {
    padding-top: 100%;
}
[data-aspect-ratio="3:4"]:before {
    padding-top: 133.33%;
}
[data-aspect-ratio="2:3"]:before {
    padding-top: 150%;
}
[data-aspect-ratio="9:16"]:before {
    padding-top: 177.77%;
}
[data-aspect-ratio="1:2"]:before {
    padding-top: 200%;
}
[data-aspect-ratio="1:3"]:before {
    padding-top: 300%;
}

par exemple:

<div data-aspect-ratio="16:9"><iframe ...></iframe></div>

source

3
répondu gordie 2015-10-23 11:18:14

disons que vous avez 2 divs l'autre div est un conteneur et l'intérieur pourrait être n'importe quel élément dont vous avez besoin pour garder son ratio (img ou une iframe youtube ou autre)

html ressemble à ceci:

<div class='container'>
  <div class='element'>
  </div><!-- end of element -->

permet de dire que vous avez besoin de garder le ratio de l '" élément

ratio = > 4 pour 1 ou 2 pour 1 ...

css ressemble à ce

.container{
  position: relative;
  height: 0
  padding-bottom : 75% /* for 4 to 3 ratio */ 25% /* for 4 to 1 ratio ..*/

}

.element{
  width : 100%;
  height: 100%;
  position: absolute; 
  top : 0 ;
  bottom : 0 ;
  background : red; /* just for illustration */
}

rembourrage lorsqu'il est spécifié en%, il est calculé sur la base de la largeur et non de la hauteur. .. donc, fondamentalement, vous, il n'a pas d'importance ce que votre largeur hauteur sera toujours calculé en fonction de cela . qui va garder les proportions .

3
répondu aeid 2016-09-15 02:04:36

juste une idée ou un piratage.

div {
  background-color: blue;
  width: 10%;
  transition: background-color 0.5s, width 0.5s;
  font-size: 0;
}

div:hover {
  width: 20%;
  background-color: red;
}
  
img {
  width: 100%;
  height: auto;
  visibility: hidden;
}
<div>
  <!-- use an image with target aspect ratio. sample is a square -->
  <img src="http://i.imgur.com/9OPnZNk.png" />
</div>
2
répondu Orland 2015-09-30 15:52:56

j'ai rencontré cette question plusieurs fois, donc j'ai fait une solution JS pour elle. Cela ajuste la hauteur du dôme en fonction de la largeur de l'élément par le rapport que vous spécifiez. Vous pouvez l'utiliser comme suit:

<div ratio="4x3"></div>

veuillez noter que puisqu'il fixe la hauteur de l'élément, l'élément doit être un display:block ou display:inline-block .

https://github.com/JeffreyArts/html-ratio-component

2
répondu user007 2017-04-13 21:44:27

alors que la plupart des réponses sont très cool, la plupart d'entre eux exigent d'avoir une image déjà dimensionnée correctement... Les autres solutions ne fonctionnent que pour une largeur et ne se soucient pas de la hauteur disponible, mais parfois vous voulez ajuster le contenu dans une certaine hauteur.

j'ai essayé de les coupler ensemble pour apporter une solution entièrement portable et re-sizable... Le truc est d'utiliser l'échelle automatique d'une image mais d'utiliser un élément svg en ligne au lieu d'utiliser une image pré-rendue ou n'importe quel autre la forme de la deuxième requête HTTP...

div.holder{
  background-color:red;
  display:inline-block;
  height:100px;
  width:400px;
}
svg, img{
  background-color:blue;
  display:block;
  height:auto;
  width:auto;
  max-width:100%;
  max-height:100%;
}
.content_sizer{
  position:relative;
  display:inline-block;
  height:100%;
}
.content{
  position:absolute;
  top:0;
  bottom:0;
  left:0;
  right:0;
  background-color:rgba(155,255,0,0.5);
}
<div class="holder">
  <div class="content_sizer">
    <svg width=10000 height=5000 />
    <div class="content">
    </div>
  </div>
</div>

notez que j'ai utilisé de grandes valeurs dans les attributs width et height de la SVG, car il doit être plus grand que la taille maximale prévue car il ne peut que rétrécir. L'exemple fait le rapport de div 10:5

1
répondu Salketer 2017-03-08 07:18:23

si vous voulez ajuster un carré à l'intérieur du viewport sur le portrait ou le paysage (aussi grand que possible, mais rien de collant à l'extérieur), basculer entre vw / vh sur l'orientation portrait / landscape :

@media (orientation:portrait ) {
  .square {
    width :100vw;
    height:100vw;
  }
} 
@media (orientation:landscape) {
  .square {
    width :100vh;
    height:100vh;
  }
} 
1
répondu MoonLite 2017-06-16 13:07:16

il s'agit d'une amélioration par rapport à la réponse acceptée:

  • utilise des pseudo-éléments au lieu de divs wrapper
  • le rapport d'aspect est basé sur la largeur de la boîte au lieu de son parent
  • la boîte s'étirera verticalement lorsque le contenu deviendra plus haut

.box {
  margin-top: 1em;
  margin-bottom: 1em;
  background-color: #CCC;
}

.fixed-ar::before {
  content: "";
  float: left;
  width: 1px;
  margin-left: -1px;
}
.fixed-ar::after {
  content: "";
  display: table;
  clear: both;
}

.fixed-ar-16-9::before {
  padding-top: 56.25%;
}
.fixed-ar-3-2::before {
  padding-top: 66.66%;
}
.fixed-ar-4-3::before {
  padding-top: 75%;
}
.fixed-ar-1-1::before {
  padding-top: 100%;
}

.width-50 {
  display: inline-block;
  width: 50%;
}
.width-20 {
  display: inline-block;
  width: 20%;
}
<div class="box fixed-ar fixed-ar-16-9">16:9 full width</div>
<hr>
<div class="box fixed-ar fixed-ar-16-9 width-50">16:9</div>
<hr>
<div class="box fixed-ar fixed-ar-16-9 width-20">16:9</div>
<div class="box fixed-ar fixed-ar-3-2 width-20">3:2</div>
<div class="box fixed-ar fixed-ar-4-3 width-20">4:3</div>
<div class="box fixed-ar fixed-ar-1-1 width-20">1:1</div>
<hr>
<div class="box fixed-ar fixed-ar-16-9 width-20">16:9</div>
<div class="box fixed-ar fixed-ar-16-9 width-50">16:9</div>
1
répondu Salman A 2018-07-03 10:20:22

vous pouvez utiliser le flux layout (FWD).

https://en.wikipedia.org/wiki/Adaptive_web_design

il va mettre à l'échelle et maintenir la mise en page, Son un peu complexe, mais permet à une page de redimensionner sans pousser le contenu comme (RWD).

il ressemble à responsive, mais il est d'échelle. https://www.youtube.com/watch?v=xRcBMLI4jbg

vous pouvez trouver le CSS formule d'échelle ici:

http://plugnedit.com/pnew/928-2 /

0
répondu user1410288 2018-04-03 11:47:06

si la structure entière du conteneur était basée sur le pourcentage, ce serait le comportement par défaut, pouvez-vous fournir un exemple plus spécifique?

ci-dessous est un exemple de ce que je veux dire, si votre hiérarchie de parent entière était basée sur le%, n'importe quel ajustement de fenêtre de navigateur fonctionnerait sans n'importe quel js/css supplémentaire, n'est-ce pas une possibilité avec votre layout?

<div style="width: 100%;">
   <div style="width: 50%; margin: 0 auto;">Content</div>
</div>
-1
répondu Nick Craver 2009-09-30 00:52:06

j'ai utilisé une nouvelle solution.

.squares{
  width: 30vw
  height: 30vw

par rapport à l'aspect principal

.aspect-ratio
  width: 10vw
  height: 10vh

cependant, ceci est relatif à l'ensemble du viewport. Donc, si vous avez besoin d'un div qui est 30% de la largeur de viewport, vous pouvez utiliser 30vw à la place, et puisque vous connaissez la largeur, vous les réutilisez en hauteur en utilisant calc et VW unité.

-1
répondu Eshwaren Manoharen 2016-12-15 09:58:17