CSS แถบเลื่อนรูปภาพหมุนได้ไม่จำกัดและแบบวงกลม

โหนดต้นทาง: 1765846

แถบเลื่อนรูปภาพ (หรือที่เรียกว่าม้าหมุน) มีอยู่ทุกที่ มี เทคนิค 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 และรูปทรงเรขาคณิตมาตรฐาน เราสร้างแถบเลื่อนวงกลมที่สวยงามซึ่งไม่ต้องใช้โค้ดมากมาย สิ่งที่เจ๋งเกี่ยวกับแถบเลื่อนนี้คือเราไม่จำเป็นต้องสร้างภาพซ้ำเพื่อให้แอนิเมชั่นไม่สิ้นสุดเพราะเรามีวงกลม หลังจากหมุนครบแล้วเราจะกลับไปที่ภาพแรก!

ประทับเวลา:

เพิ่มเติมจาก เคล็ดลับ CSS