Update: A new version of this post is available on CSS Tricks!
I became a professional developer after completing the Front End Certificate, but still work on many of the projects to sharpen my skills. Since I am not overly concerned with the certificates, I follow the project user stories only loosely – often adding or removing features as I see fit. I added a backend component to the Wikipedia Viewer Project, and elected to complete the Simon, Game of Life, and Voting App projects with Vue instead of React.
I am currently working on the Book Trading Club project, and have decided to create a carousel to display the books that are available to be traded. Specifically, I would like to (mostly) replicate the Netflix slider, and have been searching for ways to do so.
A Note on Carousels
As many UI experts will tell you, carousels are a notoriously underused component on the web – users just don’t click on them very often. In addition to this, they are hard to get right. They are often buggy, and require special care for mobile. Even my favourite slider library, Slick, comes with its own list of problems – it requires jQuery as a dependency, and has issues playing nice with bundlers like Browserify and Webpack.
Despite all these issues, Netflix has successfully integrated the carousel as the core component of their browse page (perhaps one of the most clicked pages on the web?), and I think that it looks great.
A Trivial Solution
This was my first attempt:
The idea here is to take advantage of Flexbox, which will automatically resize sibling elements when the hovered slide grows to
width: 150%; Setting
align-items: center; on the parent will prevent each item from stretching to equal heights, but the height of the parent itself still grows to fit the hovered item, creating unwanted vertical movement.
Another problem with this approach is that it relies on animating width, which is generally less performant than animating transforms.
Finally, this doesn’t actually replicate the Netflix UI properly. Under close inspection you will notice that the Netflix slider row lengthens when a single item grows, and the other slides are allowed to move outside of the viewport.
A Better Solution
If the goal is to animate transform instead of width than the sibling items will need to be moved manually. Additionally, there needs to be a way to push items that come before the hovered slide leftward, and items that come after the hovered slide rightward.
At first glance this seems impossible given the behaviour of sibling selectors in CSS – only elements that come after the selected in the DOM can be accessed. For example, the code
.box:hover ~ .box will only select elements on the right of the target slide. How do we move elements on the left?
The answer is subtraction. By creating another selector that targets all of the items inside the parent container, we can move those items left, overwrite the sibling’s of the hovered element to move right, and set the target element itself to scale.
The math of the operation is straight forward. A scaling of 150% will cause an expansion of an extra 50% horizontally, or 25% on either side. The translation needs to match this. Here is the code of everything brought together.