Horizontal Scrolling within bootstrap Container (but outside)

776 views Asked by At

I'm using bootstrap 4, and I have a container. Within this I have a horizontal scroll-able area with cards inside it. I would like these cards to be visible outside the container area when scrolled or if the cards exceed the container.

I have tried to change the overflow from scroll to visible, but if I do this I loose the ability to scroll horizontally. I tried changing the positions of the div's. Whatever I do I'm not able to get the content from within the scroll-able area to be visible outside the container but also still scroll-able.

Is there a CSS approach to this or any JS ways to do this?

var root = document.documentElement;
const lists = document.querySelectorAll('.hs'); 

lists.forEach(el => {
  const listItems = el.querySelectorAll('li');
  const n = el.children.length;
  el.style.setProperty('--total', n);
});
:root {
  --gutter: 20px;
}

.app {
  padding: var(--gutter) 0;
  display: grid;
  grid-gap: var(--gutter) 0;
  grid-template-columns: var(--gutter) 1fr var(--gutter);
  align-content: start;
}

.app > * {
  grid-column: 2 / -2;
}

.app > .full {
  grid-column: 1 / -1;
}

.hs {
  display: grid;
  grid-gap: calc(var(--gutter) / 2);
  grid-template-columns: 10px repeat(var(--total), calc(50% - var(--gutter) * 2)) 10px;
  grid-template-rows: minmax(150px, 1fr);
  
  overflow-x: scroll;
  scroll-snap-type: x proximity;
  padding-bottom: calc(.75 * var(--gutter));
  margin-bottom: calc(-.25 * var(--gutter));
    
}

.hs:before,
.hs:after {
  content: '';
}

ul {
  list-style: none;
  padding: 0;
}

.hs > li,
.item {
  scroll-snap-align: center;
  padding: calc(var(--gutter) / 2 * 1.5);
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  background: #000;
  color:#fff;
  border-radius: 8px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.4.1/js/bootstrap.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.3/css/bootstrap.min.css" rel="stylesheet"/>

<div class="container">
  <h1 id="page-title-result">Title</h1>

  <div class="app">  
     <ul class="hs full">
       <li class="item">test</li>
       <li class="item">test</li>
       <li class="item">test</li>
       <li class="item">test</li>
       <li class="item">test</li>
       <li class="item">test</li>
       <li class="item">test</li>
       <li class="item">test</li>
       <li class="item">test</li>
       <li class="item">test</li>
       <li class="item">test</li>
    </ul>
  
    <ul class="hs full">
       <li class="item">test</li>
       <li class="item">test</li>
       <li class="item">test</li>
        <li class="item">test</li>
    </ul>
  
    <div class="container">
       <div class="item">
         <h3>Block for context</h3>
       </div>
    </div>
  </div>
</div>

https://codepen.io/cameronredlet/pen/BayYgry

Intended Goal Image

1

There are 1 answers

0
Max On

I don't think my solution is elegant, but I share it as it works.

In short

Make the scrolling section fullwidth, remove margins, then add paddings that equal to .container's margins with JS.

In long

Here is what I wanted to get:

What I wanted to get

Of course gallery's elements hid outside the container:

Elements are hiding outside the container

Same with margins highlighted:

Elements are hiding outside the container, margins highlighted

What I did:

  1. made the gallery fullwidth (.container-fluid or plain width: 100%);
  2. added padding-left and padding-right

Solution

These paddings must be equal to Bootstrap container's margins. I managed it with this code:

  document.querySelectorAll('.gallery').forEach(function(gallery) {
    function offsetToPadding() {

      // Effectively, this is the value of container's margin-left and margin-right
      // Don't forget to specify it for your page
      let offset = document.querySelector(".container").offsetLeft;

      // Set this value to gallery's paddings.
      gallery.style.paddingLeft  = offset +'px';
      gallery.style.paddingRight = offset +'px';
    }

    // Edit paddings every time when page is loaded or resized
    document.addEventListener("DOMContentLoaded", offsetToPadding);
    window.addEventListener("resize", offsetToPadding);
  }

You will probably need to add some extra padding, as bootstrap containers have their own .75rem padding (in Bootstrap 5)

  document.querySelectorAll('.gallery').forEach(function(gallery) {
    function offsetToPadding() {

      let offset = document.querySelector(".container").offsetLeft;

      // Add bootstrap container default padding to offset.
      gallery.style.paddingLeft  = 'calc(' + offset +'px + .75rem)';
      gallery.style.paddingRight = 'calc(' + offset +'px + .75rem)';
    }

    document.addEventListener("DOMContentLoaded", offsetToPadding);
    window.addEventListener("resize", offsetToPadding);
  }