Experiment using CSS scroll snapping in a carousel, along with a light/dark mode toggle.
Created
February 26, 2022 08:40
-
-
Save bebetor/bec7e9cc2a6ef1bbb6120025c68396d1 to your computer and use it in GitHub Desktop.
Scroll Snap Experiment
This file contains 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 characters
main | |
section.pane | |
h1 Adventure Awaits | |
ul.carousel | |
button.theme-toggle | |
| Toggle Theme |
This file contains 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 characters
const images = [ | |
"https://source.unsplash.com/oaEpgHCgTT8", | |
"https://source.unsplash.com/9v_xYRu_laY", | |
"https://source.unsplash.com/qrPqGP-SG8w", | |
"https://source.unsplash.com/zshyCr6HGw0", | |
"https://source.unsplash.com/-g7axSVst6Y", | |
"https://source.unsplash.com/fTKkJL5Xjw8", | |
"https://source.unsplash.com/sPXGnvwOjdU" | |
]; | |
const carousel = document.querySelector('.carousel'); | |
const carouselItems = document.createDocumentFragment(); | |
images.forEach((item, index) => { | |
// Set up elements (tags) | |
const listItem = document.createElement('li'); | |
const figure = document.createElement("figure"); | |
const link = document.createElement("a"); | |
const image = document.createElement("img"); | |
// Set up element attributes | |
listItem.classList.add('carousel-item'); | |
link.href = images[index]; | |
link.target = '_blank'; | |
image.src = `${images[index]}/600x600`; | |
image.loading = 'lazy'; | |
image.alt = ""; // Note: for production, we'd want to set actual per-image alt text | |
// Put the list items together in the <ul> | |
figure.appendChild(image); | |
link.appendChild(figure); | |
listItem.appendChild(link); | |
carouselItems.appendChild(listItem); | |
}); | |
carousel.appendChild(carouselItems); | |
// Light and dark mode | |
const getTheme = () => { | |
return localStorage.getItem('theme') || 'dark'; | |
} | |
const colorScheme = document.querySelector('meta[name="color-scheme"]'); | |
const applyTheme = (theme) => { | |
document.body.className = theme; | |
colorScheme.content = theme; | |
localStorage.setItem('theme', theme); | |
} | |
const themeToggleButton = document.querySelector('.theme-toggle'); | |
let theme = getTheme(); | |
applyTheme(theme); | |
themeToggleButton.addEventListener('click', () => { | |
const newTheme = theme === 'light' ? 'dark' : 'light'; | |
applyTheme(newTheme); | |
theme = newTheme; | |
}) | |
This file contains 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 characters
:root { | |
--gap: 10px; | |
--carousel-count: 4; | |
--black: #1e1d26; | |
--white: #f7f7f7; | |
--light-blue: #b6b9bf; | |
--blue: #334668; | |
--dark-blue: #262733; | |
--light-gray: #eaeaea; | |
--background-image: url('https://source.unsplash.com/g30P1zcOzXo'); | |
--gradient: linear-gradient(rgba(253, 253, 255, 0.52), rgba(0, 0, 0, 0.55)); | |
--button-background: var(--light-gray); | |
color-scheme: dark light; // prefer dark mode | |
} | |
html, | |
body { | |
margin: 0; | |
padding: 0; | |
} | |
* { | |
box-sizing: border-box; | |
} | |
/* Scrollbar styles - https://www.digitalocean.com/community/tutorials/css-scrollbars */ | |
/* Works on Firefox */ | |
* { | |
scrollbar-width: thin; | |
} | |
/* Works on Chrome, Edge, and Safari */ | |
*::-webkit-scrollbar { | |
height: 8px; | |
} | |
*::-webkit-scrollbar-track { | |
background-color: lightgray; | |
border-radius: 6px; | |
@media (prefers-color-scheme: dark) { | |
background-color: #a2a2a2; | |
} | |
} | |
*::-webkit-scrollbar-thumb { | |
background-color: gray; | |
border-radius: 6px; | |
@media (prefers-color-scheme: dark) { | |
background-color: #6a6a6a; | |
} | |
} | |
body { | |
font-family: 'Yeseva One', serif; | |
width: 100%; | |
min-height: 100vh; | |
&.light { | |
--text: var(--blue); | |
--background: var(--white); | |
--carousel-background: var(--light-gray); | |
} | |
&.dark { | |
--text: var(--light-blue); | |
--background: var(--black); | |
--carousel-background: var(--dark-blue); | |
--gradient: linear-gradient(rgba(148, 155, 193, 0.52), rgba(11, 18, 38, 0.55)); | |
} | |
color: var(--text); | |
background-color: var(--background); | |
background-image: var(--gradient), var(--background-image); | |
background-size: cover; | |
background-repeat: no-repeat; | |
@media (min-width: 800px) { | |
--gap: 20px; | |
} | |
} | |
h1 { | |
font-size: 1.3rem; | |
margin: 0 0 2rem; | |
@media (min-width: 800px) { | |
font-size: 2.5rem; | |
} | |
} | |
img { | |
max-width: 100%; | |
height: auto; | |
} | |
main { | |
max-width: 90vw; | |
margin: 3rem auto; | |
display: flex; | |
flex-direction: column; | |
gap: 40px; | |
@media (min-width: 800px) { | |
margin: 4rem auto; | |
max-width: 80vw; | |
} | |
@media (min-width: 1200px) { | |
max-width: calc(1000px + ((var(--carousel-count) - 1) * var(--gap))); | |
max-width: 800px; | |
} | |
} | |
.pane { | |
background-color: var(--carousel-background); | |
border-radius: 3px; | |
box-shadow: 0px 2px 20px rgba(0, 0, 0, 0.36); | |
padding: 3rem; | |
mix-blend-mode: hard-light; | |
} | |
.carousel { | |
overflow-x: auto; | |
overflow-y: hidden; | |
overscroll-behavior-x: contain; | |
-webkit-overflow-scrolling: touch; // For iOS | |
scroll-behavior: smooth; | |
list-style-type: none; | |
display: grid; | |
grid-auto-columns: 300px; | |
grid-template-rows: 300px; | |
grid-auto-flow: column; | |
gap: var(--gap); | |
margin: 0; | |
scroll-snap-type: x mandatory; | |
scroll-padding: 12px; | |
padding: 0 12px 20px; | |
} | |
.carousel-item { | |
scroll-snap-align: start; | |
margin: 8px 0; | |
a { | |
display: inline-block; | |
outline-offset: 6px; | |
&:focus, | |
&:focus-visible { | |
outline: 2px dashed gray; | |
} | |
&:focus:not(:focus-visible) { | |
outline: 0; | |
} | |
} | |
figure { | |
width: 100%; | |
height: 100%; | |
margin: 0; | |
overflow: hidden; | |
} | |
img { | |
display: block; | |
width: 100%; | |
height: 100%; | |
opacity: 0.8; | |
object-fit: cover; | |
background-image: | |
linear-gradient( | |
to bottom, | |
hsl(0 0% 10%), | |
hsl(0 0% 20%) | |
); | |
border-radius: 5px; | |
transition: opacity 0.3s ease-in, transform 0.4s ease-in; | |
&:hover { | |
opacity: 1; | |
transform: scale(1.1); | |
} | |
} | |
} | |
.theme-toggle { | |
font-family: "Oswald"; | |
text-transform: uppercase; | |
color: var(--dark-blue); | |
background-color: var(--button-background); | |
border: 2px solid transparent; | |
padding: 8px 12px; | |
border-radius: 3px; | |
transition: all 0.3s ease; | |
max-width: 150px; | |
margin-left: auto; | |
&:hover { | |
background-color: #c1c1c1; | |
border: 2px solid #c1c1c1; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment