รักษาอัตราส่วนของภาพเมื่อเปลี่ยนความสูง


114

เมื่อใช้โมเดล CSS flex box ฉันจะบังคับให้รูปภาพคงอัตราส่วนได้อย่างไร

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

สังเกตว่ารูปภาพยืดหรือหดเพื่อให้เต็มความกว้างของคอนเทนเนอร์ ไม่เป็นไร แต่เราสามารถยืดหรือหดความสูงเพื่อรักษาสัดส่วนของภาพได้หรือไม่?

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
เท่าที่ฉันรู้ทางออกที่ดีที่สุดคือใช้ a <div>กับ CSSbackground-image: url(...);background-size:contain; background-repeat:no-repeat
Blazemonger

1
มีโอกาสในการขายที่น่าสนใจอยู่ที่นี่ แต่ถ้ารูปภาพไม่ได้มีอัตราส่วนเดียวกันแล้วล่ะ? การเพิ่มและ 'พิเศษ' div เป็นสิ่งสุดท้ายที่เราต้องกังวล ทำไมไม่ใช้กรณีทดสอบเช่นนี้แทน: jsfiddle.net/sheriffderek/999Lg9qv
sheriffderek

คำตอบ:


68

สำหรับแท็ก img หากคุณกำหนดด้านใดด้านหนึ่งจากนั้นอีกด้านหนึ่งจะถูกปรับขนาดเพื่อรักษาอัตราส่วนและโดยค่าเริ่มต้นรูปภาพจะขยายเป็นขนาดดั้งเดิม

ใช้ข้อเท็จจริงนี้หากคุณรวมแท็ก img แต่ละแท็กลงในแท็ก div และตั้งค่าความกว้างเป็น 100% ของ div ระดับบนสุดความสูงจะเป็นไปตามอัตราส่วนตามที่คุณต้องการ

http://jsfiddle.net/0o5tpbxg/

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

2
ฉันรู้ว่ามีคำตอบสองคำที่แนะนำให้ใช้ div แต่ฉันกำลังทำเครื่องหมายคำตอบนี้ว่าถูกต้องเพราะอธิบายได้ว่าเหตุใดความสูงของภาพจึงแตกต่างจากที่ฉันคาดไว้ อันที่จริงนี่เป็นพฤติกรรมปกติและถูกต้องและไม่น่าจะ "แก้ไข" ได้เนื่องจากไม่ใช่ข้อบกพร่อง
coderMe

18
แต่คำตอบนี้ไม่ได้พูดถึง flexbox เพราะรูปภาพทำงานแตกต่างกันใน flexbox container การตั้งค่าด้านหนึ่งจะไม่ปรับขนาดอีกด้านตามสัดส่วน การห่อไว้ในคอนเทนเนอร์ที่ไม่ใช่ flexbox ช่วยได้ แต่นั่นเป็นการเพิ่มมาร์กอัปที่ไม่จำเป็นซึ่งสูญเสียความหมาย
Robert Koritnik

3
ดูเหมือนว่าคุณไม่จำเป็นต้องใช้ div การตัดเพื่อให้ทำงานนี้: jsfiddle.net/xLc2Le0k/120
Rick Strahl

4
แต่แล้วเรื่องนี้ล่ะ? jsfiddle.net/xLc2Le0k/15 ฉันคิดว่าการแก้ปัญหานี้เป็นความบังเอิญที่ใช้งานได้เพราะภาพมีอัตราส่วนเท่ากันทั้งหมด หมายเหตุด้านข้าง: ไม่มี 'ความหมาย' ใด ๆ ที่สูญเสียไปจากการวางภาพใน div สำหรับการวางตำแหน่ง / โดยเฉพาะอย่างยิ่งเมื่อจัดการกับภาพที่ตอบสนอง
นายอำเภอ

1
วิธีแก้ปัญหาที่สะอาดที่สุดอย่างจริงจังและใช้ได้กับภาพ!
shaneonabike

64

เพื่อป้องกันไม่ให้ภาพยืดในแกนใดแกนหนึ่งภายในแม่แบบยืดหยุ่นฉันได้พบวิธีแก้ปัญหาสองสามวิธี

คุณสามารถลองใช้วัตถุที่พอดีกับภาพซึ่งเช่น

object-fit: contain;

http://jsfiddle.net/ykw3sfjd/

หรือคุณสามารถเพิ่มกฎ flex-specfic ซึ่งอาจทำงานได้ดีกว่าในบางกรณี

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

4
ความพอดีของวัตถุอาจเป็นทางออกที่ดีหากไม่ขาดการสนับสนุนใน IE และ Edgeถึง Edge 14
daniels


ฉันใช้ทางเลือกนั้นด้วยตัวเองทำงานได้ดีมาก
Matty

1
ตอนนี้ @daniels Edge มีการพัฒนาแบบ Object-Fit: developer.microsoft.com/en-us/microsoft-edge/platform/status/…
AMDG

1
object-fit: contain;ใช้เคล็ดลับสำหรับฉันเมื่อฉันมีปัญหาใน chrome เท่านั้น ff ก็ใช้ได้
Benjamin Peter

53

ไม่จำเป็นต้องเพิ่ม div ที่มี

ค่าเริ่มต้นสำหรับคุณสมบัติ css "align-items" คือ "stretch" ซึ่งเป็นสาเหตุที่ทำให้รูปภาพของคุณถูกยืดจนเต็มความสูงดั้งเดิม การตั้งค่าคุณสมบัติ css "align-items" เป็น "flex-start" จะช่วยแก้ปัญหาของคุณได้

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

3
อ่า ... ขอบคุณที่ทำในสิ่งที่สนับสนุนจริงๆ ฉันอ่านคำตอบจนถึงตอนนั้นและไม่อยากจะเชื่อเลยว่าทั้งหมดที่เรามีคือแฮ็กที่สกปรก ..
Félix Gagnon-Grenier

35

ภาพส่วนใหญ่ที่มีขนาดที่แท้จริงซึ่งมีขนาดตามธรรมชาติเช่นเดียวกับjpegภาพ ถ้าขนาดที่ระบุกำหนดหนึ่งของทั้งกว้างและความสูงที่ค่าที่หายไปจะถูกกำหนดโดยใช้อัตราส่วนที่แท้จริง ... - ดูMDN

แต่นั่นไม่ได้ผลตามที่คาดไว้หากรูปภาพที่ถูกตั้งค่าเป็นรายการที่ยืดหยุ่นโดยตรงด้วยโมดูลเลย์เอาต์กล่องยืดหยุ่นระดับ 1ในปัจจุบันเท่าที่ฉันรู้

ดูการอภิปรายและรายงานข้อบกพร่องเหล่านี้อาจเกี่ยวข้อง:

  • Flexbugs # 14 - Chrome / Flexbox Intrinsic Sizing ไม่ได้ใช้อย่างถูกต้อง
  • Firefox Bug 972595 - คอนเทนเนอร์แบบยืดหยุ่นควรใช้ "flex-Basis" แทน "width" สำหรับการคำนวณความกว้างภายในของรายการที่ยืดหยุ่น
  • Chromium Issue 249112 - ใน Flexbox อนุญาตให้ใช้อัตราส่วนภายในเพื่อแจ้งการคำนวณขนาดหลัก

วิธีแก้ปัญหาเบื้องต้นคุณสามารถ<img>ใช้ a <div>หรือ a <span>หรือมากกว่านั้นก็ได้

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 ขนาดของรายการ Flex ขั้นต่ำโดยนัย

เพื่อให้มีขนาดต่ำสุดเริ่มต้นที่เหมาะสมมากขึ้นสำหรับรายการแบบยืดหยุ่นข้อกำหนดนี้จะแนะนำค่าอัตโนมัติใหม่เป็นค่าเริ่มต้นของคุณสมบัติความกว้างต่ำสุดและความสูงต่ำสุดที่กำหนดไว้ใน CSS 2.1


หรือคุณสามารถใช้tableเลย์เอาต์CSS แทนซึ่งคุณจะได้ผลลัพธ์ที่คล้ายกันเนื่องจากflexboxมันจะทำงานบนเบราว์เซอร์อื่น ๆ แม้กระทั่งสำหรับ 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>


ข้อมูลความต้องการแรกบนเบราว์เซอร์ใหม่ที่สนับสนุน.slider > div{min-width:0} min-width: auto
Oriol

3
ข้อมูลจำเพาะ flexbox นำเสนอautoค่าใหม่เป็นค่าเริ่มต้นสำหรับmin-widthและmin-height(ก่อนหน้านี้เป็น0) Chrome ยังไม่ได้ใช้งานดังนั้นตัวอย่างแรกของคุณจึงใช้งานได้ แต่เบราว์เซอร์ใหม่จำเป็นต้องใช้เพื่ออนุญาตให้รายการ flex หดเล็กกว่าความกว้างเริ่มต้นของรูปภาพ
Oriol

2
+1 สิ่งนี้ควรเป็นคำตอบที่ยอมรับได้เพราะมันพูดถึงภาพในโมเดล flexbox ซึ่งเป็นปัญหาหลักในกรณีนี้ ...
Robert Koritnik

ตารางจะดีมากหากเค้าโครงของคุณไม่เปลี่ยนไปตามจุดพักต่างๆ แต่ไม่น่าจะเป็นไปได้ในทุกวันนี้
นายอำเภอ

1
แล้วเมื่อรูปภาพไม่ได้มีอัตราส่วนเท่ากันทั้งหมด? jsfiddle.net/sheriffderek/5u7y21we
sheriffderek

6

เมื่อเร็ว ๆ นี้ฉันเล่นกับ flexbox และฉันได้หาวิธีแก้ปัญหานี้ผ่านการทดลองและเหตุผลต่อไปนี้ อย่างไรก็ตามในความเป็นจริงฉันไม่แน่ใจว่านี่คือสิ่งที่เกิดขึ้นหรือไม่

หากความกว้างจริงได้รับผลกระทบจากระบบเฟล็กซ์ ดังนั้นหลังจากความกว้างขององค์ประกอบถึงความกว้างสูงสุดของพาเรนต์แล้วความกว้างพิเศษที่กำหนดใน css จะถูกละเว้น จากนั้นจึงปลอดภัยที่จะตั้งค่าความกว้างเป็น 100%

เนื่องจากความสูงของแท็ก img นั้นมาจากรูปภาพเองดังนั้นการตั้งค่าความสูงเป็น 0% จึงสามารถทำอะไรบางอย่างได้ (นี่คือจุดที่ฉันไม่ชัดเจนว่าเป็นอะไร ... แต่มันก็สมเหตุสมผลสำหรับฉันที่ควรแก้ไข)

การสาธิต

(จำได้ว่าเห็นที่นี่ครั้งแรก!)

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

ใช้งานได้เฉพาะใน Chrome เท่านั้น


น่าสนใจ แต่ดูเหมือนข้อบกพร่อง ตามข้อกำหนด " เปอร์เซ็นต์จะคำนวณตามความสูงของบล็อกที่มีกล่องที่สร้างขึ้นหากไม่ได้ระบุความสูงของบล็อกที่บรรจุไว้อย่างชัดเจน (กล่าวคือขึ้นอยู่กับความสูงของเนื้อหา) และองค์ประกอบนี้ไม่ได้อยู่ในตำแหน่งอย่างแน่นอน ค่าจะคำนวณเป็นauto " นั่นคือสิ่งที่เกิดขึ้นบน Firefox
Oriol

jsfiddle.net/xLc2Le0k/8อธิบายความแตกต่างของ ff และ chrome สำหรับสิ่งนี้
มูฮัมหมัด Umer

ความกว้างดูเหมือนจะทำใน ff ความสูงที่ทำในโครเมี่ยม
Muhammad Umer

เป็นเรื่องที่น่าสนใจ แต่ฉันกลัวว่าโซลูชัน X-browser เท่านั้นไม่ใช่วิธีแก้ปัญหาจริงๆ ความคิดเห็นของคุณซอที่นี่: jsfiddle.net/xLc2Le0k/8เป็นสิ่งที่น่าสนใจอย่างยิ่งใน FF สิ่งนี้ดูเหมือนจะแสดงให้เห็นว่า FF กำลังทำให้ความสูงของภาพ "ได้สัดส่วน" กับความสูงของภาพถ้ามันเป็น 100% อย่างแท้จริง กล่าวอีกนัยหนึ่ง img ไม่ "รู้" เกี่ยวกับการแสดงผลของคอนเทนเนอร์: flex สิ่งนี้อธิบายได้ว่าทำไมใน FF หากคุณตั้งค่าความกว้างของ img เป็น 100% รูปภาพจึงสูงกว่าถ้าคุณตั้งค่าความกว้างเป็นอัตโนมัติ
coderMe

นี่คือค่อนข้างใกล้ ... แต่ทำงานได้เฉพาะใน Chrome: jsfiddle.net/sheriffderek/xLc2Le0k/270
sheriffderek

2

คาดว่าพฤติกรรมนี้ ภาชนะดิ้นจะยืดลูกทั้งหมดโดยปริยาย รูปภาพไม่มีข้อยกเว้น (กล่าวคือผู้ปกครองจะมีalign-items: stretchทรัพย์สิน)

ในการรักษาอัตราส่วนเรามีสองวิธี:

  1. แทนที่align-items: stretchคุณสมบัติเริ่มต้นเป็นalign-items: flex-startหรือalign-self: centerอื่น ๆ http://jsfiddle.net/e394Lqnt/3/

หรือ

  1. ตั้งค่าคุณสมบัติการจัดแนวเฉพาะสำหรับเด็กเอง: เช่นalign-self: centerหรือalign-self: flex-startอื่น ๆ http://jsfiddle.net/e394Lqnt/2/

-1

อันที่จริงฉันพบว่าคอนเทนเนอร์ของแท็กรูปภาพต้องมีความสูงเพื่อที่จะรักษาอัตราส่วนของรูปภาพไว้ ตัวอย่างเช่น>

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

จากนั้นใน html คอนเทนเนอร์ของคุณจะห่อภาพแท็ก

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

งานนี้สำหรับ IE และเบราว์เซอร์อื่น ๆ


-1

ฉันเพิ่งมีปัญหาเดียวกัน ใช้การจัดแนวแบบยืดหยุ่นเพื่อจัดองค์ประกอบของคุณให้อยู่กึ่งกลาง คุณจำเป็นต้องใช้align-items: centerแทนalign-content: center. การดำเนินการนี้จะรักษาอัตราส่วนภาพไว้ในขณะที่การจัดแนวเนื้อหาจะไม่คงอัตราส่วนไว้

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.