สร้างเอฟเฟกต์ภาพที่ตอบสนองด้วยการไล่ระดับสี CSS และอัตราส่วนภาพ
เผยแพร่แล้ว: 2022-03-10aspect-ratio
ที่ได้รับการสนับสนุนใหม่ร่วมกับ object-fit
ช่วยแก้ไขอาการปวดหัวในอดีต! มาเรียนรู้การใช้คุณสมบัติเหล่านี้กัน นอกเหนือจากการสร้างเอฟเฟกต์การไล่ระดับสีที่ตอบสนองได้เพื่อให้มีไหวพริบยิ่งขึ้นเพื่อเตรียมพร้อมสำหรับเอฟเฟกต์ภาพในอนาคต เราจะตั้งค่าองค์ประกอบการ์ดที่มีรูปภาพขนาดใหญ่ที่ด้านบน ตามด้วยบรรทัดแรกและคำอธิบาย ปัญหาทั่วไปของการตั้งค่านี้คือเราอาจไม่สามารถควบคุม ว่า รูปภาพคืออะไรได้อย่างสมบูรณ์เสมอไป และที่สำคัญกว่านั้นคือการจัดวางของเรา ขนาด คืออะไร และแม้ว่าจะสามารถแก้ไขได้ด้วยการครอบตัดล่วงหน้า แต่เรายังคงพบปัญหาเนื่องจากคอนเทนเนอร์ขนาดที่ตอบสนองได้ ผลที่ตามมาคือตำแหน่งที่ไม่สม่ำเสมอของเนื้อหาในการ์ดซึ่งโดดเด่นจริงๆ เมื่อคุณแสดงแถวของการ์ด
วิธีแก้ปัญหาก่อนหน้านี้นอกเหนือจากการครอบตัดอาจเป็นการเปลี่ยนจาก inline img
เป็น div
เปล่าที่มีอยู่เพื่อนำเสนอภาพผ่าน background-image
เท่านั้น ฉันใช้วิธีแก้ปัญหานี้หลายครั้งแล้วในอดีต ข้อดีอย่างหนึ่งที่มีคือการใช้ เคล็ดลับที่เก่ากว่าสำหรับอัตราส่วนกว้างยาว ซึ่งใช้องค์ประกอบที่มีความสูงเป็นศูนย์และตั้งค่า padding-bottom
ภายใน การตั้งค่าช่องว่างภายในเป็นเปอร์เซ็นต์จะส่งผลให้ค่าที่คำนวณสุดท้ายสัมพันธ์กับความกว้างขององค์ประกอบ คุณอาจใช้แนวคิดนี้เพื่อรักษาอัตราส่วน 16:9 สำหรับการฝังวิดีโอ ซึ่งในกรณีนี้จะพบค่าช่องว่างภายในด้วยสูตร: 9/16 = 0.5625 * 100% = 56.26%
แต่เราจะ สำรวจคุณสมบัติ CSS สมัยใหม่สองคุณสมบัติ ที่ไม่เกี่ยวกับคณิตศาสตร์เพิ่มเติม ให้ความยืดหยุ่นมากขึ้น และยังช่วยให้รักษาความหมายโดยใช้ img
จริงแทน div
ที่ว่างเปล่า
ขั้นแรก ให้กำหนดความหมายของ HTML รวมถึงการใช้รายการที่ไม่เรียงลำดับเป็นคอนเทนเนอร์ของการ์ด:
<ul class="card-wrapper"> <li class="card"> <img src="" alt=""> <h3>A Super Wonderful Headline</h3> <p>Lorem ipsum sit dolor amit</p> </li> <!-- additional cards --> </ul>
ต่อไป เราจะสร้างชุดสไตล์พื้นฐานขั้นต่ำสำหรับองค์ประกอบ . .card
เราจะกำหนดรูปแบบภาพพื้นฐานสำหรับตัวการ์ดเอง การอัปเดตอย่างรวดเร็วสำหรับพาดหัว h3
ที่คาดหวัง จากนั้นรูปแบบที่จำเป็นเพื่อเริ่มจัดรูปแบบภาพการ์ด
.card { background-color: #fff; border-radius: 0.5rem; box-shadow: 0.05rem 0.1rem 0.3rem -0.03rem rgba(0, 0, 0, 0.45); padding-bottom: 1rem; } .card > :last-child { margin-bottom: 0; } .card h3 { margin-top: 1rem; font-size: 1.25rem; } img { border-radius: 0.5rem 0.5rem 0 0; width: 100%; } img ~ * { margin-left: 1rem; margin-right: 1rem; }
กฎข้อสุดท้ายใช้ตัว รวมแบบพี่น้องทั่วไป เพื่อเพิ่มระยะขอบในแนวนอนให้กับองค์ประกอบใดๆ ที่ตามหลัง img
เนื่องจากเราต้องการให้รูปภาพตรงกับด้านข้างของการ์ด
และความคืบหน้าของเราจนถึงตอนนี้นำเราไปสู่ลักษณะที่ปรากฏของการ์ดต่อไปนี้:
สุดท้าย เราจะสร้าง .card-wrapper
สำหรับเลย์เอาต์ที่ตอบสนองอย่างรวดเร็วโดยใช้กริด CSS การดำเนินการนี้จะลบสไตล์รายการเริ่มต้นออกด้วย
.card-wrapper { list-style: none; padding: 0; margin: 0; display: grid; grid-template-columns: repeat(auto-fit, minmax(30ch, 1fr)); grid-gap: 1.5rem; }
หมายเหตุ : หากเทคนิคกริดนี้ไม่คุ้นเคยกับคุณ ให้ทบทวนคำอธิบายในบทช่วยสอนของฉันเกี่ยวกับโซลูชันที่ทันสมัยสำหรับกริด 12 คอลัมน์
เมื่อใช้สิ่งนี้และกับการ์ดทั้งหมดที่มีรูปภาพที่มีพาธต้นทางที่ถูกต้อง สไตล์ . .card-wrapper
ของเราให้เลย์เอาต์ต่อไปนี้:
ดังที่แสดงในภาพตัวอย่าง สไตล์พื้นฐานเหล่านี้ไม่เพียงพอที่จะมีภาพอย่างเหมาะสมตามขนาดที่เป็นธรรมชาติที่แตกต่างกัน เราต้องการวิธีที่จะจำกัดภาพเหล่านี้อย่างสม่ำเสมอและสม่ำเสมอ
เปิดใช้งานขนาดภาพที่เหมือนกันกับ object-fit
ดังที่ได้กล่าวไว้ก่อนหน้านี้ ก่อนหน้านี้คุณอาจทำการอัปเดตในสถานการณ์นี้เพื่อเปลี่ยนรูปภาพที่จะเพิ่มผ่าน background-image
แทน และใช้ background-size: cover
เพื่อจัดการการปรับขนาดรูปภาพอย่างสวยงาม หรือคุณอาจพยายามบังคับใช้การครอบตัดล่วงหน้า (ยังคงเป็นเป้าหมายที่คุ้มค่า เนื่องจากการลดขนาดรูปภาพใดๆ จะช่วยเพิ่มประสิทธิภาพได้!)
ตอนนี้ เรามีพร็อพเพอร์ตี้ object-fit
ซึ่งช่วยให้แท็ก img
ทำหน้าที่เป็นคอนเทนเนอร์สำหรับรูปภาพได้ และมันมาพร้อมกับค่า cover
เช่นกันซึ่งส่งผลให้เกิดเอฟเฟกต์ที่คล้ายกับโซลูชันรูปภาพพื้นหลัง แต่ด้วยโบนัสของ การรักษาความหมาย ของรูปภาพในบรรทัด ลองใช้ดูว่ามันทำงานอย่างไร
เราจำเป็นต้องจับคู่กับมิติ height
เพื่อเป็นแนวทางเพิ่มเติมว่าเราต้องการให้คอนเทนเนอร์รูปภาพทำงานอย่างไร (จำได้ว่าเราได้เพิ่ม width: 100%
ไว้แล้ว) และเราจะใช้ฟังก์ชัน max()
เพื่อเลือก 10rem
หรือ 30vh
ขึ้นอยู่กับว่าส่วนใดมีขนาดใหญ่กว่าในบริบทที่กำหนด ซึ่งจะป้องกันไม่ให้ความสูงของภาพลดลงมากเกินไปในวิวพอร์ตที่เล็กกว่า หรือ เมื่อผู้ใช้ตั้งค่าการซูมขนาดใหญ่
img { /* ...existing styles */ object-fit: cover; height: max(10rem, 30vh); }
เคล็ดลับการเข้าถึงพิเศษ : คุณควรทดสอบเลย์เอาต์ของคุณเสมอด้วยการซูม 200% และ 400% บนเดสก์ท็อป แม้ว่าจะไม่มีการสืบค้นสื่อการ zoom
ในขณะนี้ ฟังก์ชันต่างๆ เช่น max()
สามารถช่วยแก้ไขปัญหาการจัดวางได้ บริบทอื่นที่เทคนิคนี้มีประโยชน์คือการเว้นระยะห่างระหว่างองค์ประกอบ
ด้วยการอัปเดตนี้ เราได้ปรับปรุงสิ่งต่าง ๆ อย่างแน่นอน และผลลัพธ์ของภาพก็เหมือนกับว่าเราใช้เทคนิคภาพพื้นหลังแบบเก่า:
การปรับขนาดภาพที่สอดคล้องตามการตอบสนองด้วย aspect-ratio
เมื่อใช้ object-fit
เพียงอย่างเดียว ข้อเสียอย่างหนึ่งคือ เรายังคงต้องกำหนดคำแนะนำเกี่ยวกับมิติข้อมูล
คุณสมบัติที่จะเกิดขึ้น (ขณะนี้มีอยู่ในเบราว์เซอร์ Chromium) ที่เรียกว่า aspect-ratio
จะช่วยเพิ่มความสามารถของเราในการปรับขนาดภาพอย่างสม่ำเสมอ
เมื่อใช้คุณสมบัตินี้ เราสามารถ กำหนดอัตราส่วน เพื่อปรับขนาดรูปภาพแทนการตั้งค่าขนาดที่ชัดเจน เราจะยังคงใช้มันร่วมกับ object-fit
เพื่อให้แน่ใจว่ามิติข้อมูลเหล่านี้จะส่งผลต่อรูปภาพในฐานะคอนเทนเนอร์เท่านั้น มิฉะนั้น รูปภาพอาจดูบิดเบี้ยว
นี่คือกฎรูปภาพที่อัปเดตทั้งหมดของเรา:
img { border-radius: 0.5rem 0.5rem 0 0; width: 100%; object-fit: cover; aspect-ratio: 4/3; }
เราจะเริ่มต้นด้วยอัตราส่วนภาพ 4 ⁄ 3 สำหรับบริบทการ์ดของเรา แต่คุณสามารถเลือกอัตราส่วนใดก็ได้ ตัวอย่างเช่น 1 ⁄ 1 สำหรับสี่เหลี่ยมจัตุรัส หรือ 16 ⁄ 9 สำหรับการฝังวิดีโอมาตรฐาน
นี่คือการ์ดที่อัปเดต แม้ว่าอาจเป็นเรื่องยากที่จะสังเกตเห็นความแตกต่างของภาพในกรณีนี้ เนื่องจากอัตราส่วนกว้างยาวใกล้เคียงกับรูปลักษณ์ที่เราทำได้โดยการตั้งค่า height
สำหรับ object-fit
เพียงอย่างเดียว
การตั้งค่า "อัตราส่วนภาพ" ส่งผลให้อัตราส่วนถูกคงไว้เมื่อองค์ประกอบเติบโตหรือหดตัว ในขณะที่เมื่อตั้งค่าเฉพาะ "วัตถุพอดี" และ "ความสูง" อัตราส่วนภาพจะไหลตลอดเวลาเมื่อขนาดของคอนเทนเนอร์เปลี่ยนไป
“
การเพิ่มเอฟเฟกต์ตอบสนองด้วยการไล่ระดับสี CSS และฟังก์ชั่น
ตกลง ตอนนี้เรารู้วิธีตั้งค่ารูปภาพที่มีขนาดสม่ำเสมอแล้ว มาสนุกกับมันโดยเพิ่มเอฟเฟกต์การไล่ระดับสีกัน!
เป้าหมายของเราสำหรับเอฟเฟกต์นี้คือการทำให้รูปภาพดูเหมือนจางลงในเนื้อหาการ์ด คุณอาจถูกล่อลวงให้ห่อรูปภาพในคอนเทนเนอร์ของตัวเองเพื่อเพิ่มการไล่ระดับสี แต่ด้วยงานที่เราทำในการปรับขนาดรูปภาพ เราจึงสามารถหาวิธีดำเนินการได้อย่างปลอดภัยใน . .card
หลัก
ขั้นตอนแรกคือการ กำหนดการไล่ระดับสี เราจะใช้คุณสมบัติที่กำหนดเองของ CSS เพื่อเพิ่มสีไล่ระดับสีเพื่อให้สลับเอฟเฟกต์การไล่ระดับสีได้อย่างง่ายดาย โดยเริ่มจากสีน้ำเงินเป็นสีชมพู สีสุดท้ายในการไล่ระดับสีจะเป็นสีขาวเสมอเพื่อรักษาการเปลี่ยนเป็นพื้นหลังเนื้อหาการ์ดและสร้างขอบ "ขนนก"
.card { --card-gradient: #5E9AD9, #E271AD; background-image: linear-gradient( var(--card-gradient), white max(9.5rem, 27vh) ); /* ...existing styles */ }
แต่เดี๋ยวก่อน - นั่นคือฟังก์ชัน CSS max()
หรือไม่ ในการไล่ระดับ? ใช่ เป็นไปได้ และมันเป็นความมหัศจรรย์ที่ทำให้การไล่ระดับสีนี้ตอบสนองได้อย่างมีประสิทธิภาพ!
อย่างไรก็ตาม หากฉันเพิ่มภาพหน้าจอ เราจะไม่เห็นการไล่ระดับสีที่มีผลใดๆ กับภาพเลย ในการนั้น เราจำเป็นต้องนำเข้าคุณสมบัติ mix-blend-mode
และในสถานการณ์นี้ เราจะใช้ค่า overlay
เลย์:
img { /* ...existing styles */ mix-blend-mode: overlay; }
คุณสมบัติ mix-blend-mode
นั้นคล้ายกับการใช้สไตล์การผสมเลเยอร์ที่มีอยู่ในซอฟต์แวร์จัดการภาพถ่าย เช่น Photoshop และค่า overlay
จะมีผลทำให้ โทนสีกลาง ในภาพ กลมกลืน กับการไล่ระดับสีด้านหลัง ส่งผลให้ได้ผลลัพธ์ดังต่อไปนี้
ณ จุดนี้ เรากำลังอาศัยค่า aspect-ratio
เพียงอย่างเดียวในการปรับขนาดภาพ และหากเรา ปรับขนาดคอนเทนเนอร์ และทำให้เลย์เอาต์การ์ดแสดงผลใหม่ ความสูงของรูปภาพที่เปลี่ยนไปจะทำให้การไล่ระดับสีจางลงเป็นสีขาวไม่สอดคล้องกัน
ดังนั้นเราจะเพิ่มคุณสมบัติ max-height
ด้วยเช่นกัน ซึ่ง ใช้ฟังก์ชัน max()
และมีค่าที่มากกว่าค่าในการไล่ระดับสีเล็กน้อย พฤติกรรมที่ได้คือความลาดชัน (เกือบทุกครั้ง) สอดคล้องกับด้านล่างของภาพอย่างถูกต้อง
img { /* ...existing styles */ max-height: max(10rem, 30vh); }
สิ่งสำคัญที่ควรทราบคือการเพิ่ม "ความสูงสูงสุด" จะเปลี่ยนพฤติกรรม "อัตราส่วนภาพ" แทนที่จะใช้อัตราส่วนที่แน่นอนเสมอ ระบบจะใช้อัตราส่วนนี้ต่อเมื่อมีพื้นที่จัดสรรเพียงพอตามข้อจำกัดพิเศษใหม่ของ "ความสูงสูงสุด"
“
อย่างไรก็ตาม aspect-ratio
จะยังคงทำให้แน่ใจว่ารูปภาพจะปรับขนาดอย่างสม่ำเสมอ เช่นเดียวกับประโยชน์ที่ได้รับจากความ object-fit
เท่านั้น ลองแสดงความคิดเห็นเกี่ยว aspect-ratio
ในการสาธิต CodePen สุดท้ายเพื่อดูความแตกต่างที่เกิดขึ้นในขนาดคอนเทนเนอร์
เนื่องจากเป้าหมายเดิมของเราคือการเปิดใช้ งานขนาดภาพที่ตอบสนอง ได้อย่างสม่ำเสมอ เราจึงยังคงบรรลุเป้าหมาย สำหรับกรณีการใช้งานของคุณเอง คุณอาจต้องเล่นซอกับค่าอัตราส่วนและความสูงเพื่อให้ได้เอฟเฟกต์ที่คุณต้องการ
ทางเลือก: mix-blend-mode
และการเพิ่มตัวกรอง
การใช้ overlay
เลย์เป็นค่า mix-blend-mode
เป็นตัวเลือกที่ดีที่สุดสำหรับเอฟเฟกต์เฟดเป็นสีขาวที่เราต้องการ แต่เรามาลองใช้ตัวเลือกอื่นเพื่อให้ได้เอฟเฟกต์ที่น่าทึ่งยิ่งขึ้น
เราจะอัปเดตโซลูชันของเราเพื่อเพิ่มคุณสมบัติที่กำหนดเอง CSS สำหรับค่า mix-blend-mode
และอัปเดตค่าสีสำหรับการไล่ระดับสี:
.card { --card-gradient: tomato, orange; --card-blend-mode: multiply; } img { /* ...existing styles */ mix-blend-mode: var(--card-blend-mode); }
ค่าการ multiply
มีผลทำให้โทนสีกลางมืดลง แต่จะคงสีขาวและสีดำไว้เหมือนเดิม ส่งผลให้มีลักษณะดังต่อไปนี้:
แม้ว่าเราจะสูญเสียการเฟดและตอนนี้มีขอบแข็งที่ด้านล่างของภาพ ส่วนสีขาวของการไล่ระดับสีของเรายังคงมีความสำคัญเพื่อให้แน่ใจว่าการไล่ระดับสีจะสิ้นสุดลงก่อนเนื้อหาในการ์ด
การแก้ไขเพิ่มเติม อย่างหนึ่งที่เราสามารถเพิ่มได้คือการใช้ filter
และโดยเฉพาะอย่างยิ่ง ใช้ฟังก์ชัน grayscale()
เพื่อลบสีของภาพออก ดังนั้นการไล่ระดับสีจึงเป็นแหล่งที่มาของสีภาพเพียงแหล่งเดียว
img { /* ...existing styles */ filter: grayscale(100); }
การใช้ค่า grayscale(100)
ส่งผลให้สีธรรมชาติของรูปภาพหายไปอย่างสมบูรณ์และเปลี่ยนเป็นขาวดำ นี่คือการอัปเดตเพื่อเปรียบเทียบกับภาพหน้าจอก่อนหน้าของเอฟเฟกต์เมื่อใช้การไล่ระดับสีส้มด้วยการ multiply
:
ใช้ aspect-ratio
เป็นการเพิ่มประสิทธิภาพแบบก้าวหน้า
ตามที่กล่าวไว้ก่อนหน้านี้ ขณะนี้ aspect-ratio
รองรับเฉพาะในเบราว์เซอร์ Chromium เวอร์ชันล่าสุด (Chrome และ Edge) เท่านั้น อย่างไรก็ตาม เบราว์เซอร์ทั้งหมดสนับสนุน object-fit
และเมื่อรวมกับข้อจำกัดด้าน height
ของเราแล้ว ก็ได้ผลลัพธ์ในอุดมคติน้อยกว่าแต่ยังคงเป็นที่ยอมรับ ซึ่งเห็นได้ที่นี่สำหรับ Safari:
หากไม่ aspect-ratio
ผลลัพธ์ที่ได้ก็คือความสูงของภาพถูกจำกัดไว้ในที่สุด แต่ ขนาดตามธรรมชาติ ของแต่ละภาพยังคงทำให้เกิดความแปรปรวนระหว่างความสูงของภาพในการ์ด คุณอาจต้องการเปลี่ยนเป็นการเพิ่ม max-height
หรือใช้ฟังก์ชัน max()
อีกครั้งเพื่อช่วยให้ max-height
ตอบสนองได้ดีขึ้นในขนาดการ์ดต่างๆ
การขยายเอฟเฟกต์ไล่โทนสี
เนื่องจากเรากำหนดให้การหยุดสีไล่ระดับเป็นคุณสมบัติที่กำหนดเองของ CSS เราจึงมีสิทธิ์เข้าถึงพร้อมที่จะเปลี่ยนแปลงภายใต้บริบทต่างๆ ตัวอย่างเช่น เราอาจเปลี่ยนการไล่ระดับสีเพื่อให้แสดงสีใดสีหนึ่งที่ชัดเจนยิ่งขึ้น หากการ์ดนั้นถูกวางเมาส์ไว้หรือให้ลูกๆ อยู่ในโฟกัส
อันดับแรก เราจะอัปเดตการ์ดแต่ละ h3
ให้มีลิงก์ เช่น:
<h3><a href="">A Super Wonderful Headline</a></h3>
จากนั้น เราสามารถใช้หนึ่งในตัวเลือกใหม่ล่าสุดของเรา — :focus-within
— เพื่อเปลี่ยนการไล่ระดับสีของการ์ดเมื่อลิงก์อยู่ในโฟกัส เพื่อ ความครอบคลุมเพิ่มเติม ของการโต้ตอบที่เป็นไปได้ เราจะจับคู่สิ่งนี้กับ :hover
และเราจะนำแนวคิด max()
กลับมาใช้ใหม่เพื่อกำหนดสีเดียวเพื่อให้ครอบคลุมส่วนรูปภาพของการ์ด ข้อเสียของเอฟเฟกต์นี้คือ การหยุดไล่ระดับและการเปลี่ยนสีนั้นไม่เคลื่อนไหวได้อย่างน่าเชื่อถือ — แต่สิ่งเหล่านี้จะต้องขอบคุณ CSS Houdini ในเร็วๆ นี้
ในการอัปเดตสีและเพิ่มการหยุดสีใหม่ เราเพียงแค่กำหนดค่า --card-gradient
ใหม่ภายในกฎใหม่นี้:
.card:focus-within, .card:hover { --card-gradient: #24a9d5 max(8.5rem, 20vh); }
max()
ของเรานั้นน้อยกว่าค่าดั้งเดิมที่ใช้สำหรับ white
เพื่อรักษาขอบขนนก หากเราใช้ค่าเดียวกัน ก็จะพบกับ white
และสร้างเส้นตรงแยกอย่างชัดเจน
ในการ transform
การสาธิตนี้ ตอนแรกฉันลองใช้เอฟเฟกต์ที่ใช้การทรานส์ฟอร์มด้วย scale
สำหรับเอฟเฟกต์การซูมเข้า แต่ฉันพบว่าเนื่องจากมีการ mix-blend-mode
เบราว์เซอร์จะไม่ทาสีภาพซ้ำอย่างสม่ำเสมอซึ่งทำให้เกิดการกะพริบที่ไม่พึงประสงค์ มีข้อแลกเปลี่ยนเสมอในการขอให้เบราว์เซอร์แสดงเอฟเฟกต์และแอนิเมชั่น CSS เท่านั้น และในขณะที่สิ่งที่เรา สามารถ ทำได้นั้นยอดเยี่ยมมาก ทางที่ดีควร ตรวจสอบผลกระทบ ของเอฟเฟกต์ของคุณเสมอ
ทดลองสนุก!
Modern CSS ได้มอบเครื่องมือที่ยอดเยี่ยมให้กับเราในการอัปเดตชุดเครื่องมือการออกแบบเว็บของเรา โดยมี aspect-ratio
เป็นส่วนเพิ่มเติมล่าสุด ออกไปและทดลองกับ object-fit
, aspect-ratio
และเพิ่มฟังก์ชันเช่น max()
ในการไล่ระดับสีของคุณเพื่อให้ได้เอฟเฟกต์ที่ตอบสนองอย่างสนุกสนาน! เพียงให้แน่ใจว่าได้ตรวจสอบสิ่งต่าง ๆ ข้ามเบราว์เซอร์อีกครั้ง (ตอนนี้!) และในวิวพอร์ตและขนาดคอนเทนเนอร์ที่แตกต่างกัน
นี่คือ CodePen รวมถึงคุณสมบัติและเอฟเฟกต์ที่เราตรวจสอบในวันนี้:
กำลังมองหาเพิ่มเติม? ตรวจสอบให้แน่ใจว่าคุณได้อ่านคู่มือ CSS ของเราที่นี่ใน Smashing →