เอ็กซ์เลร่า8

เอฟเฟ็กต์โฮเวอร์แฟนซีสำหรับอวาตาร์ของคุณ

คุณรู้หรือไม่ว่าเมื่อศีรษะของใครบางคนโผล่ออกมาจากวงกลมหรือรู แอนิเมชั่น Porky Pig อันโด่งดังที่เขาโบกมือลาในขณะที่โผล่ออกมาจากวงแหวนสีแดงเป็นชุดคือตัวอย่างที่สมบูรณ์แบบ และ Kilian Valkhof สร้างขึ้นใหม่ที่นี่ใน CSS-Tricks เมื่อไม่นานมานี้.

ฉันมีความคิดที่คล้ายกันแต่แก้ไขด้วยวิธีที่ต่างออกไปและด้วยแอนิเมชั่นที่โปรยปราย ฉันคิดว่ามันค่อนข้างใช้งานได้จริงและสร้างเอฟเฟ็กต์โฮเวอร์ที่สวยงามซึ่งคุณสามารถใช้กับอวาตาร์ของคุณเองได้

เห็นไหม? เรากำลังจะสร้างแอนิเมชั่นแบบปรับขนาดโดยที่อวตารดูเหมือนจะโผล่ออกมาจากวงกลมที่มันอยู่ เยี่ยมเลยใช่ไหม อย่าดูที่โค้ดและมาสร้างแอนิเมชันนี้ด้วยกันทีละขั้นตอน

HTML: เพียงหนึ่งองค์ประกอบ

หากคุณยังไม่ได้ตรวจสอบรหัสของการสาธิตและคุณสงสัยว่ามีกี่รหัส divจากนั้นหยุดตรงนั้น เพราะมาร์กอัปของเราเป็นเพียงองค์ประกอบภาพเดียว:

<img src="" alt="">

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

ฉันเขียน ชุดบทความ ที่นี่เกี่ยวกับ CSS-Tricks ที่ฉันสำรวจเอฟเฟกต์โฮเวอร์ต่างๆ โดยใช้มาร์กอัป HTML เดียวกันที่มีองค์ประกอบเดียว ฉันลงรายละเอียดเกี่ยวกับการไล่ระดับสี การปิดบัง การตัด โครงร่าง และแม้กระทั่งเทคนิคการจัดวาง ฉันขอแนะนำให้ตรวจสอบสิ่งเหล่านี้เพราะฉันจะใช้เทคนิคมากมายในโพสต์นี้ซ้ำ

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

ออกแบบโดย คัง

ฉันหวังว่าจะได้เห็นตัวอย่างมากมายที่เป็นไปได้โดยใช้ภาพจริง ดังนั้นโปรดแบ่งปันผลลัพธ์สุดท้ายของคุณในความคิดเห็นเมื่อคุณทำเสร็จแล้ว เราจะสามารถสร้างคอลเลกชันได้!

ก่อนจะกระโดดเข้าสู่ CSS เรามาแยกเอฟเฟกต์กันก่อน รูปภาพจะใหญ่ขึ้นเมื่อวางเมาส์เหนือ ดังนั้นเราจะใช้อย่างแน่นอน transform: scale() ในนั้น. มีวงกลมอยู่ด้านหลังอวาตาร์ และการไล่ระดับสีในแนวรัศมีน่าจะช่วยได้ สุดท้าย เราต้องการวิธีสร้างเส้นขอบที่ด้านล่างของวงกลมซึ่งสร้างรูปลักษณ์ของอวตารที่อยู่ด้านหลังวงกลม

ให้ของได้รับไปทำงาน!

เอฟเฟกต์สเกล

เริ่มต้นด้วยการเพิ่มการแปลง:

img { width: 280px; aspect-ratio: 1; cursor: pointer; transition: .5s;
}
img:hover { transform: scale(1.35);
}

ยังไม่มีอะไรซับซ้อนใช่ไหม เดินหน้าต่อไป

วงกลม

เราบอกว่าพื้นหลังจะเป็นการไล่ระดับสีแบบรัศมี สมบูรณ์แบบเพราะเราสามารถสร้างฮาร์ดสต็อประหว่างสีของการไล่ระดับสีในแนวรัศมี ซึ่งทำให้ดูเหมือนว่าเรากำลังวาดวงกลมด้วยเส้นทึบ

img { --b: 5px; /* border width */ width: 280px; aspect-ratio: 1; background: radial-gradient( circle closest-side, #ECD078 calc(99% - var(--b)), #C02942 calc(100% - var(--b)) 99%, #0000 ); cursor: pointer; transition: .5s;
}
img:hover { transform: scale(1.35);
}

หมายเหตุตัวแปร CSS --bฉันใช้ที่นั่น มันแสดงถึงความหนาของ "เส้นขอบ" ซึ่งจริงๆ แล้วใช้เพื่อกำหนดการหยุดสีแบบแข็งสำหรับส่วนสีแดงของการไล่ระดับสีในแนวรัศมี

ขั้นตอนต่อไปคือการเล่นกับขนาดการไล่ระดับสีเมื่อโฮเวอร์ วงกลมต้องคงขนาดไว้เมื่อรูปภาพโตขึ้น เนื่องจากเรากำลังสมัครก scale() การเปลี่ยนแปลง เราต้องการจริงๆ ลดลง ขนาดของวงกลมเพราะมิฉะนั้นจะปรับขนาดขึ้นกับอวาตาร์ ดังนั้นในขณะที่ภาพขยายขนาดขึ้น เราต้องใช้การไล่ระดับสีเพื่อลดขนาดลง

เริ่มจากการกำหนดตัวแปร CSS --fซึ่งกำหนด "ตัวคูณมาตราส่วน" และใช้เพื่อกำหนดขนาดของวงกลม ฉันกำลังใช้ 1 เป็นค่าเริ่มต้น เช่นเดียวกับที่เป็นมาตราส่วนเริ่มต้นของรูปภาพและวงกลมที่เราแปลงร่าง

นี่คือตัวอย่างเพื่อแสดงเคล็ดลับ วางเมาส์เหนือเพื่อดูว่าเกิดอะไรขึ้นเบื้องหลัง:

ฉันเพิ่มสีที่สามให้กับ radial-gradient เพื่อให้ระบุพื้นที่ของการไล่ระดับสีได้ดีขึ้น:

radial-gradient( circle closest-side, #ECD078 calc(99% - var(--b)), #C02942 calc(100% - var(--b)) 99%, lightblue
);

ตอนนี้เราต้องวางพื้นหลังของเราไว้ที่กึ่งกลางวงกลมและตรวจสอบให้แน่ใจว่าใช้ความสูงเต็มที่ ฉันต้องการประกาศทุกอย่างโดยตรงบน background พร็อพเพอร์ตี้ชวเลข ดังนั้นเราจึงสามารถเพิ่มตำแหน่งพื้นหลังของเราได้ และตรวจสอบให้แน่ใจว่าจะไม่ทำซ้ำโดยการตรึงค่าเหล่านั้นทันทีหลังจาก radial-gradient():

background: radial-gradient() 50% / calc(100% / var(--f)) 100% no-repeat;

พื้นหลังวางไว้ตรงกลาง (50%) มีความกว้างเท่ากับ calc(100%/var(--f))และมีความสูงเท่ากับ 100%.

ไม่มีอะไรจะปรับขนาดเมื่อ --f เท่ากับ 1 — อีกครั้ง ระดับเริ่มต้นของเรา ในขณะเดียวกัน การไล่ระดับสีจะใช้ความกว้างเต็มคอนเทนเนอร์ เมื่อเราเพิ่มขึ้น --fขนาดขององค์ประกอบจะเพิ่มขึ้น — ขอบคุณ scale() การแปลง - และขนาดของการไล่ระดับสีจะลดลง

นี่คือสิ่งที่เราได้รับเมื่อเราใช้ทั้งหมดนี้กับการสาธิตของเรา:

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

เส้นขอบด้านล่าง

ครั้งแรกที่ฉันพยายามแก้ไขปัญหานี้ด้วย border-bottom คุณสมบัติ แต่ฉันไม่สามารถหาวิธีจับคู่ขนาดของเส้นขอบกับขนาดของวงกลมได้ นี่คือสิ่งที่ดีที่สุดที่ฉันจะได้รับ และคุณจะเห็นได้ทันทีว่ามันผิด:

วิธีแก้ไขที่แท้จริงคือการใช้ outline คุณสมบัติ. ใช่, outlineไม่ border. ใน บทความก่อนหน้าฉันแสดงวิธีการ outline ทรงพลังและช่วยให้เราสร้างเอฟเฟ็กต์โฮเวอร์สุดเจ๋งได้ ผสมผสานกับ outline-offsetเรามีสิ่งที่ต้องการสำหรับผลของเรา

แนวคิดคือการตั้งค่า outline บนภาพและปรับออฟเซ็ตเพื่อสร้างเส้นขอบด้านล่าง ค่าชดเชยจะขึ้นอยู่กับปัจจัยการปรับสเกลเช่นเดียวกับขนาดการไล่ระดับสี

ตอนนี้เรามี "เส้นขอบ" ด้านล่างแล้ว (อันที่จริงแล้ว outline) รวมกับ "เส้นขอบ" ที่สร้างขึ้นโดยการไล่ระดับสีเพื่อสร้างวงกลมเต็ม เรายังต้องซ่อนบางส่วนของ outline (จากด้านบนและด้านข้าง) ซึ่งเราจะพูดถึงในอีกสักครู่

นี่คือโค้ดของเราจนถึงตอนนี้ รวมถึงตัวแปร CSS อีกสองสามตัวที่คุณสามารถใช้เพื่อกำหนดค่าขนาดรูปภาพ (--s) และสี "เส้นขอบ" (--c):

img { --s: 280px; /* image size */ --b: 5px; /* border thickness */ --c: #C02942; /* border color */ --f: 1; /* initial scale */ width: var(--s); aspect-ratio: 1; cursor: pointer; border-radius: 0 0 999px 999px; outline: var(--b) solid var(--c); outline-offset: calc((1 / var(--f) - 1) * var(--s) / 2 - var(--b)); background: radial-gradient( circle closest-side, #ECD078 calc(99% - var(--b)), var(--c) calc(100% - var(--b)) 99%, #0000 ) 50% / calc(100% / var(--f)) 100% no-repeat; transform: scale(var(--f)); transition: .5s;
}
img:hover { --f: 1.35; /* hover scale */
}

เนื่องจากเราต้องการเส้นขอบด้านล่างแบบวงกลม เราจึงเพิ่ม border-radius ที่ด้านล่างช่วยให้ outline เพื่อให้เข้ากับความโค้งของการไล่ระดับสี

การคำนวณที่ใช้เมื่อ outline-offset ตรงไปตรงมามากกว่าที่เห็น โดยค่าเริ่มต้น, outline ถูกวาด ด้านนอก ของกล่ององค์ประกอบ และในกรณีของเรา เราจำเป็นต้องทำ คาบเกี่ยวกัน องค์ประกอบ แม่นยำยิ่งขึ้น เราต้องการให้เป็นไปตามวงกลมที่สร้างขึ้นโดยการไล่ระดับสี

ไดอะแกรมของการเปลี่ยนพื้นหลัง

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

อย่าลืมว่าองค์ประกอบที่สองถูกปรับขนาด ดังนั้นผลลัพธ์ของเราจะถูกปรับขนาดด้วย... ซึ่งหมายความว่าเราต้องหารผลลัพธ์ด้วย f เพื่อรับค่าออฟเซ็ตจริง:

Offset = ((f - 1) * S/2) / f = (1 - 1/f) * S/2

เราเพิ่มเครื่องหมายลบเนื่องจากเราต้องการให้โครงร่างเปลี่ยนจากด้านนอกเข้าไปด้านใน:

Offset = (1/f - 1) * S/2

นี่คือตัวอย่างด่วนที่แสดงให้เห็นว่าเค้าร่างตามการไล่ระดับสีอย่างไร:

คุณอาจเห็นแล้ว แต่เรายังต้องการโครงร่างด้านล่างเพื่อซ้อนทับวงกลมแทนที่จะปล่อยให้มันทะลุผ่าน เราสามารถทำได้โดยลบขนาดของเส้นขอบออกจากออฟเซ็ต:

outline-offset: calc((1 / var(--f) - 1) * var(--s) / 2) - var(--b));

ตอนนี้เราต้องหาวิธีลบส่วนบนออกจากโครงร่าง กล่าวอีกนัยหนึ่งคือเราต้องการเฉพาะส่วนล่างของภาพเท่านั้น outline.

ขั้นแรก ให้เพิ่มช่องว่างด้านบนด้วยช่องว่างภายในเพื่อช่วยหลีกเลี่ยงการทับซ้อนกันที่ด้านบน:

img { --s: 280px; /* image size */ --b: 5px; /* border thickness */ --c: #C02942; /* border color */ --f: 1; /* initial scale */ width: var(--s); aspect-ratio: 1; padding-block-start: calc(var(--s)/5); /* etc. */
}
img:hover { --f: 1.35; /* hover scale */
}

ไม่มีเหตุผลเฉพาะสำหรับการเติมด้านบนนั้น แนวคิดคือเพื่อให้แน่ใจว่าโครงร่างไม่ได้สัมผัสกับศีรษะของอวาตาร์ ฉันใช้ขนาดขององค์ประกอบเพื่อกำหนดช่องว่างนั้นให้มีสัดส่วนเท่ากันเสมอ

โปรดทราบว่าฉันได้เพิ่มไฟล์ content-box มูลค่าให้กับ background:

background: radial-gradient( circle closest-side, #ECD078 calc(99% - var(--b)), var(--c) calc(100% - var(--b)) 99%, #0000 ) 50%/calc(100%/var(--f)) 100% no-repeat content-box;

เราต้องการสิ่งนี้เพราะเราเพิ่มช่องว่างภายในและเราต้องการให้พื้นหลังตั้งค่าเป็นกล่องเนื้อหาเท่านั้น ดังนั้นเราต้องบอกให้พื้นหลังหยุดอยู่แค่นั้นอย่างชัดเจน

การเพิ่มหน้ากาก CSS ในการผสม

เรามาถึงส่วนสุดท้ายแล้ว! สิ่งที่เราต้องทำคือซ่อนบางชิ้นและทำเสร็จแล้ว สำหรับสิ่งนี้เราจะอาศัยการ mask คุณสมบัติและแน่นอน การไล่ระดับสี

ต่อไปนี้เป็นรูปภาพเพื่ออธิบายสิ่งที่เราต้องซ่อนหรือสิ่งที่เราต้องแสดงเพื่อให้แม่นยำยิ่งขึ้น

แสดงวิธีใช้มาสก์กับส่วนล่างของวงกลม

ภาพซ้ายคือสิ่งที่เรามีในขณะนี้ และภาพขวาคือสิ่งที่เราต้องการ ส่วนสีเขียวแสดงหน้ากากที่เราต้องใช้กับภาพต้นฉบับเพื่อให้ได้ผลลัพธ์สุดท้าย

เราสามารถจำแนกหน้ากากของเราได้สองส่วน:

  • ส่วนวงกลมด้านล่างที่มีขนาดและความโค้งเท่ากันกับการไล่ระดับสีแบบรัศมีที่เราใช้สร้างวงกลมด้านหลังอวาตาร์
  • สี่เหลี่ยมผืนผ้าด้านบนที่ครอบคลุมพื้นที่ภายในโครงร่าง สังเกตว่าโครงร่างอยู่นอกพื้นที่สีเขียวด้านบนอย่างไร ซึ่งเป็นส่วนที่สำคัญที่สุด เนื่องจากจะทำให้โครงร่างถูกตัดออกเพื่อให้มองเห็นเฉพาะส่วนล่างเท่านั้น

นี่คือ CSS สุดท้ายของเรา:

img { --s: 280px; /* image size */ --b: 5px; /* border thickness */ --c: #C02942; /* border color */ --f: 1; /* initial scale */ --_g: 50% / calc(100% / var(--f)) 100% no-repeat content-box; --_o: calc((1 / var(--f) - 1) * var(--s) / 2 - var(--b)); width: var(--s); aspect-ratio: 1; padding-top: calc(var(--s)/5); cursor: pointer; border-radius: 0 0 999px 999px; outline: var(--b) solid var(--c); outline-offset: var(--_o); background: radial-gradient( circle closest-side, #ECD078 calc(99% - var(--b)), var(--c) calc(100% - var(--b)) 99%, #0000) var(--_g); mask: linear-gradient(#000 0 0) no-repeat 50% calc(-1 * var(--_o)) / calc(100% / var(--f) - 2 * var(--b)) 50%, radial-gradient( circle closest-side, #000 99%, #0000) var(--_g); transform: scale(var(--f)); transition: .5s;
}
img:hover { --f: 1.35; /* hover scale */
}

มาทำลายสิ่งนั้นกันเถอะ mask คุณสมบัติ. สำหรับผู้เริ่มสังเกตว่าคล้ายกัน radial-gradient() จาก background ทรัพย์สินอยู่ในนั้น ฉันสร้างตัวแปรใหม่ --_gสำหรับส่วนรวมที่จะทำให้ของรกน้อยลง

--_g: 50% / calc(100% / var(--f)) 100% no-repeat content-box; mask: radial-gradient( circle closest-side, #000 99%, #0000) var(--_g);

ถัดมาเป็น linear-gradient() ในนั้นเช่นกัน:

--_g: 50% / calc(100% / var(--f)) 100% no-repeat content-box; mask: linear-gradient(#000 0 0) no-repeat 50% calc(-1 * var(--_o)) / calc(100% / var(--f) - 2 * var(--b)) 50%, radial-gradient( circle closest-side, #000 99%, #0000) var(--_g);

สิ่งนี้จะสร้างส่วนสี่เหลี่ยมผืนผ้าของมาสก์ ความกว้างเท่ากับความกว้างของการไล่ระดับสีในแนวรัศมีลบด้วยความหนาของเส้นขอบสองเท่า:

calc(100% / var(--f) - 2 * var(--b))

ความสูงของสี่เหลี่ยมผืนผ้าเท่ากับครึ่งหนึ่ง 50%ขนาดขององค์ประกอบ

นอกจากนี้เรายังต้องการการไล่ระดับสีเชิงเส้นที่กึ่งกลางแนวนอน (50%) และชดเชยจากด้านบนด้วยค่าเดียวกับการชดเชยของโครงร่าง ฉันสร้างตัวแปร CSS อื่น --_oสำหรับการชดเชยที่เรากำหนดไว้ก่อนหน้านี้:

--_o: calc((1 / var(--f) - 1) * var(--s) / 2 - var(--b));

สิ่งหนึ่งที่ทำให้เกิดความสับสนคือเราต้องการ เชิงลบ ชดเชยโครงร่าง (เพื่อย้ายจากด้านนอกไปด้านใน) แต่ก บวก ชดเชยการไล่ระดับสี (เพื่อเลื่อนจากบนลงล่าง) ถ้าคุณสงสัยว่าทำไมเราถึงคูณออฟเซ็ต --_oโดย -1ตอนนี้คุณรู้แล้ว!

นี่คือตัวอย่างเพื่อแสดงการกำหนดค่าการไล่ระดับสีของมาสก์:

วางเมาส์เหนือด้านบนและดูว่าทุกอย่างเคลื่อนไหวไปด้วยกันอย่างไร กล่องตรงกลางแสดงเลเยอร์มาสก์ที่ประกอบด้วยการไล่ระดับสีสองแบบ ลองนึกภาพว่ามันเป็นส่วนที่มองเห็นได้จากภาพด้านซ้าย แล้วคุณจะได้ผลลัพธ์สุดท้ายทางด้านขวา!

ตัดขึ้น

อ๊อฟ เสร็จแล้ว! และไม่เพียงแต่เราปิดท้ายด้วยแอนิเมชั่นโฮเวอร์ที่ลื่นไหลเท่านั้น แต่เราทำทุกอย่างด้วย HTML เดียว <img> องค์ประกอบ. แค่นั้นและเล่ห์เหลี่ยม CSS น้อยกว่า 20 บรรทัด!

แน่นอน เราอาศัยกลเม็ดเล็กๆ น้อยๆ และสูตรทางคณิตศาสตร์เพื่อให้ได้ผลลัพธ์ที่ซับซ้อนเช่นนี้ แต่เรารู้แน่ชัดว่าต้องทำอย่างไรเนื่องจากเราระบุชิ้นส่วนที่เราต้องการไว้ล่วงหน้าแล้ว

เราจะทำให้ CSS ง่ายขึ้นได้ไหมถ้าเราอนุญาตให้ใช้ HTML มากขึ้น อย่างแน่นอน. แต่เรามาที่นี่เพื่อเรียนรู้เทคนิค CSS ใหม่! นี่เป็นแบบฝึกหัดที่ดีในการสำรวจการไล่ระดับสี CSS, การปิดบัง, outline พฤติกรรมของทรัพย์สิน การเปลี่ยนแปลง และอื่นๆ อีกมากมาย หากคุณรู้สึกหลงทางในจุดใดก็ตาม ลองดูสิ ซีรีส์ของฉัน ที่ใช้แนวคิดทั่วไปเดียวกัน บางครั้งการดูตัวอย่างเพิ่มเติมและใช้กรณีต่างๆ เพื่อผลักดันจุดกลับบ้านก็ช่วยได้

ฉันจะปล่อยให้คุณดูตัวอย่างสุดท้ายที่ใช้รูปถ่ายของนักพัฒนา CSS ยอดนิยม อย่าลืมแสดงตัวอย่างพร้อมรูปภาพของคุณเองให้ฉันดู เพื่อที่ฉันจะได้เพิ่มลงในคอลเลกชัน!

แชทกับเรา

สวัสดี! ฉันจะช่วยคุณได้อย่างไร?