แถบเลื่อนรูปภาพ (หรือที่เรียกว่าม้าหมุน) มีอยู่ทุกที่ มี เทคนิค CSS มากมายในการสร้างแถบเลื่อนทั่วไป โดยที่รูปภาพจะเลื่อนจากซ้ายไปขวา (หรือตรงกันข้าม) เป็นข้อตกลงเดียวกันกับ ไลบรารี JavaScript ที่มีอยู่มากมาย ที่สร้างแถบเลื่อนแฟนซีพร้อมภาพเคลื่อนไหวที่ซับซ้อน เราจะไม่ทำสิ่งนั้นในโพสต์นี้
เราจะมาสำรวจแถบเลื่อน CSS-only ที่แปลกตาและแปลกใหม่ผ่านบทความชุดเล็กๆ น้อยๆ หากคุณเบื่อที่จะเห็นสไลเดอร์คลาสสิกแบบเดิมๆ แสดงว่าคุณมาถูกที่แล้ว!
ชุดตัวเลื่อน CSS
สำหรับบทความแรกนี้ เราจะเริ่มด้วยสิ่งที่ผมเรียกว่า “ตัวเลื่อนภาพแบบหมุนเป็นวงกลม”:
เย็นใช่มั้ย? มาผ่ารหัสกัน!
มาร์กอัป HTML
หากคุณติดตามซีรีส์ของฉัน การตกแต่งภาพแฟนซี or ตาราง CSS และรูปร่างที่กำหนดเองแล้วคุณก็รู้ว่ากฎข้อแรกของฉันคือการทำงานกับ HTML ที่เล็กที่สุดเท่าที่จะเป็นไปได้ ฉันพยายามอย่างหนักที่จะค้นหาโซลูชัน CSS ก่อนที่จะทำให้โค้ดของฉันรกรุงรัง
และอื่น ๆ
ใช้กฎเดียวกันกับที่นี่ — รหัสของเราเป็นเพียงรายการรูปภาพในคอนเทนเนอร์
สมมติว่าเรากำลังทำงานกับสี่ภาพ:
แค่นั้นแหละ! ตอนนี้เรามาดูส่วนที่น่าสนใจของโค้ดกัน แต่ก่อนอื่น เราจะเจาะลึกเรื่องนี้เพื่อทำความเข้าใจตรรกะของวิธีการทำงานของแถบเลื่อนของเรา
มันทำงานอย่างไร?
นี่คือวิดีโอที่ฉันนำออก overflow: hidden
จาก CSS เพื่อให้เราเข้าใจการเคลื่อนไหวของรูปภาพได้ดีขึ้น:
มันเหมือนกับภาพสี่ของเราวางอยู่บนวงกลมขนาดใหญ่ที่หมุนทวนเข็มนาฬิกา
ทุกภาพมีขนาดเท่ากัน (แสดงโดย S
ในรูป) สังเกตวงกลมสีน้ำเงินซึ่งเป็นวงกลมที่ตัดกับจุดศูนย์กลางของภาพทั้งหมดและมีรัศมี (R
). เราจะต้องใช้ค่านี้ในภายหลังสำหรับแอนิเมชันของเรา R
เท่ากับ 0.707 * S
. (ฉันจะข้ามรูปทรงเรขาคณิตที่ให้สมการนั้นแก่เรา)
มาเขียน CSS กันเถอะ!
เราจะใช้ CSS กริด ในการวางภาพทั้งหมดในพื้นที่เดียวกันเหนือกัน:
.gallery {
--s: 280px; /* control the size */
display: grid;
width: var(--s);
aspect-ratio: 1;
padding: calc(var(--s) / 20); /* we will see the utility of this later */
border-radius: 50%;
}
.gallery > img {
grid-area: 1 / 1;
width: 100%;
height: 100%;
object-fit: cover;
border-radius: inherit;
}
จนถึงตอนนี้ยังไม่มีอะไรซับซ้อนเกินไป ส่วนที่ยุ่งยากคือภาพเคลื่อนไหว
เราพูดถึงการหมุนวงกลมขนาดใหญ่ แต่ในความเป็นจริง เราจะหมุนแต่ละภาพทีละภาพเพื่อสร้างภาพลวงตาของวงกลมขนาดใหญ่ที่หมุน เรามานิยามแอนิเมชันกัน m
และนำไปใช้กับองค์ประกอบภาพ:
.gallery > img {
/* same as before */
animation: m 8s infinite linear;
transform-origin: 50% 120.7%;
}
@keyframes m {
100% { transform: rotate(-360deg); }
}
เคล็ดลับหลักขึ้นอยู่กับบรรทัดที่ไฮไลต์ ตามค่าเริ่มต้น CSS transform-origin
คุณสมบัติเท่ากับ center
(หรือ 50% 50%
) ซึ่งทำให้ภาพหมุนรอบจุดศูนย์กลาง แต่เราไม่ต้องการให้หมุนภาพนั้น เราต้องการให้ภาพหมุนรอบศูนย์กลางของ วงกลมใหญ่ ที่มีรูปภาพของเรา ดังนั้นค่าใหม่สำหรับ transform-origin
.
เนื่องจาก R เท่ากับ 0.707 * S
เราสามารถพูดได้ว่า R
เท่ากับ 70.7%
ของขนาดภาพ นี่คือรูปที่แสดงให้เห็นว่าเราได้มาอย่างไร 120.7%
ราคา:
เรียกใช้แอนิเมชั่นและดูว่าเกิดอะไรขึ้น:
ฉันรู้ว่าฉันรู้ว่า. ผลลัพธ์อยู่ไกลจากที่เราต้องการ แต่ในความเป็นจริงเราอยู่ใกล้มาก อาจดูเหมือนมีภาพเดียวในนั้น แต่อย่าลืมว่าเรานำภาพทั้งหมดมาซ้อนทับกัน ทั้งหมดหมุนพร้อมกันและมองเห็นเฉพาะภาพบนสุดเท่านั้น สิ่งที่เราต้องการคือการหน่วงเวลาภาพเคลื่อนไหวของแต่ละภาพเพื่อหลีกเลี่ยงการทับซ้อนกัน
.gallery > img:nth-child(2) { animation-delay: -2s; } /* -1 * 8s / 4 */
.gallery > img:nth-child(3) { animation-delay: -4s; } /* -2 * 8s / 4 */
.gallery > img:nth-child(4) { animation-delay: -6s; } /* -3 * 8s / 4 */
ทุกอย่างเริ่มดีขึ้นแล้ว!
หากเราซ่อนโอเวอร์โฟลว์บนคอนเทนเนอร์ เราจะเห็นแถบเลื่อนอยู่แล้ว แต่เราจะอัปเดตแอนิเมชันเล็กน้อยเพื่อให้แต่ละภาพยังคงมองเห็นได้ในช่วงเวลาสั้นๆ ก่อนที่มันจะเลื่อนตาม
เราจะอัปเดตคีย์เฟรมแอนิเมชันเพื่อดำเนินการดังกล่าว:
@keyframes m {
0%, 3% { transform: rotate(0); }
22%, 27% { transform: rotate(-90deg); }
47%, 52% { transform: rotate(-180deg); }
72%, 77% { transform: rotate(-270deg); }
98%, 100% { transform: rotate(-360deg); }
}
สำหรับแต่ละ 90deg
(360deg/4
ที่นี่มี 4
คือจำนวนภาพ) เราจะเพิ่มการหยุดชั่วคราวเล็กน้อย แต่ละภาพจะยังคงมองเห็นได้ 5%
ของระยะเวลาโดยรวมก่อนที่เราจะเลื่อนไปยังช่วงถัดไป (27%-22%
, 52%-47%
ฯลฯ). ฉันจะปรับปรุง animation-timing-function
ใช้ cubic-bezier()
ฟังก์ชันเพื่อทำให้แอนิเมชันดูน่าสนใจยิ่งขึ้น:
ตอนนี้สไลเดอร์ของเราสมบูรณ์แบบแล้ว! เกือบจะสมบูรณ์แบบเพราะเรายังขาดสัมผัสสุดท้าย: ขอบวงกลมหลากสีสันที่หมุนรอบรูปภาพของเรา เราสามารถใช้องค์ประกอบหลอกบน .gallery
กระดาษห่อที่จะทำให้:
.gallery {
padding: calc(var(--s) / 20); /* the padding is needed here */
position: relative;
}
.gallery::after {
content: "";
position: absolute;
inset: 0;
padding: inherit; /* Inherits the same padding */
border-radius: 50%;
background: repeating-conic-gradient(#789048 0 30deg, #DFBA69 0 60deg);
mask:
linear-gradient(#fff 0 0) content-box,
linear-gradient(#fff 0 0);
mask-composite: exclude;
}
.gallery::after,
.gallery >img {
animation: m 8s infinite cubic-bezier(.5, -0.2, .5, 1.2);
}
ฉันได้สร้างวงกลมด้วย การไล่ระดับสีรูปกรวยซ้ำ สำหรับพื้นหลังขณะใช้ a เคล็ดลับการกำบัง ที่แสดงเฉพาะพื้นที่บุนวม จากนั้นฉันก็ใช้แอนิเมชั่นเดียวกันกับที่เรากำหนดไว้สำหรับรูปภาพ
เสร็จแล้ว! เรามีแถบเลื่อนวงกลมสุดเจ๋ง:
ขอลงรูปเพิ่มนะครับ
การทำงานกับภาพสี่ภาพนั้นดี แต่จะดีกว่าหากเราสามารถปรับขนาดเป็นภาพจำนวนเท่าใดก็ได้ ท้ายที่สุด นี่คือจุดประสงค์ของแถบเลื่อนรูปภาพ เราน่าจะพิจารณาได้ N
ภาพ
สำหรับสิ่งนี้ เราจะสร้างรหัสทั่วไปมากขึ้นโดยแนะนำ Sass ขั้นแรก เรากำหนดตัวแปรสำหรับจำนวนรูปภาพ ($n
) และเราจะอัปเดตทุกส่วนที่เราฮาร์ดโค้ดจำนวนรูปภาพ (4
).
เริ่มต้นด้วยความล่าช้า:
.gallery > img:nth-child(2) { animation-delay: -2s; } /* -1 * 8s / 4 */
.gallery > img:nth-child(3) { animation-delay: -4s; } /* -2 * 8s / 4 */
.gallery > img:nth-child(4) { animation-delay: -6s; } /* -3 * 8s / 4 */
สูตรสำหรับความล่าช้าคือ (1 - $i)*duration/$n
ซึ่งให้ลูป Sass ต่อไปนี้แก่เรา:
@for $i from 2 to ($n + 1) {
.gallery > img:nth-child(#{$i}) {
animation-delay: calc(#{(1 - $i) / $n} * 8s);
}
}
เราสามารถทำให้ระยะเวลาเป็นตัวแปรได้เช่นกันหากเราต้องการจริงๆ แต่ไปที่แอนิเมชั่นกันเถอะ:
@keyframes m {
0%, 3% { transform: rotate(0); }
22%, 27% { transform: rotate(-90deg); }
47%, 52% { transform: rotate(-180deg); }
72%, 77% { transform: rotate(-270deg); }
98%, 100% {transform: rotate(-360deg); }
}
มาทำให้ง่ายขึ้นเพื่อดูรูปแบบที่ดีขึ้น:
@keyframes m {
0% { transform: rotate(0); }
25% { transform: rotate(-90deg); }
50% { transform: rotate(-180deg); }
75% { transform: rotate(-270deg); }
100% { transform: rotate(-360deg); }
}
ขั้นตอนระหว่างแต่ละสถานะเท่ากับ 25%
- ซึ่งเป็น 100%/4
— และเราเพิ่ม -90deg
มุม — ซึ่งก็คือ -360deg/4
. นั่นหมายความว่าเราสามารถเขียนลูปของเราได้ดังนี้:
@keyframes m {
0% { transform: rotate(0); }
@for $i from 1 to $n {
#{($i / $n) * 100}% { transform: rotate(#{($i / $n) * -360}deg); }
}
100% { transform: rotate(-360deg); }
}
เนื่องจากแต่ละภาพที่ถ่าย 5%
ของภาพเคลื่อนไหว เราเปลี่ยนสิ่งนี้:
#{($i / $n) * 100}%
…ด้วยสิ่งนี้:
#{($i / $n) * 100 - 2}%, #{($i / $n) * 100 + 3}%
ควรสังเกตว่า 5%
เป็นค่าโดยพลการที่ฉันเลือกสำหรับตัวอย่างนี้ เรายังสามารถกำหนดให้เป็นตัวแปรเพื่อควบคุมระยะเวลาที่แต่ละภาพควรจะมองเห็นได้ ฉันจะข้ามไปเพื่อความง่าย แต่สำหรับการบ้าน คุณสามารถลองทำและแบ่งปันการนำไปใช้ของคุณในความคิดเห็น!
@keyframes m {
0%,3% { transform: rotate(0); }
@for $i from 1 to $n {
#{($i / $n) * 100 - 2}%, #{($i / $n) * 100 + 3}% { transform: rotate(#{($i / $n) * -360}deg); }
}
98%,100% { transform: rotate(-360deg); }
}
บิตสุดท้ายคือการอัปเดต transform-origin
. เราจะต้องใช้เทคนิคทางเรขาคณิต ไม่ว่ารูปภาพจะมีจำนวนเท่าใด การกำหนดค่าจะเหมือนกันเสมอ เรามีภาพของเรา (วงกลมเล็ก) อยู่ภายในวงกลมใหญ่ และเราต้องหาค่าของรัศมี R
.
คุณอาจไม่ต้องการคำอธิบายทางเรขาคณิตที่น่าเบื่อ ดังนั้นนี่คือวิธีที่เราค้นหา R
:
R = S / (2 * sin(180deg / N))
ถ้าเราแสดงเป็นเปอร์เซ็นต์ นั่นทำให้เรา:
R = 100% / (2 * sin(180deg / N)) = 50% / sin(180deg / N)
…ซึ่งหมายถึงการ transform-origin
มูลค่าเท่ากับ:
transform-origin: 50% (50% / math.sin(180deg / $n) + 50%);
เสร็จแล้ว! เรามีแถบเลื่อนที่ใช้ได้กับภาพตัวเลข!
ลองโยนเก้าภาพในนั้น:
เพิ่มรูปภาพได้มากเท่าที่คุณต้องการและอัปเดต $n
ตัวแปรที่มีจำนวนภาพทั้งหมด
ตัดขึ้น
ด้วยเทคนิคเล็กๆ น้อยๆ โดยใช้การแปลง CSS และรูปทรงเรขาคณิตมาตรฐาน เราสร้างแถบเลื่อนวงกลมที่สวยงามซึ่งไม่ต้องใช้โค้ดมากมาย สิ่งที่เจ๋งเกี่ยวกับแถบเลื่อนนี้คือเราไม่จำเป็นต้องสร้างภาพซ้ำเพื่อให้แอนิเมชั่นไม่สิ้นสุดเพราะเรามีวงกลม หลังจากหมุนครบแล้วเราจะกลับไปที่ภาพแรก!