Wyśrodkuj powiększony obraz w Div

175

Próbowałem ustalić, jak wyśrodkować zbyt duży obraz w elemencie div, używając tylko CSS.

Używamy układu płynnego, więc szerokość kontenerów obrazu zmienia się wraz z szerokością strony (wysokość elementu div jest stała). Obraz znajduje się w elemencie div, z wartością wstawionego cienia pola, tak aby wyglądał tak, jakbyś patrzył na obraz na stronie.

Rozmiar samego obrazu został tak dopasowany, aby wypełniał otaczający element div w najszerszej możliwej wartości (projekt ma max-widthwartość).

Jest to dość łatwe, jeśli obraz jest mniejszy niż otaczający go element div:

margin-left: auto;
margin-right: auto;
display: block; 

Ale kiedy obraz jest większy niż div, po prostu zaczyna się od lewej krawędzi i jest poza środkiem w prawo (używamy overflow: hidden).

Moglibyśmy przypisać width=100%, ale przeglądarki wykonują kiepską robotę zmieniając rozmiar obrazów, a projektowanie stron internetowych koncentruje się na wysokiej jakości obrazach.

Jakieś pomysły na wyśrodkowanie obrazu tak, overflow:hiddenaby równo odcięło obie krawędzie?

Tomek
źródło
2
Czy kiedykolwiek rozwiązałeś ten problem @Tom? W tej chwili mam ten sam problem. :)
ctrlplusb
Zakładam, że szerokość twojego obrazu jest różna.
otherDewi

Odpowiedzi:

365

Spróbuj czegoś takiego. Powinno to wyśrodkować każdy duży element na środku w pionie i poziomie w stosunku do jego rodzica, niezależnie od ich obu rozmiarów.

.parent {
    position: relative;
    overflow: hidden;
    //optionally set height and width, it will depend on the rest of the styling used
}

.child {
    position: absolute;
    top: -9999px;
    bottom: -9999px;
    left: -9999px;
    right: -9999px;
    margin: auto;

}
hyounis
źródło
4
cudownie: to działa z każdym elementem. nawet z wideo HTML 5 ... dzięki!
taseenb
3
Jak rozumiem: działa, ponieważ tworzy element (miejmy nadzieję) większy niż obraz (2 * 9999px x 2 * 9999px) i wyśrodkowuje obraz wewnątrz tego elementu (margin: auto). Tak długo, jak obraz nie przekracza 2 * 9999 pikseli, powinien działać.
Michael Krupp
16
Dlaczego nie użyć -100%dla górnego / prawego / dolnego / lewego? Dzięki temu pojemnik mógłby mieć dosłownie dowolną szerokość.
Simon,
15
Tak, też doświadczyłem -100%problemu ^^. BTW: jeśli dodasz min-widthi min-heightstanowi 100%w zasadzie uzyskać background-size: cover;zachowanie z tagów graficznych -> jsfiddle
Simon
3
@HarrisonPowers Cóż, rodzic musi mieć oczywiście wysokość, niezależnie od tego, czy jest stała, czy dynamiczna. Będzie również działać, jeśli inna zawartość wypełnia element div, powodując jego wysokość (na przykład tekst).
hyounis
162

To jest stara Q, ale nowoczesne rozwiązanie bez flexboksa lub absolutnej pozycji działa w ten sposób.

margin-left: 50%;
transform: translateX(-50%);

Więc dlaczego to działa?
Na pierwszy rzut oka wydaje się, że przesuwamy się o 50% w prawo, a następnie ponownie o 50% w lewo. To spowodowałoby zerowe przesunięcie, więc co z tego?
Ale te 50% to nie to samo, ponieważ ważny jest kontekst. Jeśli użyjesz jednostek względnych, margines zostanie obliczony jako procent szerokości elementu nadrzędnego , podczas gdy transformacja będzie wynosić 50% w stosunku do tego samego elementu.

Mamy taką sytuację, zanim dodamy CSS

       +-------------------------------------------+
       | Parent element P of E                     |
       |                                           |
       +-----------------------------------------------------------+
       | Element E                                                 |
       +-----------------------------------------------------------+
       |                                           |
       +-------------------------------------------+

Z dodatkowym stylem, margin-left: 50%który mamy

       +-------------------------------------------+
       | Parent element P of E                     |
       |                                           |
       |                     +-----------------------------------------------------------+
       |                     | Element E                                                 |
       |                     +-----------------------------------------------------------+
       |                     |                     |
       +---------------------|---------------------+
       |========= a ========>|

       a is 50% width of P

I transform: translateX(-50%)przesuwa się z powrotem w lewo

       +-------------------------------------------+
       | Parent element P of E                     |
       |                                           |
+-----------------------------------------------------------+
| Element E                 |                               |
+-----------------------------------------------------------+
|<============ b ===========|                      |
       |                    |                      |
       +--------------------|----------------------+
       |========= a =======>|

       a is 50% width of P
       b is 50% width of E

Niestety działa to tylko w przypadku wyśrodkowania w poziomie, ponieważ obliczenie procentu marginesu jest zawsze odniesione do szerokości. To znaczy nie tylko margin-lefti margin-right, ale także margin-topi margin-bottomsą obliczane w odniesieniu do szerokości.

Zgodność z przeglądarkami nie powinna stanowić problemu: https://caniuse.com/#feat=transforms2d

yunzen
źródło
Nie działa w przypadku wyrównania w pionie (gdy .inner ma większą wysokość niż .outer)
cronfy
1
@cronfy No. w pionie nie zadziała, bo margin-top: 50%będzie 50% szerokości . nie żądaną wysokość.
yunzen
2
to zdecydowanie najbardziej eleganckie rozwiązanie
Souhaieb Besbes
szukanie na chwilę rozwiązania, najlepszego, najprostszego; Pozdrawiam
lauWM
2
To jest czysta magia czarodziejów. Dziękuję Ci! Działa idealnie w Safari i Chrome (z dodatkiem -webkit-transform: translateX(-50%);na miarę)
Nick Schneble
22

Umieść duży element DIV wewnątrz elementu DIV, wyśrodkuj go i wyśrodkuj obraz wewnątrz tego elementu DIV.

To wyśrodkowuje go w poziomie:

HTML:

<div class="imageContainer">
  <div class="imageCenterer">
    <img src="http://placekitten.com/200/200" />
  </div>
</div>

CSS:

.imageContainer {
  width: 100px;
  height: 100px;
  overflow: hidden;
  position: relative;
}
.imageCenterer {
  width: 1000px;
  position: absolute;
  left: 50%;
  top: 0;
  margin-left: -500px;
}
.imageCenterer img {
  display: block;
  margin: 0 auto;
}

Demo: http://jsfiddle.net/Guffa/L9BnL/

Aby wyśrodkować go również w pionie, możesz użyć tego samego dla wewnętrznego elementu DIV, ale potrzebowałbyś wysokości obrazu, aby umieścić go całkowicie wewnątrz niego.

Guffa
źródło
Skończyło się na tym, że lewa krawędź obrazu została wyśrodkowana w elemencie „imageContainer”. Jak skomentowałem powyżej, nasz element div kontenera obrazu ma płynną szerokość i stałą wysokość.
Tom
1
@Tom: Jeśli usunę widthustawienie na kontenerze, będzie to szerokość elementu nadrzędnego, a obraz jest wyśrodkowany, nawet jeśli strona jest węższa niż obraz, tj. Tyle samo lewej krawędzi, co prawa krawędź zostanie ukryte : jsfiddle.net/Guffa/L9BnL/2
Guffa
Dzięki za inspirację. Używam pozycji: względna dla .imageCenter. W ten sposób nie potrzebuję pozycji: względna dla kontenera nadrzędnego.
user3153298
Jest wiele sprytnych sztuczek w tym pytaniu i wszystkie mają swoje wady. Niektóre działają „lepiej”, ale wcale nie są łatwe do zrozumienia. To rozwiązanie ma sens, ponieważ obraz jest normalnie wyśrodkowany w szerszym elemencie div, który jest przycinany. Czuje się źle, ale zdecydowanie działa bez łamania praw fizyki sieci. Wybrałem tę opcję spośród kilku innych, bardzo trudnych do zrozumienia sztuczek, nawet jeśli wydaje się trochę brudna.
Radley Sustaire,
9

Spóźniony do gry, ale odkryłem, że ta metoda jest niezwykle intuicyjna. https://codepen.io/adamchenwei/pen/BRNxJr

CSS

.imageContainer {
  border: 1px black solid;

  width: 450px;
  height: 200px;
  overflow: hidden;
}
.imageHolder {
  border: 1px red dotted;

  height: 100%;
  display:flex;
  align-items: center;
}
.imageItself {
  height: auto;
  width: 100%;
  align-self: center;

}

HTML

<div class="imageContainer">
  <div class="imageHolder">
    <img class="imageItself" src="http://www.fiorieconfetti.com/sites/default/files/styles/product_thumbnail__300x360_/public/fiore_viola%20-%202.jpg" />
  </div>
</div>
Ezeewei
źródło
3
Miły! Można to też uprościć. Sztuczka jest wykonywana display: flexw kontenerze nadrzędnym i align-self: centerna obrazie. Oto zoptymalizowana wersja: codepen.io/anon/pen/dWKyey
caiosm1005
5

Nie używaj stałej lub jawnej szerokości lub wysokości w tagu obrazu. Zamiast tego zakoduj to:

      max-width:100%;
      max-height:100%;

np .: http://jsfiddle.net/xwrvxser/1/

skórzana kurtka 4
źródło
1
To pozostawia miejsce wokół obrazu, którego, jak sądzę, próbują uniknąć.
Koniec
3

Jestem wielkim fanem robienia obrazu jako tła div / node - wtedy możesz po prostu użyć background-position: centeratrybutu, aby go wyśrodkować niezależnie od rozmiaru ekranu

Shain Lafazan
źródło
9
Nie jest to przystępny sposób wykorzystania obrazów. Może działać dobrze w przypadku obrazów dekoracyjnych, ale każdy obraz, który ma charakter informacyjny, wymaga tekstu alternatywnego.
user2532030
0

Szerokość i wysokość to tylko przykładowo:

parentDiv{
    width: 100px;
    height: 100px;
    position:relative; 
}
innerDiv{
    width: 200px;
    height: 200px;
    position:absolute; 
    margin: auto;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
}

Musi zadziałać, jeśli lewa i górna część nadrzędnego elementu DIV nie znajdują się na samej górze i po lewej stronie okna ekranu. Mi to pasuje.

Панайот Толев
źródło
Nie wydawało się to robić różnicy. Nie jestem pewien, czy ma to coś wspólnego z faktem, że szerokość jest płynna, podczas gdy wysokość jest ustalona na tym, co będzie nadrzędnym elementem div.
Tom
2
Ta technika działa, jeśli obraz jest mniejszy niż kontener.
otherDewi
0

Uważam, że jest to bardziej eleganckie rozwiązanie, bez flexu:

.wrapper {
    overflow: hidden;
}
.wrapper img {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    /* height: 100%; */ /* optional */
}
Cezar D.
źródło
0

Opierając się na świetnej odpowiedzi @ yunzen:

Domyślam się, że wiele osób poszukujących tego tematu próbuje użyć dużego obrazu jako obrazu tła „bohatera”, na przykład na stronie głównej. W takim przypadku często chcieliby, aby tekst pojawił się na obrazie i dobrze go skalował na urządzeniach mobilnych.

Oto idealny CSS dla takiego obrazu tła (użyj go na <img>tagu):

/* Set left edge of inner element to 50% of the parent element */
margin-left: 50%;

/* Move to the left by 50% of own width */
transform: translateX(-50%);

/* Scale image...(101% - instead of 100% - avoids possible 1px white border on left of image due to rounding error */
width: 101%;

/* ...but don't scale it too small on mobile devices - adjust this as needed */
min-width: 1086px;

/* allow content below image to appear on top of image */
position: absolute;
z-index: -1;

/* OPTIONAL - try with/without based on your needs */
top: 0;

/* OPTIONAL - use if your outer element containing the img has "text-align: center" */
left: 0;
Dave Koo
źródło
-1

Jedną z opcji, której możesz użyć, jest object-fit: coverto, że zachowuje się trochę jak background-size: cover. Więcej o dopasowaniu do obiektu .

zignoruj ​​wszystkie JS poniżej, to tylko do demonstracji.

Kluczowe jest to, że musisz ustawić obraz wewnątrz opakowania i nadać mu następujące właściwości.

.wrapper img {
  height: 100%;
  width: 100%;
  object-fit: cover;
}

Stworzyłem demo poniżej, w którym zmieniasz wysokość / szerokość opakowania i widzisz w grze. Obraz będzie zawsze wyśrodkowany w pionie i poziomie. Zajmie 100% swojej nadrzędnej szerokości i wysokości i nie zostanie rozciągnięty / zgnieciony. Oznacza to, że proporcje obrazu są zachowane. Zamiast tego zmiany są wprowadzane poprzez powiększanie / pomniejszanie.

Jedynym minusem object-fitjest to, że nie działa na IE11.

// for demo only
const wrapper = document.querySelector('.wrapper');
const button = document.querySelector('button');
const widthInput = document.querySelector('.width-input');
const heightInput = document.querySelector('.height-input');


const resizeWrapper = () => {
  wrapper.style.width = widthInput.value + "px";
  wrapper.style.height = heightInput.value + "px";
}

button.addEventListener("click", resizeWrapper);
.wrapper {
  overflow: hidden;
  max-width: 100%;
  margin-bottom: 2em;
  border: 1px solid red;
}

.wrapper img {
  display: block;
  height: 100%;
  width: 100%;
  object-fit: cover;
}
<div class="wrapper">
  <img src="https://i.imgur.com/DrzMS8i.png">
</div>


<!-- demo only -->
<lable for="width">
  Width: <input name="width" class='width-input'>
</lable>
<lable for="height">
  height: <input name="height" class='height-input'>
</lable>
<button>change size!</button>

wolt
źródło