<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 );
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.