<h1>CSS Dynamic Snapping Text</h1>
<p>CSS Trickery inspired by Jason Pamental’s <a href="https://mobydick.wales/">digital book experience</a>. How do you have multiple defined-width textboxes with unknown text length on a single page, each with swipable columns horizontally and with snapping?
  <div class="container">
    <div class="textbox-container">
      <div class="button-container">
        <div class="button prev"><i class="fa fa-chevron-circle-left"></i></div>
        <div class="button next"><i class="fa fa-chevron-circle-right"></i></div>
      </div>
      <div class="textbox">
        <article class="content">
<h1>Lorem ipsum dolor sit amet consectetuer adipiscing 
elit</h1>
<p>Lorem ipsum dolor sit amet, consectetuer adipiscing 
elit. Aenean commodo ligula eget dolor. Aenean massa 
<strong>strong</strong>. Cum sociis natoque penatibus 
et magnis dis parturient montes, nascetur ridiculus 
mus. Donec quam felis, ultricies nec, pellentesque 
eu, pretium quis, sem. Nulla consequat massa quis 
enim. Donec pede justo, fringilla vel, aliquet nec, 
vulputate eget, arcu. In enim justo, rhoncus ut, 
imperdiet a, venenatis vitae, justo. Nullam dictum 
felis eu pede 
mollis pretium. Integer tincidunt. Cras dapibus. 
Vivamus elementum semper nisi. Aenean vulputate 
eleifend tellus. Aenean leo ligula, porttitor eu, 
consequat vitae, eleifend ac, enim. Aliquam lorem ante, 
dapibus in, viverra quis, feugiat a, tellus. Phasellus 
viverra nulla ut metus varius laoreet. Quisque rutrum. 
Aenean imperdiet. Etiam ultricies nisi vel augue. 
Curabitur ullamcorper ultricies nisi.</p>
<h1>Lorem ipsum dolor sit amet consectetuer adipiscing 
elit</h1>
<h2>Aenean commodo ligula eget dolor aenean massa</h2>
<p>Lorem ipsum dolor sit amet, consectetuer adipiscing 
elit. Aenean commodo ligula eget dolor. Aenean massa. 
Cum sociis natoque penatibus et magnis dis parturient 
montes, nascetur ridiculus mus. Donec quam felis, 
ultricies nec, pellentesque eu, pretium quis, sem.</p>
<h2>Aenean commodo ligula eget dolor aenean massa</h2>
<p>Lorem ipsum dolor sit amet, consectetuer adipiscing 
elit. Aenean commodo ligula eget dolor. Aenean massa. 
Cum sociis natoque penatibus et magnis dis parturient 
montes, nascetur ridiculus mus. Donec quam felis, 
ultricies nec, pellentesque eu, pretium quis, sem.</p>
<ul>
  <li>Lorem ipsum dolor sit amet consectetuer.</li>
  <li>Aenean commodo ligula eget dolor.</li>
  <li>Aenean massa cum sociis natoque penatibus.</li>
</ul>
<p>Lorem ipsum dolor sit amet, consectetuer adipiscing 
elit. Aenean commodo ligula eget dolor. Aenean massa. 
Cum sociis natoque penatibus et magnis dis parturient 
montes, nascetur ridiculus mus. Donec quam felis, 
ultricies nec, pellentesque eu, pretium quis, sem.</p>
        </article>
        <div class="pager_wrapper"></div>
      </div>
    </div>

    <p></p>

    <p></p>

    <p></p>

    <div class="textbox-container">
      <div class="button-container">
        <div class="button prev"><i class="fa fa-chevron-circle-left"></i></div>
        <div class="button next"><i class="fa fa-chevron-circle-right"></i></div>
      </div>
      <div class="textbox">
        <article class="content">
          <p>purus faucibus ornare suspendisse sed. Porttitor eget dolor morbi non arcu risus. Sed velit dignissim sodales ut. Est pellentesque elit ullamcorper dignissim cras. Lacus viverra vitae congue eu consequat ac felis. Quis blandit turpis cursus in.</p>
          <p>Eget nulla facilisi etiam dignissim diam quis enim lobortis scelerisque. Ac felis donec et odio pellentesque diam volutpat commodo. Cursus in hac habitasse platea dictumst quisque sagittis purus. Urna nec tincidunt praesent semper feugiat nibh sed pulvinar proin. Mi sit amet mauris commodo quis imperdiet massa. Eros donec ac odio tempor orci. Morbi tristique senectus et netus. Pretium vulputate sapien nec sagittis aliquam malesuada bibendum. In hac habitasse platea dictumst vestibulum.</p>
          <p>Viverra justo nec ultrices dui sapien eget mi proin sed. Ac turpis egestas sed tempus urna et pharetra pharetra. Maecenas pharetra convallis posuere morbi. Magna sit amet purus gravida quis blandit turpis cursus in. Cras semper auctor neque vitae tempus. A diam sollicitudin tempor id eu nisl nunc mi ipsum. Diam maecenas ultricies mi eget mauris. Et ultrices neque ornare aenean. Integer eget aliquet nibh praesent tristique magna sit. Imperdiet nulla malesuada pellentesque elit eget.</p>
          <p>Luctus venenatis lectus magna fringilla urna porttitor rhoncus dolor purus. Posuere ac ut consequat semper viverra nam libero justo. Fringilla ut morbi tincidunt augue. Turpis massa tincidunt dui ut. Penatibus et magnis dis parturient montes nascetur ridiculus. Neque vitae tempus quam pellentesque nec nam aliquam sem. Fringilla phasellus faucibus scelerisque eleifend. Eget gravida cum sociis natoque penatibus. Ut ornare lectus sit amet est placerat in egestas. Aliquet eget sit amet tellus cras adipiscing.</p>
          <p>Fames ac turpis egestas integer eget aliquet nibh praesent. Suspendisse sed nisi lacus sed viverra. Tincidunt vitae semper quis lectus nulla at. Morbi blandit cursus risus at ultrices mi. Quis eleifend quam adipiscing vitae proin. Ornare quam viverra orci sagittis eu volutpat odio facilisis. Ullamcorper dignissim cras tincidunt lobortis feugiat vivamus at augue. Ut venenatis tellus in metus vulputate eu scelerisque felis imperdiet. Auctor neque vitae tempus quam pellentesque nec nam. Vulputate sapien nec sagittis aliquam malesuada bibendum arcu vitae.</p>
        </article>
        <div class="pager_wrapper"></div>
      </div>
    </div>
    
  </div>
html,
body {
  background-color: chocolate;
  text-align: center;
}

.container {
  display: flex;
}

h1, p, a, h2, ul {
  font-family: arial;
  color: white;
}

p {
  margin-top: 0px;
}

.button {
  background-color: transparent;
  border: none;
  padding: 0px;
  margin: 0px;
  width: 20px;
  height: 20px;
  font-size: 20px;
  cursor: pointer;
}

/* Darker background on mouse-over */
.button:hover {
  color: orange;
}

.textbox-container{
  height: 400px;
    width: 20%;
    margin: 0 auto;
  
}

.textbox {
  width: 100%;
  height: 100%;
 overflow-x: hidden; 
  scroll-snap-type: x mandatory;
  overflow-y: hidden;
 
}

.content {
  text-align: left;
  columns: 100vw auto;
  column-gap: 0px;
  height: 90%;
  font: 120%/1.4 Georgia;
  margin-top: 0;
  padding-top: 0;
  padding-bottom: 1rem;
  position: relative;
}

.pager_wrapper {
  display: flex;
  width: calc(100% * var(--page-count));
 
}

.pager-wrapper--page {
  background-color: white;
  float: left;
  height: 10px;
  margin-left: 0;
  margin-right: 5px;
  max-width: none;
  width: 100%;
  scroll-snap-align: start;
  position: relative;
  z-index: 10;
}

.counter {
  text-align: center;
}

.button-container {
  color: white;
  display: flex;
  position: relative;
  top: 0px;
 justify-content: space-between;
}

.prev {
  position: relative;
  left: -30px;
}

.next {
  position: relative;
  right: -30px;
}

.round {
  border-radius: 50%;
}
window.onload = function () {
 pageCounter();
};
window.onresize = function () {
  pageCounter();
};

var dd = 0;

function pageCounter() {
  var textBlocks = document.getElementsByClassName("textbox-container");
  console.log("PageCounter: TextBlocks.length" + textBlocks.length);

  for (var i = 0; i < textBlocks.length; i++) {
    console.log("ForLoop: i = " + i + " TextBlocks: " + textBlocks[i]);
    /// for each textbox container on the page, figure out the page count based on the columns in the content div.
    var contentContainerWidth = textBlocks[i]
      .getElementsByClassName("textbox")[0]
      .getElementsByClassName("content")[0].scrollWidth;
    var textBoxWidth = textBlocks[i].getElementsByClassName("textbox")[0]
      .clientWidth;
    var pageCount = Math.floor(contentContainerWidth / textBoxWidth);

    ///Give the page count class to the the textbox-container
    textBlocks[i].style.setProperty("--page-count", pageCount);

    /// add hidden divs to be used by the snapping scroller
    var currentDiv = textBlocks[i].getElementsByClassName("pager_wrapper")[0];
    currentDiv.innerHTML = "";
    for (let i = 0; i < pageCount; i++) {
      var pageDiv = document.createElement("div");
      var newContent = document.createTextNode(" ");
      pageDiv.appendChild(newContent);
      pageDiv.classList.add("pager-wrapper--page");
      pageDiv.classList.add("border");
      currentDiv.appendChild(pageDiv);
    }

    //the next and back buttons
    //distance to move columns on click
    dd = contentContainerWidth / pageCount;
    //position buttons at midway point
    var halfwayPixels = textBlocks[i].getElementsByClassName("textbox")[0].getElementsByClassName("content")[0].offsetHeight/2;
    textBlocks[i].getElementsByClassName("button-container")[0].style.top = halfwayPixels + "px";
    
    // add some event listeners that move the correct txtbox on the page back and forward
    textBlocks[i]
      .getElementsByClassName("prev")[0]
      .addEventListener("click", function (event) {
        //console.log('Function thinks event target is ' + event.target.parentElement.parentElement.parentElement.className);
        event.target.parentElement.parentElement.parentElement
          .getElementsByClassName("textbox")[0]
          .scrollBy({
            top: 0,
            left: -dd,
            behavior: "smooth"
          });
      });
    textBlocks[i]
      .getElementsByClassName("next")[0]
      .addEventListener("click", function scrollToNextPage() {
        event.target.parentElement.parentElement.parentElement
          .getElementsByClassName("textbox")[0]
          .scrollBy({
            top: 0,
            left: dd,
            behavior: "smooth"
          });
      });
  }
}
Run Pen

External CSS

  1. https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.5.8/slick.min.css
  2. https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.5.8/slick-theme.min.css

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js
  2. https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.5.8/slick.min.js