Mantieni le proporzioni dell'immagine quando si modifica l'altezza


114

Utilizzando il modello CSS flex box, come posso forzare un'immagine a mantenere le sue proporzioni?

JS Fiddle: http://jsfiddle.net/xLc2Le0k/2/

Notare che le immagini si allungano o si restringono per riempire la larghezza del contenitore. Va bene, ma possiamo anche allungare o restringere l' altezza per mantenere le proporzioni dell'immagine?

HTML

<div class="slider">
    <img src="http://www.placebacon.net/400/300" alt="Bacn">
    <img src="http://www.placebacon.net/400/300" alt="Bacn">
    <img src="http://www.placebacon.net/400/300" alt="Bacn">
    <img src="http://www.placebacon.net/400/300" alt="Bacn">
</div>

CSS

.slider {
    display: flex;
}
.slider img {
    margin: 0 5px;
}

1
Per quanto ne so, la soluzione migliore è usare un <div>con il CSSbackground-image: url(...);background-size:contain; background-repeat:no-repeat
Blazemonger

1
Ci sono alcuni indizi interessanti qui, ma cosa succede quando le immagini non hanno già lo stesso rapporto? L'aggiunta di un div "extra" è l'ultima cosa di cui dobbiamo preoccuparci. Perché non utilizzare invece un test case come questo: jsfiddle.net/sheriffderek/999Lg9qv
sheriffderek

Risposte:


68

Per i tag img, se si definisce un lato, l'altro lato viene ridimensionato per mantenere le proporzioni e per impostazione predefinita le immagini si espandono alla loro dimensione originale.

Usando questo fatto se avvolgi ogni tag img nel tag div e imposti la sua larghezza al 100% del div genitore, l'altezza sarà in base alle proporzioni desiderate.

http://jsfiddle.net/0o5tpbxg/

* {
    margin: 0;
    padding: 0;
}
.slider {
    display: flex;
}
.slider .slide img {
    width: 100%;
}

2
So che ci sono due risposte che suggeriscono di utilizzare div, ma contrassegno questa risposta come corretta perché spiega perché le altezze dell'immagine sono diverse da quelle che mi aspettavo. In effetti, questo è un comportamento normale e corretto ed è improbabile che venga "risolto", poiché non è un bug.
coderMe

18
Ma questa risposta non parla di flexbox, perché le immagini si comportano in modo diverso all'interno del contenitore flexbox. L'impostazione di un lato non ridimensionerà proporzionalmente l'altro. Avvolgerli in un contenitore non flexbox aiuta, ma ciò aggiunge markup non necessario perdendo semanticità.
Robert Koritnik,

3
Non sembra che tu abbia bisogno di un div avvolgente per far funzionare questo: jsfiddle.net/xLc2Le0k/120
Rick Strahl

4
Ma che dire di questo? jsfiddle.net/xLc2Le0k/15 Penso che questa soluzione sia un colpo di fortuna che funziona solo perché le immagini hanno tutte lo stesso rapporto. nota a margine: non c'è alcuna "semanticità" persa inserendo un'immagine in un div per il posizionamento / soprattutto quando si ha a che fare con immagini responsive.
Sheriffderek il

1
Seriamente la soluzione più pulita e funziona con l'immagine!
shaneonabike

64

Per evitare che le immagini si allunghino su entrambi gli assi all'interno di un genitore flessibile, ho trovato un paio di soluzioni.

Puoi provare a utilizzare l'adattamento all'oggetto sull'immagine che, ad es

object-fit: contain;

http://jsfiddle.net/ykw3sfjd/

Oppure puoi aggiungere regole specifiche di flessibilità che potrebbero funzionare meglio in alcuni casi.

align-self: center;
flex: 0 0 auto;

4
object-fit potrebbe essere una buona soluzione se non mancasse il supporto in IE ed Edge anche fino a Edge 14
daniels

1
Dai un'occhiata a questo fallback ad oggetti per Edge e IE .
Andrei Telteu

Ho usato io stesso quel fallback, funziona molto bene.
Matty Balaam

1
@daniels Edge ora ha l'adattamento agli oggetti nello sviluppo: developer.microsoft.com/en-us/microsoft-edge/platform/status/…
AMDG

1
object-fit: contain;ha fatto il trucco per me, quando ho avuto solo il problema in chrome, ff andava bene.
Benjamin Peter

53

Non è necessario aggiungere un div contenitore.

L'impostazione predefinita per la proprietà css "align-items" è "stretch", che è ciò che causa l'allungamento delle immagini alla sua altezza originale completa. L'impostazione della proprietà css "align-items" su "flex-start" risolve il problema.

.slider {
    display: flex;
    align-items: flex-start;  /* ADD THIS! */
}

3
Ahh ... grazie per aver effettivamente fatto le cose nel modo supportato. Stavo leggendo le risposte fino a quella e non potevo credere che tutto ciò che avevamo erano sporchi hack ..
Félix Gagnon-Grenier,

35

La maggior parte delle immagini con dimensioni intrinseche , cioè una dimensione naturale, come jpegun'immagine. Se la dimensione specificata definisce sia la larghezza che l'altezza, il valore mancante viene determinato utilizzando il rapporto intrinseco ... - vedere MDN .

Ma ciò non funziona come previsto se le immagini che vengono impostate come elementi flessibili diretti con l'attuale modulo di layout a scatola flessibile di livello 1 , per quanto ne so.

Vedi queste discussioni e le segnalazioni di bug potrebbero essere correlate:

  • Flexbugs # 14 - Dimensionamento intrinseco di Chrome / Flexbox non implementato correttamente.
  • Bug di Firefox 972595 - I contenitori flessibili dovrebbero utilizzare "base flessibile" invece di "larghezza" per calcolare le larghezze intrinseche degli elementi flessibili
  • Chromium Problema 249112 - In Flexbox, consenti proporzioni intrinseche per informare il calcolo della dimensione principale.

Come soluzione alternativa, puoi racchiudere ciascuno <img>di essi con a <div>o a <span>, o giù di lì.

jsFiddle

.slider {
  display: flex;
}

.slider>div {
  min-width: 0; /* why? see below. */
}

.slider>div>img {
  max-width: 100%;
  height: auto;
}
<div class="slider">
  <div><img src="https://picsum.photos/400/300?image=0" /></div>
  <div><img src="https://picsum.photos/400/300?image=1" /></div>
  <div><img src="https://picsum.photos/400/300?image=2" /></div>
  <div><img src="https://picsum.photos/400/300?image=3" /></div>
</div>

4.5 Dimensione minima implicita degli articoli flessibili

Per fornire una dimensione minima predefinita più ragionevole per gli elementi flessibili , questa specifica introduce un nuovo valore automatico come valore iniziale delle proprietà min-width e min-height definite nei CSS 2.1.


In alternativa, puoi utilizzare tableinvece il layout CSS , che otterrai risultati simili in flexboxquanto funzionerà su più browser, anche per IE8.

jsFiddle

.slider {
  display: table;
  width: 100%;
  table-layout: fixed;
  border-collapse: collapse;
}

.slider>div {
  display: table-cell;
  vertical-align: top;
}

.slider>div>img {
  max-width: 100%;
  height: auto;
}
<div class="slider">
  <div><img src="https://picsum.photos/400/300?image=0" /></div>
  <div><img src="https://picsum.photos/400/300?image=1" /></div>
  <div><img src="https://picsum.photos/400/300?image=2" /></div>
  <div><img src="https://picsum.photos/400/300?image=3" /></div>
</div>


Il primo frammento deve essere utilizzato .slider > div{min-width:0}sui nuovi browser che supportano min-width: auto.
Oriol

3
La specifica flexbox ha introdotto un nuovo autovalore come valore predefinito per min-widthe min-height(in precedenza lo era 0). Chrome non lo implementa ancora, quindi il tuo primo snippet funziona. Ma i nuovi browser ne hanno bisogno per consentire agli elementi flessibili di ridursi più piccoli della larghezza predefinita delle immagini.
Oriol

2
+1 questa risposta dovrebbe essere accettata perché parla di immagini nel modello flexbox che è il problema principale in questo caso ...
Robert Koritnik

Il tavolo è ottimo se il layout non cambia in vari punti di interruzione, ma è improbabile di questi tempi.
sheriffderek

1
E quando le immagini non hanno tutte le stesse proporzioni? jsfiddle.net/sheriffderek/5u7y21we
sheriffderek

6

Ultimamente ho giocato a flexbox e sono arrivato alla soluzione per questo attraverso la sperimentazione e il seguente ragionamento. Tuttavia, in realtà non sono sicuro che sia esattamente ciò che accade.

Se la larghezza reale è influenzata dal sistema flessibile. Quindi, dopo che la larghezza degli elementi ha raggiunto la larghezza massima del genitore, la larghezza extra impostata in css viene ignorata. Quindi è sicuro impostare la larghezza al 100%.

Poiché l'altezza del tag img è derivata dall'immagine stessa, impostare l'altezza su 0% potrebbe fare qualcosa. (qui è dove non sono chiaro su cosa ... ma per me aveva senso che dovesse risolverlo)

DEMO

(ricorda di averlo visto qui prima!)

.slider {
    display: flex;
}
.slider img {
    height: 0%;
    width: 100%;
    margin: 0 5px;
}

Funziona solo in Chrome ancora


Interessante, ma sembra un bug. Secondo la specifica , " La percentuale è calcolata rispetto all'altezza del blocco contenitore del riquadro generato. Se l'altezza del blocco contenitore non è specificata esplicitamente (cioè dipende dall'altezza del contenuto), e questo elemento non è posizionato in modo assoluto , il valore viene calcolato inauto ". È quello che succede su Firefox.
Oriol

jsfiddle.net/xLc2Le0k/8 spiega la differenza tra ff e chrome. per questo
Muhammad Umer

width sembra fare in ff quello che fa height in chrome.
Muhammad Umer

È interessante, ma temo che le soluzioni solo per browser X non siano realmente soluzioni. Il tuo violino commentato, qui: jsfiddle.net/xLc2Le0k/8 è assolutamente affascinante , però, in FF. Questo sembra mostrare che FF sta rendendo l'altezza dell'immagine "proporzionata" all'altezza dell'immagine se fosse veramente al 100%. In altre parole, l'img non "sa" del display del contenitore: flex. Questo spiega perché, in FF, se imposti la larghezza dell'immagine al 100%, l'immagine è più alta rispetto a quando imposti la larghezza su auto.
coderMe

Questo è un po 'vicino ... ma funziona solo in Chrome: jsfiddle.net/sheriffderek/xLc2Le0k/270
sheriffderek

2

Questo comportamento è previsto. flex container estenderà tutti i suoi figli per impostazione predefinita. L'immagine non fa eccezione. (cioè, il genitore avrà la align-items: stretchproprietà)

Per mantenere le proporzioni abbiamo due soluzioni:

  1. Sostituisci la align-items: stretchproprietà predefinita in align-items: flex-starto align-self: centerecc., Http://jsfiddle.net/e394Lqnt/3/

o

  1. Imposta la proprietà align esclusivamente sul figlio stesso: like, align-self: centero align-self: flex-startecc. Http://jsfiddle.net/e394Lqnt/2/

-1

In realtà ho scoperto che il contenitore del tag immagine deve avere un'altezza per mantenere il rapporto dell'immagine. ad esempio>

.container{display:flex; height:100%;} img{width:100%;height:auto;}

quindi nel tuo html il tuo contenitore avvolgerà l'immagine del tag

<div class="container"><img src="image.jpg" alt="image" /></div>

questo funziona per IE e altri browser


-1

Ho appena avuto lo stesso problema. Usa l'allineamento flessibile per centrare i tuoi elementi. Devi usare align-items: centerinvece di align-content: center. Ciò manterrà le proporzioni, mentre align-content non manterrà le proporzioni.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.