Duy trì tỷ lệ khung hình khi thay đổi chiều cao


114

Bằng cách sử dụng mô hình hộp linh hoạt CSS, làm cách nào để buộc hình ảnh duy trì tỷ lệ khung hình?

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

Lưu ý rằng hình ảnh kéo dài hoặc thu nhỏ để lấp đầy chiều rộng của vùng chứa. Điều đó tốt, nhưng chúng ta có thể kéo dài hoặc thu nhỏ chiều cao để duy trì tỷ lệ hình ảnh không?

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
Theo như tôi biết, giải pháp tốt nhất là sử dụng một <div>với CSSbackground-image: url(...);background-size:contain; background-repeat:no-repeat
Blazemonger

1
Có một số khách hàng tiềm năng thú vị ở đây, nhưng còn khi các hình ảnh không có cùng tỷ lệ thì sao? Thêm và div 'thêm', là điều cuối cùng chúng ta cần lo lắng. Tại sao không sử dụng một trường hợp thử nghiệm như thế này thay vì: jsfiddle.net/sheriffderek/999Lg9qv
sheriffderek

Câu trả lời:


68

Đối với thẻ img nếu bạn xác định một mặt thì mặt còn lại sẽ được thay đổi kích thước để giữ nguyên tỷ lệ khung hình và theo mặc định, hình ảnh sẽ mở rộng về kích thước ban đầu.

Sử dụng thực tế này nếu bạn bọc mỗi thẻ img thành thẻ div và đặt chiều rộng của nó thành 100% div mẹ thì chiều cao sẽ theo tỷ lệ khung hình như bạn muốn.

http://jsfiddle.net/0o5tpbxg/

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

2
Tôi biết có hai câu trả lời đề xuất sử dụng div, nhưng tôi đánh dấu câu trả lời này là đúng vì nó giải thích tại sao chiều cao hình ảnh khác với tôi mong đợi. Trên thực tế, đây là hành vi bình thường và đúng, và không có khả năng được "sửa", vì nó không phải là một lỗi.
coderMe

18
Nhưng câu trả lời này không nói gì về flexbox, vì hình ảnh hoạt động khác nhau trong vùng chứa flexbox. Đặt một bên sẽ không thay đổi kích thước theo tỷ lệ bên kia. Gói chúng trong vùng chứa không flexbox giúp ích nhưng điều đó làm tăng thêm đánh dấu không cần thiết làm mất ngữ nghĩa.
Robert Koritnik

3
Có vẻ như bạn không cần một div bao bọc để làm việc này: jsfiddle.net/xLc2Le0k/120
Rick Strahl

4
Nhưng, điều này thì sao? jsfiddle.net/xLc2Le0k/15 Tôi nghĩ rằng giải pháp này là một sự may mắn chỉ hoạt động vì tất cả các hình ảnh đều có cùng tỷ lệ. lưu ý bên cạnh: không có bất kỳ 'ngữ nghĩa' nào bị mất khi đặt một hình ảnh trong một div để định vị / đặc biệt là khi xử lý các hình ảnh đáp ứng.
sheriffderek

1
Nghiêm túc là giải pháp sạch nhất và nó hoạt động với hình ảnh!
shaneonabike

64

Để giữ cho hình ảnh không bị kéo giãn theo một trong hai trục bên trong một phụ kiện flex, tôi đã tìm thấy một số giải pháp.

Bạn có thể thử sử dụng object-fit trên hình ảnh, ví dụ:

object-fit: contain;

http://jsfiddle.net/ykw3sfjd/

Hoặc bạn có thể thêm các quy tắc flex-specfic có thể hoạt động tốt hơn trong một số trường hợp.

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

4
đối tượng điều chỉnh kích thước có thể là một giải pháp tốt được nó không thiếu hỗ trợ trong IE và Edge thậm chí lên đến Edge 14
daniels


Bản thân tôi đã sử dụng dự phòng đó, hoạt động rất tốt.
Matty Balaam

1
@daniels Edge hiện đang phát triển object-fit: developer.microsoft.com/en-us/microsoft-edge/platform/status/…
AMDG

1
object-fit: contain;đã làm thủ thuật cho tôi, khi tôi chỉ gặp vấn đề trong chrome, ff là ổn.
Benjamin Peter

53

Không cần thêm div có chứa.

Mặc định cho thuộc tính css "align-items" là "Stretch", đây là nguyên nhân khiến hình ảnh của bạn bị kéo dài đến toàn bộ chiều cao ban đầu của nó. Đặt thuộc tính css "align-items" thành "flex-start" sẽ khắc phục được sự cố của bạn.

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

3
Ahh ... cảm ơn vì đã thực sự làm mọi việc theo cách được hỗ trợ. Tôi đã đọc các câu trả lời cho đến khi một điều đó và không thể tin rằng tất cả chúng tôi đã có được hacks bẩn ..
Félix Gagnon-Grenier

35

Hầu hết các hình ảnh có kích thước nội tại , đó là kích thước tự nhiên, giống như một jpeghình ảnh. Nếu kích thước được chỉ định xác định một trong cả chiều rộng và chiều cao, thì giá trị còn thiếu được xác định bằng cách sử dụng tỷ lệ nội tại ... - xem MDN .

Nhưng điều đó không hoạt động như mong đợi nếu các hình ảnh đang được đặt làm các mục linh hoạt trực tiếp với Mô-đun bố cục hộp linh hoạt hiện tại Cấp 1 , theo như tôi biết.

Xem các cuộc thảo luận này và báo cáo lỗi có thể liên quan:

  • Flexbugs # 14 - Kích thước nội tại của Chrome / Flexbox không được triển khai chính xác.
  • Firefox Bug 972595 - Vùng chứa linh hoạt nên sử dụng "cơ sở linh hoạt" thay vì "chiều rộng" để tính toán chiều rộng nội tại của các mục linh hoạt
  • Chromium Issue 249112 - Trong Flexbox, cho phép tỷ lệ khung hình nội tại thông báo cho phép tính kích thước chính.

Để giải quyết vấn đề, bạn có thể kết hợp từng thứ <img>bằng một <div>hoặc một <span>, hoặc lâu hơn.

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 Kích thước tối thiểu ngụ ý của các hạng mục linh hoạt

Để cung cấp kích thước tối thiểu mặc định hợp lý hơn cho các mục flex , thông số kỹ thuật này giới thiệu một giá trị tự động mới làm giá trị ban đầu của thuộc tính min-widthmin-height được xác định trong CSS 2.1.


Ngoài ra, bạn có thể sử dụng tablebố cục CSS để thay thế, bạn sẽ nhận được kết quả tương tự vì flexboxnó sẽ hoạt động trên nhiều trình duyệt hơn, ngay cả đối với 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>


Đoạn mã đầu tiên cần .slider > div{min-width:0}trên các trình duyệt mới hỗ trợ min-width: auto.
Oriol

3
Thông số flexbox đã giới thiệu một autogiá trị mới làm giá trị mặc định cho min-widthmin-height(trước đây là 0). Chrome chưa triển khai, vì vậy đoạn mã đầu tiên của bạn hoạt động. Nhưng các trình duyệt mới cần nó để cho phép các mục linh hoạt thu nhỏ hơn chiều rộng mặc định của hình ảnh.
Oriol

2
1 này nên được chấp nhận câu trả lời vì nó nói về hình ảnh trong mô hình flexbox đó là vấn đề gốc trong trường hợp này ...
Robert Koritnik

Bảng là tuyệt vời nếu bố cục của bạn không thay đổi ở các điểm ngắt khác nhau, nhưng điều đó khó xảy ra trong những ngày này.
sheriffderek

1
Còn khi các hình ảnh không có cùng tỷ lệ thì sao? jsfiddle.net/sheriffderek/5u7y21we
sheriffderek

6

Gần đây, tôi đã chơi flexbox và tôi đã tìm ra giải pháp cho điều này thông qua thử nghiệm và lý luận sau đây. Tuy nhiên, trong thực tế, tôi không chắc liệu đây có phải chính xác những gì xảy ra hay không.

Nếu chiều rộng thực bị ảnh hưởng bởi hệ thống flex. Vì vậy, sau khi chiều rộng của các phần tử đạt đến chiều rộng tối đa của phần tử mẹ, chúng sẽ bỏ qua chiều rộng bổ sung được đặt trong css. Sau đó, có thể an toàn để đặt chiều rộng thành 100%.

Vì chiều cao của thẻ img được lấy từ chính hình ảnh nên việc đặt chiều cao thành 0% có thể làm được điều gì đó. (đây là nơi tôi không rõ là gì ... nhưng tôi thấy có lý khi nó nên sửa nó)

BẢN GIỚI THIỆU

(hãy nhớ xem nó ở đây đầu tiên!)

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

Chỉ hoạt động trong chrome


Thật thú vị, nhưng nó có vẻ là một lỗi. Theo thông số kỹ thuật , " Phần trăm được tính theo chiều cao của khối chứa của hộp được tạo. Nếu chiều cao của khối chứa không được chỉ định rõ ràng (nghĩa là, nó phụ thuộc vào chiều cao nội dung) và phần tử này không được định vị tuyệt đối , giá trị được tính thànhauto ". Đó là những gì xảy ra trên Firefox.
Oriol

jsfiddle.net/xLc2Le0k/8 giải thích sự khác biệt trong ff và chrome. cho điều này
Muhammad Umer

chiều rộng dường như đang làm trong ff chiều cao đang làm trong chrome.
Muhammad Umer

Điều đó thật thú vị, nhưng tôi e rằng các giải pháp chỉ dành cho trình duyệt X không thực sự là giải pháp. Tuy nhiên, fiddle đã nhận xét của bạn, tại đây: jsfiddle.net/xLc2Le0k/8 hoàn toàn hấp dẫn trong FF. Điều này có vẻ cho thấy FF đang làm cho chiều cao hình ảnh "tương xứng" với chiều cao của hình ảnh nếu nó thực sự là 100%. Nói cách khác, img không "biết" về màn hình của vùng chứa: flex. Điều này giải thích tại sao, trong FF, nếu bạn đặt chiều rộng của img thành 100%, hình ảnh sẽ cao hơn so với khi bạn đặt chiều rộng thành tự động.
coderMe

Điều này khá gần ... nhưng chỉ hoạt động trong Chrome: jsfiddle.net/sheriffderek/xLc2Le0k/270
sheriffderek

2

Hành vi này được mong đợi. flex container sẽ kéo giãn tất cả các con của nó theo mặc định. Hình ảnh không có ngoại lệ. (tức là, cha mẹ sẽ có align-items: stretchtài sản)

Để giữ tỷ lệ khung hình, chúng tôi có hai giải pháp:

  1. Thay thế thuộc tính mặc định align-items: stretchthành align-items: flex-starthoặc align-self: centerv.v., http://jsfiddle.net/e394Lqnt/3/

hoặc là

  1. Đặt thuộc tính căn chỉnh dành riêng cho chính phần tử con: like, align-self: centerhoặc align-self: flex-startv.v. http://jsfiddle.net/e394Lqnt/2/

-1

Trên thực tế, tôi phát hiện ra rằng vùng chứa của thẻ hình ảnh cần phải có chiều cao để giữ tỷ lệ của hình ảnh. ví dụ>

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

thì trong html vùng chứa của bạn sẽ bao bọc hình ảnh thẻ

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

điều này hoạt động cho IE và các trình duyệt khác


-1

Tôi chỉ có cùng một vấn đề. Sử dụng căn chỉnh linh hoạt để căn giữa các phần tử của bạn. Bạn cần sử dụng align-items: centerthay vì align-content: center. Điều này sẽ duy trì tỷ lệ khung hình, trong khi căn chỉnh nội dung sẽ không giữ nguyên tỷ lệ khung hình.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.