Conserver le rapport hauteur / largeur d'une div avec CSS


1059

Je veux créer un divqui peut changer sa largeur / hauteur à mesure que la largeur de la fenêtre change.

Existe-t-il des règles CSS3 qui permettraient à la hauteur de changer en fonction de la largeur, tout en conservant son rapport hauteur / largeur ?

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

div gardant le rapport d'aspect en fonction de la largeur de la fenêtre


3
J'ai écrit sur différentes approches à ce sujet dans mon article CSS-Tricks sur la mise
Zach Saucier

2
Je suis venu à ce Q & A très tard, mais je dois commenter. Bien qu'il soit très discipliné et dans les règles SO de tous ceux qui répondent pour faire de leur mieux pour satisfaire la "seule CSS" exigence de la question, il est assez surprenant qu'à l'exception de la réponse de user007 plus bas sur la page, non. on a mentionné l'évidence: il n'existe pas de solution fiable uniquement CSS, ce problème nécessite Javascript. Un débutant venant sur cette page pourrait perdre un temps précieux à passer d'un ensemble d'avantages / inconvénients à un autre avant que l'ampoule ne s'éteigne: CSS uniquement ne suffira pas.
Theo d'Or

1
J'ai écrit un petit outil qui facilite la prévisualisation et le calcul des proportions, aspectrat.io . Il génère également le code CSS / Sass / Less approprié que vous pouvez copier et coller dans vos projets. J'espère que les gens le trouveront utile.
Ryan Hefner

voir cet exemple: w3schools.com/howto/howto_css_aspect_ratio.asp ..... qui m'a fonctionné
Cristian Agudelo

1
Cette question concerne le réglage de la hauteur en fonction de la largeur . Si vous avez besoin du contraire, consultez Définition de la largeur des éléments en fonction de la hauteur via CSS .
John Mellor du

Réponses:


1354

Créez simplement un wrapper <div>avec un pourcentage pour padding-bottom, comme ceci:

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

/* demonstration purposed only : non-essential */
.demoWrapper {
  padding: 10px;
  background: white;
  box-sizing: border-box;
  resize: horizontal;
  border: 1px dashed;
  overflow: auto;
  max-width: 100%;
  height: calc(100vh - 16px);
}
<div class="demoWrapper">
  <div></div>
</div>

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

Cela repose sur le fait que pour le rembourrage:

Le pourcentage est calculé par rapport à la largeur du bloc contenant la boîte générée [...] (source: w3.org , mine d'accent)

Valeurs de remplissage pour d'autres rapports d'aspect et largeur de 100%:

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

Placer du contenu dans la div:

Afin de conserver le rapport d'aspect du div et d'empêcher son contenu de l'étirer, vous devez ajouter un enfant absolument positionné et l'étirer jusqu'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


29
@schellmax, c'est parce que le remplissage% est calculé par rapport à la largeur de l'élément courant, alors que la hauteur% est calculée par rapport à la hauteur de l'élément parent. De plus, les positions absolues sont calculées par rapport au conteneur extérieur d'un élément, qui comprend la zone de rembourrage. Pour plus d'informations Google "CSS Box Model"
Anson Kao

11
Cela ne semble pas fonctionner de manière imbriquée. Cela fonctionne au premier niveau, mais lorsque vous essayez de faire la même chose à l'intérieur du rapport d'aspect de maintien div, le pourcentage de bas de remplissage semble être appliqué à la largeur du parent. voici un exemple où le .stretchy-wrap.onethird padding-bottom de 25% est en fait 25% de la largeur du parent. Quelqu'un peut-il expliquer cela?
Misterparker

4
Absolument génial. Cela me tue que cette technique ne fonctionne pas lorsque vous souhaitez fixer la hauteur à 100%. @Misterparker, la technique repose sur les calculs de largeur et de rembourrage effectués par rapport à la même référence; vous ne pouvez pas utiliser une largeur inférieure à 100%, comme vous l'avez fait dans votre exemple.
steveluscher

2
@Misterparker Oui, le pourcentage de remplissage est calculé proportionnellement à la largeur de l'élément parent. Voir l'exemple plus approfondi que j'ai publié dans une modification de ma réponse. Ma démo mise à jour montre une «mode imbriquée» dont vous parliez.
Web_Designer

3
le fait qu'il ait démontré que cela fonctionne est suffisant pour me convaincre que c'est la meilleure réponse que j'ai jamais vue sur SO. crier à mon homme @Web_Designer

410

vw unités:

Vous pouvez utiliser des vwunités pour la largeur et la hauteur de l'élément. Cela permet de conserver le rapport hauteur / largeur de l'élément, en fonction de la largeur de la fenêtre.

vw: 1 / 100e de la largeur de la fenêtre. [ MDN ]

Alternativement, vous pouvez également utiliser vhpour la hauteur de la fenêtre, ou même vmin/ vmaxpour utiliser la plus petite / plus grande des dimensions de la fenêtre (discussion ici ).

Exemple: rapport d'aspect 1: 1

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

Pour d'autres proportions, 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 divs carrés

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 violon avec cette démo et voici une solution pour faire une grille réactive de carrés avec un contenu centré verticalement et horizontalement .


La prise en charge du navigateur pour les unités vh / vw est IE9 + voir canIuse pour plus d'informations


14
Ce devrait être la réponse acceptée. Peut-être pas maintenant, mais à l'avenir. Les unités vw sont désormais prises en charge dans la plupart des navigateurs .
août

3
@vivekmaharajh les deux techniques sont bonnes, chacune a ses avantages et ses inconvénients. L'utilisation de l'un ou de l'autre dépend grandement de la situation.
web-tiki

11
@ web-tiki, vous avez raison. J'ai rencontré un problème - il suppose que la largeur de l'élément est proportionnelle à la largeur de la fenêtre d'affichage, ce qui ne sera pas le cas si 1) vous avez des choses comme des gouttières à largeur fixe ou 2) vous avez défini la largeur maximale pour certains de vos éléments.
Vivek Maharajh

1
C'est peut-être juste Chrome v47beta, mais quand j'ai réglé le div sur width:50%et height:50vwla hauteur est un peu plus haute que la largeur, donc pas exactement une proportion de 1: 1. Des idées?
thdoan

2
@ 10basetom c'est un comportement normal. Les unités vw contiennent la largeur de la barre de défilement, contrairement à% width. La différence entre la hauteur et la largeur dépendra de la taille de la barre de défilement qui est différente selon le navigateur.
web-tiki du

26

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

Supposons que vous ayez une vidéo intégrée comme celle-ci:

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

Vous pouvez ensuite placer tout cela à l'intérieur d'un div avec une classe "vidéo". Cette classe vidéo sera probablement l'élément fluide de votre site Web de telle sorte qu'elle ne présente pas en soi de contrainte de hauteur directe, mais lorsque vous redimensionnez le navigateur, sa largeur change en fonction du flux du site Web. Ce serait l'élément dans lequel vous essayez probablement d'obtenir votre vidéo intégrée tout en conservant un certain rapport d'aspect de la vidéo.

Pour ce faire, je mets une image avant l'objet intégré dans la classe "video" div.

!!! La partie importante est que l'image a le rapport d'aspect correct que vous souhaitez conserver. Assurez-vous également que la taille de l'image est au moins aussi grande que la plus petite que vous attendez de la vidéo (ou de tout ce que vous conservez l'AR) en fonction de 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 conserver un rapport hauteur / largeur de 3: 2, n'utilisez pas uniquement une image de 3 x 2 pixels. Cela peut fonctionner dans certaines circonstances, mais je ne l'ai pas testé, et ce serait probablement une bonne idée à éviter.

Vous devriez probablement déjà avoir une largeur minimale comme celle-ci définie pour les éléments fluides de votre site Web. Sinon, c'est une bonne idée de le faire afin d'éviter de couper des éléments ou de se chevaucher lorsque la fenêtre du navigateur devient trop petite. Il est préférable d'avoir une barre de défilement à un moment donné. La plus petite largeur qu'une page Web devrait obtenir se situe autour de ~ 600 px (y compris toutes les colonnes de largeur fixe) car les résolutions d'écran ne sont pas plus petites, sauf si vous avez affaire à des sites adaptés aux téléphones. !!!

J'utilise un png complètement transparent mais je ne pense pas vraiment que cela finisse par être important si vous le faites correctement. Comme ça:

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

Vous devriez maintenant pouvoir ajouter du 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 dans l'objet et incorporez les balises qui sont généralement fournies avec le code d'intégration copié / collé.

Le fonctionnement dépend des propriétés de position de l'élément de classe vidéo et de l'élément que vous souhaitez conserver un certain rapport hauteur / largeur. Il tire parti de la façon dont une image conservera son rapport d'aspect approprié lorsqu'elle sera redimensionnée dans un élément. Il indique tout ce qui se trouve dans l'élément de classe vidéo pour tirer pleinement parti de l'immobilier fourni par l'image dynamique en forçant sa largeur / hauteur à 100% de l'élément de classe vidéo ajusté par l'image.

Assez cool, hein?

Vous devrez peut-être jouer avec un peu pour le faire fonctionner avec votre propre design, mais cela fonctionne étonnamment bien pour moi. Le concept général est là.


17

Elliot m'a inspiré cette solution - merci:

aspectratio.png est un fichier PNG complètement transparent avec la taille de votre format d'image 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);
}

Veuillez noter: background-size est une fonctionnalité css3 qui pourrait ne pas fonctionner avec vos navigateurs cibles. Vous pouvez vérifier l'interopérabilité (par exemple sur caniuse.com ).


14

Pour ajouter à la réponse de Web_Designer, le <div>aura une hauteur (entièrement composée de rembourrage inférieur) de 75% de la largeur de son élément contenant . 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 ainsi.

Si vous souhaitez que votre div soit d'une largeur autre que 100%, vous avez besoin d'un autre div enveloppant sur lequel définir la 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 récemment utilisé quelque chose de similaire à l'astuce d'image d'Elliot pour me permettre d'utiliser des requêtes de médias CSS pour servir un fichier de logo différent en fonction de la résolution de l'appareil, mais toujours à l'échelle proportionnellement comme le <img>ferait naturellement (j'ai défini le logo comme image d'arrière-plan sur un .png transparent avec le bon rapport hauteur / largeur). Mais la solution de Web_Designer me sauverait une demande http.


Excellente solution. Dans mon cas, je connais la taille d'image "naturelle" lorsque je la place dans DOM et j'ai besoin d'avoir un espace réservé d'image avec une hauteur appropriée pour empêcher un nouveau défilement une fois que le navigateur charge les images. Dans .ar-externe, j'ai la largeur de l'image en pixels, dans .ar j'ai le fond de remplissage calculé à partir du rapport d'aspect de l'image réelle. Au lieu de ar-inner, j'ai l'image elle-même (<img>). Cependant, j'ai dû régler la largeur à 100% au lieu de définir le haut, le bas, la gauche et la droite. Lorsque je règle maxWidth sur ar-externe, l'image est bien mise à l'échelle lorsque le parent est petit, mais ne se met pas à l'échelle plus grande que sa taille naturelle.
Mi-La

13

Comme indiqué ici sur w3schools.com et quelque peu réitéré dans cette réponse acceptée , les valeurs de remplissage en pourcentages (soulignement le mien):

Spécifie le remplissage en pourcentage de la largeur de l' élément contenant

Ergo, un exemple correct de DIV réactif qui conserve un rapport d'aspect 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


13

Comme @ web-tiki montre déjà un moyen d'utiliser vh/ vw, j'ai également besoin d'un moyen de centrer à 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));
}

translateYgardera ce centre à l'écran. calc(100vw * 16 / 9)est la hauteur attendue pour 9/16. (100vw * 16 / 9 - 100vh)est la hauteur de débordement, donc, tirez vers overflow height/2le haut le gardera au centre de l'écran.

Pour le paysage, et gardez 16: 9 , vous montrez l'utilisation

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

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

Si vous souhaitez vous adapter à différentes tailles d'écran, vous pouvez également être intéressé

  • couverture de taille d'arrière-plan / contenir
    • Le style ci-dessus est similaire au contenu, dépend du rapport largeur: hauteur.
  • ajustement aux objets
    • couvrir / contenir pour img / tag vidéo
  • @media (orientation: portrait)/@media (orientation: landscape)
    • Requête des médias pour portrait/ landscapepour changer le rapport.

11

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

  • Utilise des pseudo-éléments au lieu de diviseurs de wrapper
  • Le rapport hauteur / largeur est basé sur la largeur de la boîte au lieu de son parent
  • La boîte s'étendra verticalement lorsque le contenu devient plus grand

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


comment désactiver l'étirement vertical de la boîte? à proprement parler, un div d'étirement ne maintient pas son rapport d'aspect
florian

Si le contenu est plus grand que la hauteur attendue, la boîte s'étirera verticalement. Cette idée est mieux utilisée avec un contenu qui pourrait s'étirer pour correspondre aux dimensions de ses parents, par exemple des vidéos et des images.
Salman A

10

Je suis tombé sur une solution intelligente en utilisant <svg>et display:grid.

L'élément de grille vous permet d'occuper le même espace avec deux (ou plus) éléments, sans avoir besoin de spécifier lequel définit la hauteur. Ce qui signifie que, hors de la boîte, le plus grand définit le rapport .

Cela signifie que vous pouvez l'utiliser tel quel lorsque vous savez que le contenu ne sera jamais assez grand pour remplir tout le "ratio" et que vous cherchez simplement un moyen de positionner le contenu dans cet espace (c'est-à-dire de le centrer sur les deux directions, utilisez display:flex; align-items:center; justify-content:center).
C'est à peu près la même chose que d'utiliser un rapport transparent <img>avec display:blocket prédéterminé, sauf qu'il <svg>est plus léger et beaucoup plus facile à modifier (pour changer le rapport en conséquence, si vous en avez besoin).

<div class="ratio">
  <svg viewBox="0 0 1 1"></svg>
  <div>
    I'm square
  </div>
</div>
.ratio {
  display: grid;
}
.ratio > * {
  grid-area: 1/1/1/1;
}

Il vous suffit de modifier le <svg>rapport s:

  • <svg viewBox="0 0 4 3"></svg>
  • <svg viewBox="0 0 16 9"></svg>

Voyez-le fonctionner:


Si vous avez besoin d'une solution où l'élément de contenu n'est pas autorisé à définir le rapport lorsqu'il est plus grand (avec débordement masqué ou automatique), vous devez définir position:relativesur la grille et position:absolute; height:100%; overflow-y: auto;sur le contenu. Exemple:


9

Sur la base de vos solutions, j'ai fait quelques trucs:

Lorsque vous l'utilisez, votre code HTML sera uniquement

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

Pour l'utiliser de cette façon, faites: 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 en ayant cela, vous définissez simplement attr data-keep-ratiosur hauteur / largeur et c'est tout.


3
vous ne devriez data-keep-ratiopas utiliser keep-ratioet obtenir sa valeur en utilisant$(this).data('keep-ratio');
Robert

votre code fonctionne maintenant et fonctionnera peut-être pour toujours, mais ce n'est pas standard et les navigateurs peuvent cesser de le prendre en charge à tout moment à l'avenir
Robert

1
L'utilisation de JS ici provoquera de mauvaises nouvelles!
Amir Hossein Ahmadi

8

Vous pouvez utiliser un svg. Rendez la position du conteneur / wrapper relative, placez d'abord le svg comme positionné statiquement, puis mettez le contenu absolument positionné (haut: 0; gauche: 0; droite: 0; bas: 0;)

Exemple avec des proportions 16: 9:

image.svg: (peut être inséré en 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 le svg en ligne ne semble pas fonctionner, mais vous pouvez encoder le svg en url 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%;" />

7

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>

la source


15
Juste pour info ... Vous pouvez faire cette chose exacte (en utilisant des sélecteurs d'attributs) dans exactement le même nombre de lignes en utilisant du CSS simple. Le [data-aspect-ratio]sélecteur d'attributs est à votre disposition en CSS.
rnevius

6

Alors que la plupart des réponses sont très cool, la plupart d'entre elles nécessitent d'avoir une image déjà dimensionnée correctement ... D'autres solutions ne fonctionnent que pour une largeur et ne se soucient pas de la hauteur disponible, mais parfois vous souhaitez également adapter le contenu à une certaine hauteur .

J'ai essayé de les coupler ensemble pour apporter une solution entièrement portable et redimensionnable ... L'astuce consiste à utiliser la mise à l'échelle automatique d'une image mais à utiliser un élément svg en ligne au lieu d'utiliser une image pré-rendue ou toute forme de 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 de largeur et de hauteur du SVG, car il doit être plus grand que la taille maximale attendue car il ne peut que rétrécir. L'exemple fait le rapport de div 10: 5


4

Juste une idée ou un hack.

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>


Ce n'est pas une solution uniquement CSS ... Maintenant, si vous auriez utilisé une image encodée en base64 dans un pseudo-élément, cela aurait été une solution intéressante.
rnevius

1
Il n'y a vraiment pas de solution CSS uniquement. HTML est le composant de base du Web. Je crois que le but de la question est de s'abstenir d'utiliser JS peut-être pour économiser les ressources / le traitement.
orlland

Je ne sais pas si le pseudo-élément fonctionnera. J'ai utilisé la propriété d'img element pour conserver son rapport d'aspect pour que cette solution fonctionne.
orlland

Bien, mais il ne calcule une hauteur que lorsque la largeur change. Il devrait faire dans les deux sens, donc lorsque je réduis la hauteur, la largeur est également recalculée. Sinon c'est inutile ..
Ωmega

4

disons que vous avez 2 divs, le div externe est un conteneur et l'intérieur peut être tout é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 -->

disons que vous devez conserver le rapport de "l'élément"

rapport => 4 à 1 ou 2 à 1 ...

css ressemble à ceci

.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 */
}

le rembourrage spécifié en% est calculé en fonction de la largeur et non de la hauteur. .. donc, fondamentalement, peu importe votre largeur, sa hauteur sera toujours calculée en fonction de cela. qui gardera le ratio.


4

J'ai rencontré ce problème plusieurs fois, j'ai donc fait une solution JS pour cela. Cela ajuste essentiellement la hauteur du domElement 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 définit la hauteur de l'élément, l'élément doit être soit a display:blocksoit display:inline-block.

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


1
Bien que je n'aie pas vu ou essayé votre code (j'ai déjà le mien), j'ai voté pour votre réponse juste parce que vous présentez la seule solution fiable, un script JS.
Theo d'Or

La question demandait spécifiquement une solution qui n'avait pas besoin de Javascript.
Flimm

4

Si vous souhaitez placer un carré à l'intérieur de la fenêtre en mode portrait ou paysage (aussi grand que possible, mais rien ne dépasse à l'extérieur), basculez entre l'utilisation de vw/ vhsur l'orientation portrait/ landscape:

@media (orientation:portrait ) {
  .square {
    width :100vw;
    height:100vw;
  }
} 
@media (orientation:landscape) {
  .square {
    width :100vh;
    height:100vh;
  }
} 

4

Je voudrais partager ma solution, où j'ai un img-tag remplissant un certain rapport d'aspect. Je ne pouvais pas utiliser en backgroundraison du manque de soutien de la CMS et je ne préfère utiliser une balise de style comme ceci: <img style="background:url(...)" />. De plus, la largeur est de 100%, il n'est donc pas nécessaire de la définir à une taille fixe comme dans certaines solutions. Il évoluera de manière réactive!

.wrapper {
  width: 50%;
}

.image-container {
  position: relative;
  width: 100%;
}

.image-container::before {
  content: "";
  display: block;
}

.image-container img {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.ratio-4-3::before {
  padding-top: 75%;
}

.ratio-3-1::before {
  padding-top: calc(100% / 3);
}

.ratio-2-1::before {
  padding-top: 50%;
}
<div class="wrapper"> <!-- Just to make things a bit smaller -->
  <p>
  Example of an 4:3 aspect ratio, filled by an image with an 1:1 ratio.
  </p>
  <div class="image-container ratio-4-3"> <!-- Lets go for a 4:3 aspect ratio -->
    <img src="https://placekitten.com/1000/1000/" alt="Kittens!" />
  </div>
  <p>
  Just place other block elements around it; it will work just fine.
  </p>
</div>


3

Vous pouvez y parvenir en utilisant SVG.

Cela dépend d'un cas, mais dans certains cas, c'est vraiment utile. À titre d'exemple - vous pouvez définir background-imagesans définir de hauteur fixe ou l'utiliser pour intégrer YouTube <iframe>avec un ratio 16:9, position:absoluteetc.

Pour le 3:2ratio défini viewBox="0 0 3 2"et ainsi de suite.

Exemple:

div{
    background-color:red
}
svg{
    width:100%;
    display:block;
    visibility:hidden
}

.demo-1{width:35%}
.demo-2{width:20%}
<div class="demo-1">
  <svg viewBox="0 0 3 2"></svg>
</div>

<hr>

<div class="demo-2">
  <svg viewBox="0 0 3 2"></svg>
</div>


3

Un moyen simple de conserver les proportions, en utilisant l'élément canvas.

Essayez de redimensionner le div ci-dessous pour le voir en action.

Pour moi, cette approche a fonctionné le mieux, donc je la partage avec d'autres afin qu'ils puissent en bénéficier également.

.cont {
  border: 5px solid blue;
  position: relative;
  width: 300px;
  padding: 0;
  margin: 5px;
  resize: horizontal;
  overflow: hidden;
}

.ratio {
  width: 100%;
  margin: 0;
  display: block;
}

.content {
  background-color: rgba(255, 0, 0, 0.5);
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  margin: 0;
}
<div class="cont">
  <canvas class="ratio" width="16" height="9"></canvas>
  <div class="content">I am 16:9</div>
</div>

Fonctionne également avec une hauteur dynamique!

.cont {
  border: 5px solid blue;
  position: relative;
  height: 170px;
  padding: 0;
  margin: 5px;
  resize: vertical;
  overflow: hidden;
  display: inline-block; /* so the div doesn't automatically expand to max width */
}

.ratio {
  height: 100%;
  margin: 0;
  display: block;
}

.content {
  background-color: rgba(255, 0, 0, 0.5);
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  margin: 0;
}
<div class="cont">
  <canvas class="ratio" width="16" height="9"></canvas>
  <div class="content">I am 16:9</div>
</div>


yup m'a aidé, je peux maintenant l'utiliser pour configurer la hauteur de la division parent de l'image)
Alex

2

Disons que vous aimez maintenir la largeur: 100px et la hauteur: 50px (c.-à-d. 2: 1) Faites simplement ce calcul:

.pb-2to1 {
  padding-bottom: calc(50 / 100 * 100%); // i.e., 2:1
}


1

Vous pouvez utiliser la disposition de flux (FWD).

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

Il mettra à l'échelle et maintiendra la mise en page, c'est un peu complexe mais permet à une page de se redimensionner sans pousser le contenu comme (RWD).

Il semble réactif, mais il évolue. https://www.youtube.com/watch?v=xRcBMLI4jbg

Vous pouvez trouver la formule de mise à l'échelle CSS ici:

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


Comment cela répond-il à la question?
Flimm

0

J'ai utilisé une nouvelle solution.

.squares{
  width: 30vw
  height: 30vw

Au rapport d'aspect principal

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

Cependant, cela est relatif à la fenêtre entière. Donc, si vous avez besoin d'un div qui représente 30% de la largeur de la fenêtre, vous pouvez utiliser 30vw à la place, et puisque vous connaissez la largeur, vous les réutilisez en hauteur à l'aide de calc et vw unit.


7
N'est-ce pas exactement ce que la deuxième réponse la plus élevée a déjà décrite?
rnevius

-4

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

Voici un exemple de ce que je veux dire, si toute votre hiérarchie parent était basée sur%, tout ajustement de la fenêtre du navigateur fonctionnerait sans js / css supplémentaire, n'est-ce pas une possibilité avec votre mise en page?

<div style="width: 100%;">
   <div style="width: 50%; margin: 0 auto;">Content</div>
</div>

1
Voir ma modification à la question d'origine. Je ne vois pas où cette technique conserverait les proportions, la hauteur ne changerait pas.
jackb
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.