Zachowaj proporcje div z CSS

1058

Chcę utworzyć taki, divktóry może zmieniać szerokość / wysokość wraz ze zmianą szerokości okna.

Czy są jakieś reguły CSS3, które pozwoliłyby na zmianę wysokości w zależności od szerokości, przy jednoczesnym zachowaniu proporcji ?

Wiem, że mogę to zrobić za pomocą JavaScript, ale wolałbym używać tylko CSS.

div zachowując współczynnik kształtu zgodnie z szerokością okna

jackb
źródło
2
O różnych podejściach pisałem w artykule CSS-Tricks na temat skalowania responsywnych animacji
Zach Saucier,
2
Przyszedłem do tego pytania bardzo późno, ale muszę to skomentować. Chociaż jest to bardzo zdyscyplinowane i zgodne z regułami SO każdego, kto odpowiada, starając się zaspokoić żądanie „jedynego CSS” pytania, dość zaskakujące jest to, że z wyjątkiem odpowiedzi user007 na dole strony, nie- wspomniano o oczywistości: nie istnieje niezawodne rozwiązanie tylko CSS, ten problem wymaga Javascript. Nowicjusz wchodzący na tę stronę może zmarnować cenny czas na przełączanie się z jednego zestawu zalet / wad na inny, zanim zgaśnie żarówka: CSS nie wystarczy.
Theo d'Or
1
Napisałem małe narzędzie, które ułatwia przeglądanie i obliczanie proporcji obrazu, formatrat.io . Generuje również odpowiedni kod CSS / Sass / Less, który można skopiować i wkleić do swoich projektów. Mam nadzieję, że ludzie uznają to za przydatne.
Ryan Hefner
zobacz ten przykład: w3schools.com/howto/howto_css_aspect_ratio.asp ..... który mnie zadziałał
Cristian Agudelo
1
To pytanie dotyczy ustawienia wysokości na podstawie szerokości . Jeśli potrzebujesz czegoś przeciwnego, sprawdź Ustawianie szerokości elementu na podstawie wysokości za pomocą CSS .
John Mellor,

Odpowiedzi:

1352

Wystarczy utworzyć opakowanie <div>z wartością procentową dla padding-bottom:

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>

Spowoduje to, że <div>wysokość będzie równa 75% szerokości pojemnika (współczynnik kształtu 4: 3).

Opiera się to na tym, że w przypadku wypełnienia:

Procent jest obliczany w odniesieniu do szerokości wygenerowanego bloku zawierającego blok [...] (źródło: w3.org , moje podkreślenie)

Wartości dopełnienia do dołu dla innych współczynników kształtu i 100% szerokości:

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

Umieszczanie treści w div:

Aby zachować współczynnik kształtu div i zapobiec jego rozciągnięciu, musisz dodać dziecko o absolutnej pozycji i rozciągnąć go na brzegach opakowania za pomocą:

div.stretchy-wrapper {
  position: relative;
}

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

Oto demo i kolejne bardziej szczegółowe demo

Projektant stron internetowych
źródło
29
@ schellmax, ponieważ wypełnienie% jest obliczane w stosunku do szerokości bieżącego elementu, gdzie jako wysokość% jest obliczana w stosunku do wysokości elementu nadrzędnego. Ponadto pozycje bezwzględne są obliczane w stosunku do zewnętrznego pojemnika elementu, który obejmuje obszar wypełnienia. Aby uzyskać więcej informacji Google „Model pudełkowy CSS”
Anson Kao,
11
To nie wydaje się działać w sposób zagnieżdżony. Działa na pierwszym poziomie, ale podczas próby zrobienia tego samego w div przy zachowaniu proporcji, procent wypełnienia dolnej krawędzi wydaje się być stosowany do szerokości elementu nadrzędnego. tutaj jest przykład, w którym .stretchy-wrap.onethird-bottom-bottom 25% jest faktycznie 25% szerokości rodzica. Czy ktoś może to wyjaśnić?
Misterparker
4
Niesamowite. Zabija mnie to, że ta technika nie zadziała, jeśli chcesz naprawić wysokość na 100%. @Misterparker, technika opiera się na obliczeniach szerokości i wypełnienia wykonywanych w odniesieniu do tego samego odniesienia; nie możesz użyć szerokości mniejszej niż 100%, jak w przykładzie.
steveluscher
2
@Misterparker Tak, procent wypełnienia jest obliczany proporcjonalnie do szerokości elementu rodzica. Zobacz bardziej szczegółowy przykład, który opublikowałem w odpowiedzi na moją odpowiedź. Moje zaktualizowane demo pokazuje „zagnieżdżoną modę”, o której mówiłeś.
Web_Designer,
3
fakt, że wykazał, że to działa, wystarczy, aby przekonać mnie, że jest to najlepsza odpowiedź, jaką kiedykolwiek widziałem na SO. krzycz do mojego mężczyzny @Web_Designer
411

vw jednostki:

Możesz użyć vwjednostek zarówno dla szerokości, jak i wysokości elementu. Umożliwia to zachowanie proporcji elementu na podstawie szerokości rzutni.

vw: 1/100 szerokości rzutni. [ MDN ]

Alternatywnie, możesz również użyć vhdla wysokości rzutni, a nawet vmin/, vmaxaby użyć mniejszych / większych wymiarów rzutni ( tutaj dyskusja ).

Przykład: proporcje 1: 1

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

W przypadku innych współczynników kształtu możesz skorzystać z poniższej tabeli, aby obliczyć wartość wysokości zgodnie z szerokością elementu:

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

Przykład: siatka 4x4 kwadratowych div

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>

Oto Fiddle w tej wersji demonstracyjnej, a tutaj jest rozwiązanie, aby stworzyć responsywną siatkę kwadratów z zawartością pionową i poziomą .


Obsługa przeglądarek dla jednostek vh / vw to IE9 +, patrz canIuse, aby uzyskać więcej informacji

web-tiki
źródło
13
To powinna być zaakceptowana odpowiedź. Może nie teraz, ale w przyszłości. Jednostki vw są teraz obsługiwane w większości przeglądarek .
sierpnia
3
@vivekmaharajh obie techniki są dobre, każda z nich ma swoje zalety i wady. Używanie jednego lub drugiego zależy w dużej mierze od sytuacji.
web-tiki
11
@ web-tiki, masz rację. Natknąłem się na jeden problem - zakłada się, że szerokość elementu jest proporcjonalna do szerokości rzutni, co nie będzie miało miejsca, jeśli 1) masz rzeczy takie jak rynny o stałej szerokości lub 2) masz ustawiony maksymalną szerokość dla niektórych twoich elementów.
Vivek Maharajh
1
Może to po prostu Chrome v47beta, ale kiedy ustawiam div, width:50%a height:50vwwysokość jest nieco wyższa niż szerokość, więc nie dokładnie proporcja 1: 1. Jakieś pomysły?
thdoan
2
@ 10basetom jest to normalne zachowanie. Jednostki vw zawierają szerokość paska przewijania, podczas gdy% width nie. Różnica między wysokością a szerokością zależy od rozmiaru paska przewijania, który różni się w zależności od przeglądarki.
web-tiki,
26

Znalazłem sposób na zrobienie tego za pomocą CSS, ale musisz być ostrożny, ponieważ może się to zmienić w zależności od przepływu Twojej strony internetowej. Zrobiłem to, aby osadzić wideo o stałym współczynniku kształtu w części szerokości witryny na mojej stronie.

Załóżmy, że masz osadzony film:

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

Następnie możesz umieścić to wszystko w div z klasą „wideo”. Ta klasa wideo prawdopodobnie będzie płynnym elementem w Twojej witrynie, tak że sama w sobie nie ma bezpośrednich ograniczeń wysokości, ale po zmianie rozmiaru przeglądarki zmieni szerokość w zależności od przepływu strony internetowej. Byłby to element, w którym prawdopodobnie próbujesz uzyskać osadzone wideo przy zachowaniu określonego współczynnika kształtu wideo.

W tym celu umieszczam obraz przed osadzonym obiektem w div klasy „video”.

!!! Ważne jest, aby obraz miał prawidłowy współczynnik kształtu, który chcesz zachować. Upewnij się również, że rozmiar obrazu jest NAJMNIEJ tak duży, jak najmniejsze, czego oczekujesz, że wideo (lub cokolwiek utrzymujesz AR) będzie oparte na twoim układzie. Pozwoli to uniknąć potencjalnych problemów z rozdzielczością obrazu, gdy zostanie on zmieniony w procentach. Na przykład, jeśli chcesz zachować proporcje 3: 2, nie używaj tylko obrazu 3 na 2 piksele. Może działać w pewnych okolicznościach, ale nie przetestowałem go i prawdopodobnie dobrym pomysłem byłoby go uniknąć.

Prawdopodobnie powinieneś już mieć taką minimalną szerokość zdefiniowaną dla płynnych elementów swojej witryny. Jeśli nie, warto to zrobić, aby uniknąć odcinania elementów lub nakładania się, gdy okno przeglądarki staje się zbyt małe. W pewnym momencie lepiej jest mieć pasek przewijania. Najmniejsza szerokość, jaką powinna uzyskać strona internetowa, to około ~ 600 pikseli (w tym dowolne kolumny o stałej szerokości), ponieważ rozdzielczości ekranu nie są mniejsze, chyba że masz do czynienia z witrynami przyjaznymi dla telefonu. !!!

Używam całkowicie przezroczystego PNG, ale nie sądzę, żeby miało to znaczenie, jeśli zrobisz to dobrze. Lubię to:

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

Teraz powinieneś być w stanie dodać CSS podobny do następującego:

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

Upewnij się, że usunąłeś również wszelkie wyraźne deklaracje wysokości lub szerokości w obiekcie i umieściłeś znaczniki, które zwykle pochodzą z kopiowanym / wklejanym kodem osadzania.

Sposób jego działania zależy od właściwości pozycji elementu klasy wideo i żądanego elementu ma określony współczynnik kształtu. Wykorzystuje sposób, w jaki obraz zachowa odpowiedni współczynnik kształtu po zmianie rozmiaru w elemencie. Mówi cokolwiek innego, co znajduje się w elemencie klasy wideo, aby w pełni skorzystać z nieruchomości zapewnianej przez obraz dynamiczny, zmuszając jego szerokość / wysokość do 100% elementu klasy wideo dostosowywanego przez obraz.

Całkiem fajnie, co?

Być może będziesz musiał się z nim trochę pobawić, aby uruchomić go z własnym projektem, ale dla mnie to zadziwiająco dobrze. Istnieje ogólna koncepcja.

zrzec się
źródło
17

Elliot zainspirował mnie do tego rozwiązania - dzięki:

aspectratio.png to całkowicie przezroczysty plik PNG o rozmiarze preferowanego współczynnika proporcji, w moim przypadku 30x10 pikseli.

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

Proszę zanotować: background-size jest funkcją css3, która może nie działać z twoimi przeglądarkami docelowymi. Możesz sprawdzić interoperacyjność (np. Na caniuse.com ).

Florian Breisch
źródło
14

Aby dodać do odpowiedzi Web_Designera, <div>będzie miał wysokość (w całości złożoną z dolnego wypełnienia) wynoszącą 75% szerokości jego zawierającego elementu . Oto dobre podsumowanie: http://mattsnider.com/css-using-percent-for-margin-and-padding/ . Nie jestem pewien, dlaczego tak powinno być, ale tak właśnie jest.

Jeśli chcesz, aby div miał szerokość inną niż 100%, potrzebujesz innego zawijanego div, na którym ustawisz szerokość:

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

Ostatnio użyłem czegoś podobnego do sztuczki graficznej Elliota, aby pozwolić mi na użycie zapytań o media CSS w celu wyświetlenia innego pliku logo w zależności od rozdzielczości urządzenia, ale nadal skaluje się proporcjonalnie, jak to <img>naturalnie zrobię (ustawiam logo jako obraz tła na przezroczysty plik .png z prawidłowym współczynnikiem kształtu). Ale rozwiązanie Web_Designer uratuje mi żądanie HTTP.

nabrown
źródło
Świetne rozwiązanie. W moim przypadku znam „naturalny” rozmiar obrazu podczas umieszczania go w DOM i muszę mieć symbol zastępczy obrazu o odpowiedniej wysokości, aby zapobiec dalszemu przewijaniu po załadowaniu obrazów przez przeglądarkę. W .ar-outer mam szerokość obrazu w pikselach, w .ar mam wypełnienie dołu obliczone na podstawie rzeczywistego współczynnika kształtu obrazu. Zamiast ar-inner mam sam obraz (<img>). Musiałem jednak ustawić szerokość na 100% zamiast ustawiania górnego, dolnego, lewego i prawego. Kiedy ustawię maxWidth na ar-outer, obraz ładnie skaluje się, gdy rodzic jest mały, ale nie skaluje się do większego rozmiaru niż jego naturalny rozmiar.
Mi-La
13

Jak stwierdzono tutaj na w3schools.com i nieco powtórzono w tej zaakceptowanej odpowiedzi , wartości dopełniania jako wartości procentowe (moje podkreślenie):

Określa dopełnienie w procentach szerokości elementu zawierającego

Ergo, poprawny przykład responsywnego DIV, który utrzymuje proporcje 16: 9, jest następujący:

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>

Demo na JSFiddle

Marc A.
źródło
13

Ponieważ @ web-tiki już pokazuje sposób korzystania z vh/ vw, potrzebuję również sposobu na wyśrodkowanie ekranu, oto fragment kodu dla portretu 9:16 .

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

translateYzatrzyma to centrum na ekranie. calc(100vw * 16 / 9)oczekiwana wysokość dla 9/16. (100vw * 16 / 9 - 100vh)ma wysokość przelewu, więc podciągnięcie overflow height/2spowoduje utrzymanie go na środku ekranu.

Dla krajobrazu i zachowaj 16: 9 , pokazujesz użycie

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

Współczynnik 9/16 jest łatwy do zmiany, bez potrzeby wcześniejszego definiowania 100:56.25lub. 100:75Jeśli chcesz najpierw zapewnić wysokość, powinieneś zmienić szerokość i wysokość, np. height:100vh;width: calc(100vh * 9 / 16)Dla portretu 9:16.

Jeśli chcesz dostosować do innego rozmiaru ekranu, możesz również zainteresować

  • okładka / zawiera tło w tle
    • Powyższy styl jest podobny do zawierającego, zależy od stosunku szerokości do wysokości.
  • dopasowanie obiektowe
    • cover / zawiera tag img / video
  • @media (orientation: portrait)/@media (orientation: landscape)
    • Zapytanie medialne o portrait/ w landscapecelu zmiany proporcji.
wener
źródło
11

Jest to poprawka do przyjętej odpowiedzi:

  • Używa pseudo elementów zamiast div otoki
  • Proporcje obrazu oparte są na szerokości ramki zamiast jej elementu nadrzędnego
  • Ramka będzie rozciągać się pionowo, gdy zawartość będzie wyższa

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

Salman A.
źródło
jak wyłączyć pionowe rozciąganie pudełka? Ściśle mówiąc, rozciągająca się div nie utrzymuje swojego współczynnika kształtu
florian
Jeśli zawartość jest wyższa niż oczekiwana wysokość, pole będzie rozciągać się pionowo. Ten pomysł najlepiej wykorzystać w przypadku treści, które mogą rozciągać się w celu dopasowania do wymiarów nadrzędnych, np. Wideo i obrazy.
Salman,
10

Natknąłem się na inteligentne rozwiązanie za pomocą <svg>i display:grid.

Element siatki pozwala zajmować to samo miejsce z dwoma (lub więcej) elementami, bez potrzeby określania, który z nich określa wysokość. Co oznacza, że ​​po wyjęciu z pudełka wyższy ustawia współczynnik .

Oznacza to, że możesz z niego korzystać w takiej postaci, w której wiesz, że zawartość nigdy nie będzie wystarczająco wysoka, aby wypełnić cały „współczynnik”, a po prostu szukasz sposobu na umieszczenie zawartości w tym miejscu (tj. Wyśrodkowanie jej w obu kierunkach. display:flex; align-items:center; justify-content:center).
Jest to prawie to samo, co użycie przezroczystego <img>z display:blockgóry określonego współczynnika, z tym wyjątkiem, że <svg>jest lżejszy i znacznie łatwiejszy do modyfikacji (aby zmienić współczynnik odpowiednio, jeśli zajdzie taka potrzeba).

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

Wszystko, co musisz zrobić, to zmienić <svg>współczynnik s:

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

Zobacz, jak działa:


Jeśli potrzebujesz rozwiązania, w którym element treści nie może ustawić współczynnika, gdy jest wyższy (z ukrytym przepełnieniem lub auto), musisz ustawić position:relativena siatce i position:absolute; height:100%; overflow-y: auto;na zawartości. Przykład:

tao
źródło
9

Bazując na twoich rozwiązaniach, podjąłem sztuczkę:

Gdy go użyjesz, twój HTML będzie tylko

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

Aby użyć tego w ten sposób, wykonaj: CSS:

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

i js (jQuery)

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

Mając to, właśnie ustawiłeś attr data-keep-rationa wysokość / szerokość i to wszystko.

pie6k
źródło
3
powinieneś data-keep-rationie używać keep-ratioi uzyskać jego wartość używając$(this).data('keep-ratio');
Robert
Twój kod działa teraz i być może będzie działał wiecznie, ale nie jest to standard, a przeglądarki mogą przestać go obsługiwać w przyszłości
Robert
1
Korzystanie z JS spowoduje złe wieści!
Amir Hossein Ahmadi
8

Możesz użyć SVG. Ustaw względnie pozycję kontenera / opakowania, najpierw ustaw svg jako statycznie pozycjonowane, a następnie umieść absolutnie pozycjonowaną zawartość (góra: 0; lewo: 0; prawo: 0; dół: 0;)

Przykład z proporcjami 16: 9:

image.svg: (można wstawić w 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>

Zauważ, że inline svg nie działa, ale możesz urlencode svg i osadzić go w atrybucie img src w następujący sposób:

<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%;" />
Maciej Krawczyk
źródło
7

SCSS jest najlepszym rozwiązaniem w moim przypadku; za pomocą atrybutu danych:

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

Na przykład :

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

źródło

Gordie
źródło
15
Po prostu FYI ... Możesz to zrobić dokładnie (używając selektorów atrybutów) w dokładnie takiej samej ilości linii, używając zwykłego CSS. [data-aspect-ratio]Selektor atrybutu jest dostępne w CSS.
rnevius
6

Chociaż większość odpowiedzi jest bardzo fajna, większość z nich wymaga, aby obraz był już odpowiednio zwymiarowany ... Inne rozwiązania działają tylko dla szerokości i nie dbają o dostępną wysokość, ale czasami chcesz dopasować zawartość również do określonej wysokości .

Próbowałem połączyć je ze sobą, aby uzyskać w pełni przenośne i skalowalne rozwiązanie ... Sztuką jest użycie do automatycznego skalowania obrazu, ale użycie wbudowanego elementu svg zamiast użycia wstępnie renderowanego obrazu lub dowolnej formy drugie żądanie 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>

Zauważ, że użyłem dużych wartości w atrybutach szerokości i wysokości pliku SVG, ponieważ musi on być większy niż maksymalny oczekiwany rozmiar, ponieważ może on się tylko kurczyć. W tym przykładzie współczynnik div wynosi 10: 5

Salketer
źródło
4

Tylko pomysł lub 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>

orland
źródło
To nie jest rozwiązanie tylko CSS ... Teraz, gdybyś użył obrazu zakodowanego w base64 w pseudoelemencie, byłoby to fajne rozwiązanie.
rnevius
1
Naprawdę nie ma rozwiązania wyłącznie CSS. HTML jest podstawowym składnikiem sieci. Uważam, że celem tego pytania jest powstrzymanie się od używania JS, być może w celu oszczędzania zasobów / przetwarzania.
Irlandia
Nie jestem pewien, czy pseudoelement zadziała. Wykorzystałem właściwość elementu img, aby utrzymać jego proporcje, aby to rozwiązanie działało.
Norwegia
Fajnie, ale oblicza wysokość tylko wtedy, gdy zmienia się szerokość. Powinno to działać w obie strony, więc gdy zmniejszam wysokość, szerokość jest również ponownie obliczana. W przeciwnym razie jest to bezużyteczne ..
Ωmega
4

powiedzmy, że masz 2 div div outher jest kontenerem, a wewnętrzna może być dowolnym elementem, którego potrzebujesz, aby zachować jego stosunek (img lub iframe na youtube lub cokolwiek innego)

HTML wygląda następująco:

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

powiedzmy, że musisz zachować stosunek „elementu”

stosunek => 4 do 1 lub 2 do 1 ...

css wygląda tak

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

wypełnienie, gdy podano w%, jest obliczane na podstawie szerokości, a nie wysokości. .. więc w zasadzie nie ma znaczenia, jaką szerokość będzie zawsze obliczać na podstawie tego. który zachowa stosunek.

Ahmed Eid
źródło
4

Jeśli chcesz dopasować kwadrat w okienku ekranu w widoku pionowym lub poziomym (tak duży, jak to możliwe, ale nic nie wystaje na zewnątrz), przełącz się między użyciem vw/ vhorientacji portrait/ landscape:

@media (orientation:portrait ) {
  .square {
    width :100vw;
    height:100vw;
  }
} 
@media (orientation:landscape) {
  .square {
    width :100vh;
    height:100vh;
  }
} 
MoonLite
źródło
4

Chciałbym udostępnić moje rozwiązanie, w którym mam imgtag wypełniający pewien współczynnik kształtu. I nie mógł skorzystać backgroundz powodu braku wsparcia CMS, a ja nie, że wolą używać tagu stylu tak: <img style="background:url(...)" />. Ponadto szerokość wynosi 100%, więc nie trzeba ustawiać jej na stały rozmiar, jak w niektórych rozwiązaniach. Skaluje się odpowiednio!

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

LaVomit
źródło
3

Problem ten napotkałem już kilka razy, więc stworzyłem dla niego rozwiązanie JS. Zasadniczo dostosowuje wysokość domElement zgodnie z szerokością elementu o określony współczynnik. Możesz użyć tego w następujący sposób:

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

Należy pamiętać, że ponieważ ustawia wysokość elementu, element powinien mieć wartość a display:blocklub display:inline-block.

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

użytkownik007
źródło
1
Chociaż nie widziałem ani nie wypróbowałem twojego kodu (mam już swój własny), głosowałem za odpowiedzią tylko dlatego, że prezentujesz jedyne niezawodne rozwiązanie, skrypt JS.
Theo d'Or
Pytanie konkretnie dotyczyło rozwiązania, które nie wymagało Javascript.
Flimm
2

Możesz to osiągnąć za pomocą SVG.

To zależy od przypadku, ale w niektórych jest naprawdę przydatne. Jako przykład - możesz ustawić background-imagebez ustawiania stałej wysokości lub użyć go do osadzenia youtube <iframe>ze współczynnikiem 16:9iposition:absolute etc.

Dla 3:2zestawu proporcjiviewBox="0 0 3 2" i tak dalej.

Przykład:

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>

Jakub Muda
źródło
2

Powiedz, że chcesz zachować Szerokość: 100 pikseli i Wysokość: 50 pikseli (tj. 2: 1) Po prostu zrób to:

.pb-2to1 {
  padding-bottom: calc(50 / 100 * 100%); // i.e., 2:1
}
Syed
źródło
1

Prosty sposób na zachowanie współczynnika kształtu za pomocą elementu canvas.

Spróbuj zmienić rozmiar div poniżej, aby zobaczyć go w akcji.

Dla mnie to podejście zadziałało najlepiej, dlatego dzielę się nim z innymi, aby również mogli z niego skorzystać.

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

Działa również z dynamiczną wysokością!

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

Gbr22
źródło
tak, pomógł mi, teraz mogę go użyć, aby ustawić wysokość div rodzica obrazu)
Alex
0

Użyłem nowego rozwiązania.

.squares{
  width: 30vw
  height: 30vw

Do głównego współczynnika kształtu

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

Jest to jednak względne w stosunku do całej rzutni. Tak więc, jeśli potrzebujesz div, który jest 30% szerokości rzutni, możesz zamiast tego użyć 30vw, a ponieważ znasz szerokość, ponownie używasz ich na wysokości za pomocą jednostki calc i vw.

Eshwaren Manoharen
źródło
7
Czy nie jest to dokładnie to, co już zarysowała druga najwyżej oceniana odpowiedź?
rnevius
-4

Jeśli cała struktura kontenera była oparta na wartościach procentowych, byłoby to zachowanie domyślne, czy możesz podać bardziej szczegółowy przykład?

Poniżej znajduje się przykład tego, co mam na myśli, jeśli cała twoja hierarchia nadrzędna była oparta na%, dowolne dostosowanie okna przeglądarki działałoby bez dodatkowego js / css, czy nie jest to możliwe w twoim układzie?

<div style="width: 100%;">
   <div style="width: 50%; margin: 0 auto;">Content</div>
</div>
Nick Craver
źródło
1
Zobacz moją edycję oryginalnego pytania. Nie widzę, gdzie ta technika zachowałaby proporcje, wysokość nie zmieniłaby się.
jackb