<div class="controls">
<label for="vertical">Vertical</label>
<input type="radio" checked name="orientation" id="vertical"/>
<label for="horizontal">Horizontal</label>
<input type="radio" name="orientation" id="horizontal"/>
</div>
<section class="scroller">
<article>
<div class="indicator indicator--top">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" d="M4.5 15.75l7.5-7.5 7.5 7.5" />
</svg>
</div>
<p>Lorem ipsum, dolor sit amet consectetur adipisicing elit. Amet animi consequatur atque accusantium soluta cumque, temporibus ipsam eos voluptas porro architecto expedita quisquam eum et necessitatibus culpa odio, laudantium reprehenderit.</p>
<p>Maxime perferendis nostrum, temporibus quibusdam delectus, rerum laudantium ad eius reprehenderit labore accusamus voluptatibus doloremque, eveniet autem veritatis nulla nam ipsum quaerat repudiandae ut perspiciatis iste. Voluptatibus quasi ea natus.</p>
<p>Optio sapiente ipsum, non autem aspernatur aperiam magnam! Vel accusantium unde quibusdam neque. A ullam quod quia aspernatur molestias voluptatem ea in deleniti ad explicabo, pariatur facilis harum inventore aliquam.</p>
<p>Excepturi suscipit nulla iure sit, doloremque numquam. Ullam id, earum neque cum accusamus debitis illo, dolorem nostrum iste amet optio culpa. Vero labore architecto, soluta at placeat dolorum aliquam debitis.</p>
<p>Minus amet laudantium ex ab. Harum praesentium in quia accusantium aut perferendis iure inventore impedit officiis, pariatur excepturi voluptate nostrum ipsam quam quod recusandae voluptatibus sit cupiditate fugit ducimus distinctio.</p>
<p>Cumque, dolorum. Vitae, odio tempore. Illum unde architecto eligendi et. Non quibusdam iusto adipisci ullam est porro magni mollitia neque laboriosam doloribus tempore modi laudantium nostrum fugit, provident sunt dolorum!</p>
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Repellendus, quis deserunt. Nemo aliquid ratione magni labore asperiores. Consequuntur, laborum perspiciatis porro optio soluta, nesciunt est laudantium eligendi voluptatum quos vel?</p>
<p>Doloremque eligendi velit voluptas eveniet veniam nesciunt, esse harum exercitationem laborum, soluta ad, vitae ut ullam consequuntur culpa inventore reiciendis iste dolorum! Incidunt corrupti eligendi officiis dolor nemo quidem recusandae.</p>
<p>Animi inventore culpa eum eaque sed tempore illo, ipsa ea optio soluta atque itaque quos beatae dolore. Nam aliquid inventore itaque ab perferendis ratione soluta quod est, doloribus fugit magni.</p>
<p>Ad excepturi ex veniam quam quas nesciunt deleniti suscipit voluptatem omnis enim. Soluta magni dolore nostrum omnis? Tempora soluta doloremque vel veritatis, repellendus dolorem dicta dignissimos quaerat atque, recusandae quis.</p>
<p>Culpa beatae recusandae impedit unde saepe quos explicabo alias reprehenderit accusantium laudantium aspernatur, commodi veniam quasi vel ratione corrupti aliquam consequatur similique enim sunt! Quod facere cum at saepe cumque.</p>
<p>Rem eos laudantium culpa enim quibusdam, in consequatur non ea, iste illum minima aperiam accusamus ducimus repudiandae soluta, blanditiis at debitis magni excepturi delectus? Inventore necessitatibus laudantium accusantium ullam ad.</p>
<p>Alias deserunt possimus ipsum nemo provident dolore, reprehenderit id? Similique voluptas ipsa perferendis eius et, a, odit minus neque laboriosam modi quisquam, vel eum blanditiis! Aliquid soluta recusandae nostrum dolor.</p>
<p>Animi quas dolorum tempora consequatur sequi? Ratione ipsa consequuntur est quibusdam unde hic, inventore rerum alias, quasi aut maiores! Quaerat eligendi ut vitae, veniam officiis delectus animi repudiandae exercitationem! Ducimus.</p>
<p>Necessitatibus vitae porro, quos eum dolorem, aliquam corporis perspiciatis cumque facilis maxime nobis praesentium quia earum tempora quisquam provident ab laborum ea nostrum facere esse fugiat? Nostrum deleniti eligendi debitis.</p>
<p>Consequatur odit reprehenderit culpa, delectus libero pariatur placeat nobis ut, quidem cum molestias facere porro aperiam similique perferendis maxime ea debitis numquam, possimus hic. Quisquam modi ipsa consequuntur nemo sint!</p>
<div class="indicator indicator--bottom">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" d="M19.5 8.25l-7.5 7.5-7.5-7.5" />
</svg>
</article>
</div>
</section>
* {
box-sizing: border-box;
}
body {
display: grid;
place-items: center;
min-height: 100vh;
background: hsl(0 0% 80%);
accent-color: hsl(250 90% 70%);
}
.controls {
position: fixed;
top: 1rem;
right: 1rem;
display: grid;
grid-template-columns: auto 1fr;
gap: 0 1rem;
}
.scroller {
width: 50ch;
height: 80vh;
overflow: auto;
position: relative;
background: canvas;
padding: 0 1rem;
resize: both;
color: hsl(0 0% 18%);
border-radius: 0.5rem;
box-shadow: 0 0 2rem -1rem hsl(0 0% 10% / 0.75);
}
svg {
width: 24px;
}
.indicator {
position: sticky;
display: flex;
align-items: center;
justify-content: center;
background: canvas;
height: 48px;
/* Scroll stuff */
--scroll-buffer: 2rem;
opacity: 0;
animation: reveal both linear;
animation-timeline: scroll(nearest);
animation-range: 0 var(--scroll-buffer);
}
.indicator--top {
top: 0;
border-bottom: 1px solid hsl(0 0% 0% / 0.5);
}
:root:has(#horizontal:checked) article {
gap: 2rem;
display: flex;
align-items: center;
height: 100%;
width: 800vw;
}
:root:has(#horizontal:checked) article p {
flex: 1 0 100cqi;
display: grid;
place-items: center;
padding: 4rem;
scroll-snap-align: center;
}
:root:has(#horizontal:checked) .scroller {
padding: 1rem 0;
overflow-x: auto;
scroll-snap-type: x mandatory;
}
:root:has(#horizontal:checked) .indicator--bottom svg,
:root:has(#horizontal:checked) .indicator--top svg {
rotate: -90deg;
}
:root:has(#horizontal:checked) .indicator {
height: 100%;
width: 2rem;
position: absolute;
animation-timeline: --article;
clip-path: inset(2rem 0 2rem 0);
}
:root:has(#horizontal:checked) .indicator--top {
border-bottom: none;
align-self: flex-start;
left: 0;
border-right: 1px solid hsl(0 0% 0% / 0.5);
}
:root:has(#horizontal:checked) .scroller {
container-type: inline-size;
}
.indicator--bottom {
bottom: 0;
border-top: 1px solid hsl(0 0% 0% / 0.5);
animation-range: calc(100% - var(--scroll-buffer)) 100%;
animation-direction: reverse;
}
:root:has(#horizontal:checked) .indicator--bottom {
right: 0;
bottom: unset;
border-left: 1px solid hsl(0 0% 0% / 0.5);
border-top: none;
}
:root:has(#horizontal:checked) article {
scroll-timeline: --article;
scroll-timeline-axis: inline;
width: 100%;
overflow: auto;
scroll-snap-type: x mandatory;
}
@keyframes reveal {
to {
opacity: 1;
}
}
This Pen doesn't use any external CSS resources.