<p><label>Ширина [1..10]: <input type="range" min="1" max="10" step="1" value="2" id="shwidth"/></label></p>
<p><label>Интервал времени [0.5..5] сек: <input type="range" min="500" max="5000" step="100" value="800" id="tointv" style="width: 60mm;"/></label></p>
<p><label>Назад?: <input type="checkbox" id="swleft"/></label></p>
<p><label>На позицию: <input type="number" id="swpos"/></label></p>
<p id="info"></p>
<p></p>

<div class="single">0</div>
<div class="single">1</div>
<div class="single">2</div>
<div class="single">3</div>
<div class="single">4</div>
<div class="single">5</div>
<div class="double">6</div>
<div class="single">7</div>
<div class="single">8</div>
<div class="double">9</div>
<div class="double">10</div>
<div class="single">11</div>
<div class="single">12</div>
<div class="double">13</div>
<div class="single">14</div>
<div class="triple">15</div>
<div class="single">16</div>
<div class="single">17</div>
body{
  background: #335;
  overflow-x: hidden;
  text-align: center;
  color: white;
}

.single, .double, .triple{
  height: 30mm;
  margin: 2mm auto -32mm;
  background: white;
  opacity: 0.5;
  color: black;
  width: calc( var(--base) * 20mm );
  transform: translate( calc( ( var(--pos) - var(--off) + var(--sid) * 1.2 ) * 20mm +
    ( var(--ind) - var(--cur) - ( var(--cnt) - 1 ) / 2 ) * 2mm ), 0 );
  transition: transform 0.3s;
}
.show{
  opacity: 1;
}
.single{
  --base: 1;
}
.double{
  --base: 2;
}
.triple{
  --base: 3;
}
function qs( a, n ) { return ( n || document ) ?. querySelector( a ) }
function qsa( a, n ) { return [ ...( n || document ) ?. querySelectorAll( a ) || [] ] }



function widbyname( e ) {
  return [ 'single', 'double', 'triple' ].findIndex( n => e.classList.contains( n ) ) + 1;
}

// элементов под ширину
function widsum( a, i, s, p = -1, root = true ) {
  const e = a[ i ];
  if( !e ) return [];
  s = s - widbyname( e );
  if( s < 0 ) return root ? [ e ] : [];
  i = i + ( p || 1 );
  if( p < 0 ) return [ ...widsum( a, i, s, p, false ), e ];
  return [ e, ...widsum( a, i, s, p, false ) ];
}

// ширина элементов
function sumwid( a, i, p = -1 ) {
  const e = a[ i ];
  if( !e ) return 0;
  return widbyname( e ) + sumwid( a, i + ( p || 1 ), p );
}


function show( slides, summed ) {
  const s0 = slides.indexOf( summed.at( 0 ) );
  const s1 = slides.indexOf( summed.at( -1 ) );
  const n = Math.min( s0, s1 );
  const m = Math.max( s0, s1 );
  const off = sumwid( slides.slice( 0, n ), 0, 1 ) + sumwid( summed, 0, 1 ) / 2;
  slides.forEach( ( s, i ) => {
    const pos = sumwid( slides, i, -1 ) - widbyname( s ) / 2;
    s.style.setProperty( '--ind', i );
    s.style.setProperty( '--cur', n );
    s.style.setProperty( '--pos', pos );
    s.style.setProperty( '--off', off );
    s.style.setProperty( '--sid', ( i < n ) && -1 || ( i > m ) && 1 || 0 );
    s.style.setProperty( '--cnt', summed.length );
    s.classList.toggle( 'show', summed.includes( s ) );
  } );
}


( function f( s, n ) {
  const wid = parseInt( qs( '#shwidth' ).value ) || 2;
  const to = parseInt( qs( '#tointv' ).value ) || 800;
  const ward = qs( '#swleft' ).checked ? -1 : 1;
  const needpos = qs( '#swpos' ).valueAsNumber;
  const slides = qsa( s );
  const summed = widsum( slides, n, wid, ward );
  show( slides, summed, n );
  qs('#info').innerHTML = JSON.stringify( { wid, to, ward, n }, 2, 2 );
  n = isNaN( needpos ) ?
    ( n + ward * summed.length + slides.length ) % slides.length :
    needpos;
  setTimeout( f, to, s, n );
} ) ( 'div', 0 );

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.