Create a "slot machine" with dynamic height children

Viewed 505

I am working on a layout that is similar in nature to a slot machine. Each of its children will be text, and the layout is responsive (so at different resolutions, the children's text may or may not wrap to multiple lines, thus changing the height).

The layout will have a visible "viewport" of 3 items at a time. So that the "viewport" does not shift around, all children need to have the same height. This got me thinking of 2 different routes, but I can't make either work.

  1. Use display: flex. With a column layout, you can have them all stack. The problem with this is, I don't think you can make all children have the same height unless you specify a calculated height on the flex container (thus, you'd have to use js to calculate the max height of all the flex children)
  2. Use display: grid. Out of the box you can make all children have equal height with grid. The problem is, how do hide the overflow guaranteeing you are only showing 3 at a time in the "viewport" for the slot machine?

This layout may not be possible without js calculations, but because of the fact that it has to be completely responsive, I don't want to have to redo the calculations on every window resize. Can anyone think of a way to do this using pure css?

I made a fiddle to show a bare-bones implementation. The "viewport" is the red box, and each item is in the blue box. In the real world, I would be hiding everything outside of the red box and would not want to have to specifically set height on any container.

var scroll = document.getElementById('scroll');
var wrapper = document.getElementById('wrapper');

scroll.addEventListener('click', function() {
  wrapper.classList.toggle('scrolled');
});
.example {
  display: flex;
}

.container {
  height: 90px;
  width: 300px;
  outline: 1px solid red;
  z-index:1;
}

.wrapper {
  display: flex;
  flex-direction: column;
  transition-property: transform;
  transition-duration: 500ms;
}

.wrapper.scrolled {
  transform: translateY(-300px);
}

.inner {
  outline: 1px solid blue;
  flex-grow: 1;
  height: 30px;
}

.buttons {
  margin-right: 3em;
}
<div class="example">
  <div class="buttons">
    <button id="scroll">Scroll</button>
  </div>

  <div class="container">
    <div id="wrapper" class="wrapper">
      <div class="inner">Some text</div>
      <div class="inner">Some text</div>
      <div class="inner">Some text</div>
      <div class="inner">Some text</div>
      <div class="inner">Some text</div>
      <div class="inner">Some text</div>
      <div class="inner">Some text</div>
      <div class="inner">Some text</div>
      <div class="inner">Some text</div>
      <div class="inner">Some text</div>
      <div class="inner">Some text</div>
      <div class="inner">Some text</div>
      <div class="inner">Some text</div>
      <div class="inner">Some text</div>
    </div>
  </div>
</div>

1 Answers

Hey so I think I get what you're going for here and designed a "slot machine" mechanic that scales its inner and outer objects using vh.

So the container object would have something like...

.container {
    width: 300px;
    height: 90vh;
    outline: 1px solid red;
    z-index:1;
    overflow: hidden;
}

...and the inner object would have something like...

.inner {
    outline: 1px solid blue;
    flex-grow: 1;
    height: 30vh;
}

I also adjusted the Javascript scrolling to base the amount scrolled off of what object is being scrolled to. This can be automated with something like a timer instead of the button:

var scroll = document.getElementById('scroll');
var wrapper = document.getElementById('wrapper');
var innerArray = document.getElementsByClassName('inner');

var innerNum = 1; // Start at the second element
scroll.addEventListener('click', function() {
  if (innerNum == innerArray.length-2) { // Check to see if the last item has been scrolled to
    innerNum = 0; // Scroll back to the first item if it has
  }
  //wrapper.classList.toggle('scrolled');
  innerArray[innerNum].scrollIntoView({ 
    behavior: 'smooth' 
  });
  innerNum++;
});

Here is the Codepen that demonstrates the example. I can clarify the code further if you would like me to. My apologies if I was way off the ball on what you were going for!

Related