V

V
5 min read

CSS Mastery: Trendy Horizontal Scrolling Portfolio in only 100 Lines

You’ve probably seen these gorgeous scrolling portfolios lately, featured on Codrops and several Awwwards portfolios. When I began to dig in to the methods for building one, I was disappointed to find most of them use Javascript or worse, WebGL. I thought back to the “news ticker” of yesteryear, knowing it was possible to recreate these effects in CSS alone, allowing for a leaner, better experience overall.

If you missed it, check out CSS Mastery: Animation @keyframes to get your mind thinking about how your elements should move. CSS transition and animation are almost the same, where animation can dig deeper by giving your element a defined timeline for when different style changes take effect or, in this case, to move something from one place to another.

Here, we combine 5 powerful CSS properties for an optimally responsive horizontal scrolling portfolio with text and hover effects: flexbox @animation loading viewport units clip-path

Disclaimer: you’re gonna see a little jerk when this loads due to Codepen

Breaking it down

The structure is pretty simple, allowing you to apply the styling shown here to other scenarios such as Elementor or Gutenberg blocks in WordPress without much fuss (you just need to get the class names on the right elements).

<div class="text-scroller">

<div class="scroller-left">
<div class="werd">Words go here</div>
</div>
<div class="scroller-right">
<div class="werd">Words go here</div>
</div>

</div>

Text Scroller

We use translate3d in an animation @keyframe to move the text and images from right to left with an animation we named “scroller”:

@keyframes scroller {
 0% {
   -webkit-transform: translate3d(0, 0, 0);
   transform: translate3d(0, 0, 0);
   visibility: visible;
 }
 100% {
   -webkit-transform: translate3d(-100%, 0, 0);
   transform: translate3d(-100%, 0, 0);
 }
}

Next, the text-scroller class just handles the styling and position of the scrolling text section. We also want to align the leading scroller to the left edge of the viewport so the copy can follow. This is what creates the “infinite” feel.

Positioning

.text-scroller{
   position: fixed;
   display: inline-flex;
   width: 100%;
   overflow: hidden;
   height: 50vh;
   text-transform: uppercase;
   align-items: center;
   justify-content: center;
}
.scroller-left {
left: 100%;
}

Scroll Effect

And now for the effects. The important bits here are the white-space: nowrap and animation properties. infinite and linear are the values that create the movement from right to left and the duration is how fast or slow it goes. The font size and number of words (or the length of your sentence) will also affect how fast the movement appears.

.werd {
  height: 4rem;
  padding-left: 1rem;
  line-height: 4rem;
  white-space: nowrap;
  -webkit-animation-iteration-count: infinite;
  animation-iteration-count: infinite;
  -webkit-animation-timing-function: linear;
  animation-timing-function: linear;
  -webkit-animation-name: scroller;
  animation-name: scroller;
  -webkit-animation-duration: 40s;
  animation-duration: 40s;
  font-size: 6vw;
  color: white;
}

To allow the fonts to scale elegantly in the browser, I opted for the VW unit here versus rems.

Image Scroller

The image scroller uses much of the same structure and styles, with a couple variations to handle responsive scaling of the images, and a nice hover interaction.

<div class="image-scroller">

<div class="scroller-left">
<div class="look">
<img loading="lazy" src="..." />
</div>
</div>

<div class="scroller-right">
<div class="look">
<img loading="lazy" src="..." />
</div>
</div>

</div>

loading

Very often, webpages contain many images that contribute to data-usage and how fast a page can load. Most of those images are off-screen (non-critical), requiring user interaction (an example being scroll) in order to view them.

The loading attribute on an <img> element (or the loading attribute on an <iframe>) can be used to instruct the browser to defer loading of images/iframes that are off-screen until the user scrolls near them. This is a relatively new native lazy-load method that removes the need for JS. It probably doesn’t work in Edge/Internet Explorer.

.image-scroller{
  position: fixed;
  display: flex;
  top: 24%;
  width: 100%;
  overflow: hidden;
  min-height: 80vh;
  align-items: center;
  justify-content: center;
  z-index: 444;
}

I made this section a little taller so there is some space between the text and the landscape oriented images. I also added a z-index for those oddball browsers that have issues with clipping.

Scroll & Hover Effect

The styling of the image wrapper handles the scrolling in the exact same way as the text:

.image-scroller .look{
 display: flex;
-webkit-animation-iteration-count: infinite;
animation-iteration-count: infinite;
-webkit-animation-timing-function: linear;
animation-timing-function: linear;
-webkit-animation-name: scroller;
animation-name: scroller;
-webkit-animation-duration: 40s;
animation-duration: 40s;
justify-content: space-evenly;
align-items: flex-end;
}

The styling for the image itself handles three things: responsive scaling thanks to VW, setup for the hover interaction with clip-path and a cubic bezier transition which gives the image a smooth scaled-down effect without actually scaling the image (which tends to be wonky and pixelly).

.look > img{
  width: 10vw;
  margin: 2em;
  filter: grayscale(0);
  -webkit-clip-path: inset(0 0 0 0);
  clip-path: inset(0 0 0 0);
  -webkit-transition: 1s cubic-bezier(.075,.82,.165,1);
  -moz-transition: 1s cubic-bezier(.075,.82,.165,1);
  transition: 1s cubic-bezier(.075,.82,.165,1);
}

And now for the hover animation (using a variant of the bloom animation I teach in the @keyframe tutorial) and the cubic transition:

@keyframes bloom {
 0% {
   filter: grayscale(0);
 }
 40% {
   filter: grayscale(.5);
 }
 100% {
   filter: grayscale(.8);
 }
}
.look img:hover{
   animation: bloom ease-in-out .75s forwards;
   clip-path: inset(10px);
}

Resources

Share on twitter
Share on linkedin
Share on email
Share on facebook
Share on email
Share on print

Letterer. Conjuror.
_X Designer.

I am  a creative polymath currently located in Croatia. I accept commissions for custom websites, ecommerce or print design on a limited freelance basis. I currently work as a content editor & curator for Envato, a certified B corp.

View CV

 

Currently accepting proposals for 2021. Have a crazy idea? Tell me about it.