JSFiddle - React, Tailwind, and code Playground

by Krzysztof

HTML

<div class="upcoming-element">
    <p>Upcoming:</p>
    <div class="marqueeable">
        <div class="wrapper active">
            <div class="subwrapper">
                 <h3>Watch this new video! Watch this new video! Watch this new video!</h3>
            </div>
        </div>
        <div class="wrapper masked">
            <div class="subwrapper">
                 <h3>Watch this new video! Watch this new video! Watch this new video!</h3>
            </div>
        </div>
        <div class="wrapper masked">
            <div class="subwrapper">
                 <h3>Watch this new video! Watch this new video! Watch this new video!</h3>
            </div>
        </div>
    </div>
</div>

<button id="maskLeft">maskLeft</button>
<button id="maskRight">maskRight</button>
<button id="scroll">scroll</button>
<!-- Used to measure width of h3 title -->
<h3 class="measure"></h3>

CSS

body {
    background-color: #F00;
}
p, h3 {
    margin: 2px;
}
p {
    display: inline-block;
    margin-left: 12px;
}
h3 {
    padding-left: 12px;
    white-space: nowrap;
}
h3.measure {
    display: none;
    padding: 0 10px;
}
.upcoming-element {
    width: 450px;
    position: relative;
    background-color: #00CCFF;
    margin-bottom: 25px;
    opacity: 0.75;
}
.marqueeable {
    overflow-x: hidden;
    width: 450px;
    position: relative;
    opacity: 0.75;
}
.wrapper {
    opacity: 0;
    transition: opacity .75s ease-in-out;
    -moz-transition: opacity .75s ease-in-out;
    -webkit-transition: opacity .75s ease-in-out;
}
.wrapper.active {
    opacity: 1;
    transition: opacity .5s ease-in-out;
    -moz-transition: opacity .5s ease-in-out;
    -webkit-transition: opacity .5s ease-in-out;
}
.wrapper.masked {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
}
.wrapper.fade {
    opacity: 0;
}
.wrapper.mask {
    -webkit-mask-image: -webkit-linear-gradient(left, rgba(0, 0, 0, 0) 10px, rgba(0, 0, 0, 1) 100px);
}
.subwrapper.mask {
    -webkit-mask-image: -webkit-linear-gradient(right, rgba(0, 0, 0, 0) 10px, rgba(0, 0, 0, 1) 100px);
}

JavaScript

var remask = function (left, right) {    
    var $active = $('.wrapper').eq(active),
        leftMask = $active.hasClass('mask'),
        rightMask = $active.find('.subwrapper').hasClass('mask');
    
    console.log('Active', active, $('.wrapper').eq(active));

    if (left != null) {
        leftMask = left;
    }
    if (right != null) {
        rightMask = right;
    }

    active = (active + 1) % 3;
    console.log('Active', active, $('.wrapper').eq(active));
    var $nextActive = $('.wrapper').eq(active),
        $nextActiveSub = $nextActive.find('.subwrapper');
    leftMask ? $nextActive.addClass('mask') : $nextActive.removeClass('mask');
    rightMask ? $nextActiveSub.addClass('mask') : $nextActiveSub.removeClass('mask');

    $active.toggleClass('active');
    $nextActive.toggleClass('active');
};
var scrollHandler = function (evt) {
    $('.measure').text($('.marqueeable .wrapper.active h3').text());

    var marqueeSpeed = 35; // px per s
    var marqueeWidth = $('.measure').outerWidth() - $('.marqueeable').width();
    var marqueeDuration = Math.round(marqueeWidth / marqueeSpeed * 1000);
    
    if (marqueeWidth > 0) {
        $('.marqueeable h3').animate({
            "margin-left": "-=" + marqueeWidth
        }, marqueeDuration, function () {
            $('.marqueeable h3').css('margin-left', 0);
        });
    }
};


var left = false;
var right = false;
var active = 0;

$('#maskLeft').on('click', function (evt) {
    left = !left;
    remask(left);
});
$('#maskRight').on('click', function (evt) {
    right = !right;
    remask(null, right);
});
$('#scroll').on('click', scrollHandler);