Created
          September 29, 2025 09:49 
        
      - 
      
- 
        Save gorobey/94e1b8968d2eccd02eec56165308c0c4 to your computer and use it in GitHub Desktop. 
Revisions
- 
        gorobey created this gist Sep 29, 2025 .There are no files selected for viewingThis file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,21 @@ A CSS-only Carousel Slider -------------------------- I've recently read about and discussed CSS Scroll Snapping so often that I felt like I should build a CSS-only carousel based on it. Here are a few things to note: Accessibility is in line with all other CSS-only experiments: it can only be considered mediocre in term of semantics and visual indicators. Don't do this in production. The going forward and back is done via a combination of [CSS Scroll Snap](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Scroll_Snap) together with [`scroll-behavior: smooth`](https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-behavior) and moving the focus through the slides via anchor links. The nicest trick I pull off is the one for the auto-forward: 1. first I slowly offset the scroll snap points to the right, making the scroll area follow along due to being snapped to them. 2. after having scrolled the width of a whole slide, I deactivate the snapping. The scroll area is now untied from the scroll snap points. 3. Now I let the scroll snap points jump back to their initial positions without them "snap-dragging" the scroll area back with them 4. Then I re-engage the snapping which now lets the scroll area snap to a different snap point 🤯 Whatever... look at the code 🙃 A [Pen](https://codepen.io/Schepp/pen/WNbQByE) by [Christian "Schepp" Schaefer](https://codepen.io/Schepp) on [CodePen](https://codepen.io). [License](https://codepen.io/license/pen/WNbQByE). This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,65 @@ <h1>CSS-only Carousel</h1> <p>This carousel is created with HTML and CSS only.</p> <section class="carousel" aria-label="Gallery"> <ol class="carousel__viewport"> <li id="carousel__slide1" tabindex="0" class="carousel__slide"> <div class="carousel__snapper"> <a href="#carousel__slide4" class="carousel__prev">Go to last slide</a> <a href="#carousel__slide2" class="carousel__next">Go to next slide</a> </div> </li> <li id="carousel__slide2" tabindex="0" class="carousel__slide"> <div class="carousel__snapper"></div> <a href="#carousel__slide1" class="carousel__prev">Go to previous slide</a> <a href="#carousel__slide3" class="carousel__next">Go to next slide</a> </li> <li id="carousel__slide3" tabindex="0" class="carousel__slide"> <div class="carousel__snapper"></div> <a href="#carousel__slide2" class="carousel__prev">Go to previous slide</a> <a href="#carousel__slide4" class="carousel__next">Go to next slide</a> </li> <li id="carousel__slide4" tabindex="0" class="carousel__slide"> <div class="carousel__snapper"></div> <a href="#carousel__slide3" class="carousel__prev">Go to previous slide</a> <a href="#carousel__slide1" class="carousel__next">Go to first slide</a> </li> </ol> <aside class="carousel__navigation"> <ol class="carousel__navigation-list"> <li class="carousel__navigation-item"> <a href="#carousel__slide1" class="carousel__navigation-button">Go to slide 1</a> </li> <li class="carousel__navigation-item"> <a href="#carousel__slide2" class="carousel__navigation-button">Go to slide 2</a> </li> <li class="carousel__navigation-item"> <a href="#carousel__slide3" class="carousel__navigation-button">Go to slide 3</a> </li> <li class="carousel__navigation-item"> <a href="#carousel__slide4" class="carousel__navigation-button">Go to slide 4</a> </li> </ol> </aside> </section> This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,228 @@ @keyframes tonext { 75% { left: 0; } 95% { left: 100%; } 98% { left: 100%; } 99% { left: 0; } } @keyframes tostart { 75% { left: 0; } 95% { left: -300%; } 98% { left: -300%; } 99% { left: 0; } } @keyframes snap { 96% { scroll-snap-align: center; } 97% { scroll-snap-align: none; } 99% { scroll-snap-align: none; } 100% { scroll-snap-align: center; } } body { max-width: 37.5rem; margin: 0 auto; padding: 0 1.25rem; font-family: 'Lato', sans-serif; } * { box-sizing: border-box; scrollbar-color: transparent transparent; /* thumb and track color */ scrollbar-width: 0px; } *::-webkit-scrollbar { width: 0; } *::-webkit-scrollbar-track { background: transparent; } *::-webkit-scrollbar-thumb { background: transparent; border: none; } * { -ms-overflow-style: none; } ol, li { list-style: none; margin: 0; padding: 0; } .carousel { position: relative; padding-top: 75%; filter: drop-shadow(0 0 10px #0003); perspective: 100px; } .carousel__viewport { position: absolute; top: 0; right: 0; bottom: 0; left: 0; display: flex; overflow-x: scroll; counter-reset: item; scroll-behavior: smooth; scroll-snap-type: x mandatory; } .carousel__slide { position: relative; flex: 0 0 100%; width: 100%; background-color: #f99; counter-increment: item; } .carousel__slide:nth-child(even) { background-color: #99f; } .carousel__slide:before { content: counter(item); position: absolute; top: 50%; left: 50%; transform: translate3d(-50%,-40%,70px); color: #fff; font-size: 2em; } .carousel__snapper { position: absolute; top: 0; left: 0; width: 100%; height: 100%; scroll-snap-align: center; } @media (hover: hover) { .carousel__snapper { animation-name: tonext, snap; animation-timing-function: ease; animation-duration: 4s; animation-iteration-count: infinite; } .carousel__slide:last-child .carousel__snapper { animation-name: tostart, snap; } } @media (prefers-reduced-motion: reduce) { .carousel__snapper { animation-name: none; } } .carousel:hover .carousel__snapper, .carousel:focus-within .carousel__snapper { animation-name: none; } .carousel__navigation { position: absolute; right: 0; bottom: 0; left: 0; text-align: center; } .carousel__navigation-list, .carousel__navigation-item { display: inline-block; } .carousel__navigation-button { display: inline-block; width: 1.5rem; height: 1.5rem; background-color: #333; background-clip: content-box; border: 0.25rem solid transparent; border-radius: 50%; font-size: 0; transition: transform 0.1s; } .carousel::before, .carousel::after, .carousel__prev, .carousel__next { position: absolute; top: 0; margin-top: 37.5%; width: 4rem; height: 4rem; transform: translateY(-50%); border-radius: 50%; font-size: 0; outline: 0; } .carousel::before, .carousel__prev { left: -1rem; } .carousel::after, .carousel__next { right: -1rem; } .carousel::before, .carousel::after { content: ''; z-index: 1; background-color: #333; background-size: 1.5rem 1.5rem; background-repeat: no-repeat; background-position: center center; color: #fff; font-size: 2.5rem; line-height: 4rem; text-align: center; pointer-events: none; } .carousel::before { background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Cpolygon points='0,50 80,100 80,0' fill='%23fff'/%3E%3C/svg%3E"); } .carousel::after { background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Cpolygon points='100,50 20,100 20,0' fill='%23fff'/%3E%3C/svg%3E"); }