两个容器之间的自定义形状线,可更改颜色,例如进度条

时间:2018-12-16 17:24:11

标签: javascript jquery html css

enter image description here

基于上图,我想要实现的目标是:

  1. 一旦容器到达视口的中间,其文本背景将变为黄色。
  2. 在用户向下或向上滚动时,中间箭头也会慢慢用黄色填充,直到用户到达下一个容器的中间视口为止。

现在,我设法使焦点容器将其文本背景更改为黄色,并且已经显示了进度条的形状,但我不知道如何在用户滚动条上相对于其更改为黄色动作(如进度条)。另外,第一个进度条需要从右开始,而第二个进度条则需要从左开始,反之亦然。

P / S:我正在考虑仅使用图像,但是确保像进度条一样将其更改为黄色是不可能的。

$(document).ready(function() {
    var winHeight = $(window).height(),
        topLimit = winHeight * .2;

    $(window).on('scroll', function() {
        $('.parent').each(function() {
            var thisTop = $(this).offset().top - $(window).scrollTop();
            if (thisTop <= topLimit) {
                $(this).addClass('highlight');
            } else {
                $(this).removeClass('highlight');
            }
        });
    });
});
.parent {
  margin-top: 50px;
  height: 250px;
}

.img-col {
  width: 50%;
  height: 250px;
  background-color: green; 
  float:left;
}

.text-col {
  width: 50%;
  height: 250px;
  background-color: blue; 
  float: right;
}

.highlight .text-col {
  background-color: yellow;
}

.middle-line {
  height: 1px;
  width: 100%;
  position: relative;
  background: #000;
  margin-top: 50px;
}

.vertical-right {
  height: 20px;
  width: 1px;
  background: #000;
  position: absolute;
  right: 0;
  bottom: 0;
}

.vertical-left {
  height: 20px;
  width: 1px;
  background: #000;
  position: absolute;
  left: 0;
  top: 0;
}

.vertical-right-bottom {
  height: 20px;
  width: 1px;
  background: #000;
  position: absolute;
  right: 0;
  top: 0;
}

.vertical-left-top {
  height: 20px;
  width: 1px;
  background: #000;
  position: absolute;
  left: 0;
  bottom: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<html>
<body>
<div class="parent">
    <div class="img-col"></div>
    <div class="text-col">Some text here</div>
</div>

<div class="middle-line">
  <div class="vertical-right"></div>
  <div class="vertical-left"></div>
</div>

<div class="parent">
    <div class="text-col" style="float: left;">Some text here</div>
    <div class="img-col" style="float: right;"></div>
</div>

<div class="middle-line">
  <div class="vertical-right-bottom"></div>
  <div class="vertical-left-top"></div>
</div>

<div class="parent">
    <div class="img-col"></div>
    <div class="text-col">Some text here</div>
</div>

<div class="middle-line">
  <div class="vertical-right"></div>
  <div class="vertical-left"></div>
</div>

<div class="parent">
    <div class="text-col" style="float: left;">Some text here</div>
    <div class="img-col" style="float: right;"></div>
</div>

<div class="parent"></div>
</body>
</html>

3 个答案:

答案 0 :(得分:4)

文本背景更改

在到达视口中心时更改文本背景相对简单,可以通过一些经过精心构造的CSS类和一些JavaScript来实现。

主列表中的每个项目都有多个组件,包括几个需要更改背景色的文本框。我们为每个文本框添加一个类-我们称之为.colour-animate。在我们的CSS中,我们添加了transition属性,以使动画平滑淡入淡出。

.colour-animate {
    transition: background-color 0.3s;
}

现在使用JavaScript。

如果主列表中的每个项目都有类名.item,我们可以遍历item的列表,并检查每个项目是否在视口中心上方。这是一个简单的计算:

if ( items[ i ].getBoundingClientRect().top < ( window.innerHeight / 2 ) ) {
    // do stuff
}

如果是的话,我们然后遍历该.colour-animate的{​​{1}}个孩子。对于每个item,我们可以更改背景色。对于视口中心下方的每个.colour-animate,我们重置其.item子级的背景色。这意味着如果我们向上滚动页面,黄色将重置。

完成后台更改的代码:

.colour-animate
var items = document.getElementsByClassName( "item" );

function scroll() {
    for ( var i = 0; i < items.length; i++ ) {
        var colours = items[ i ].getElementsByClassName( "colour-animate" );
        if ( items[ i ].getBoundingClientRect().top < ( window.innerHeight / 2 ) ) {
          for ( var j = 0; j < colours.length; j++ ) {
            colours[ j ].style.backgroundColor = "rgba( 255,208,0,0.7 )";
           }
        } else {
           for ( var j = 0; j < colours.length; j++ ) {
            colours[ j ].style.backgroundColor = "";
           }
        }
    }
}


window.onscroll = function () {
    window.requestAnimationFrame(scroll); 
} 
window.onload = scroll();
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
    background-color: #111;
    padding: 50px;
}
.item {
    background-image: url( https://upload.wikimedia.org/wikipedia/en/f/f7/Leger_railway_crossing.jpg );
    background-size: cover;
    position: relative;
    display: flex;
    justify-content: flex-start;
    margin: 40px auto;
}
.item.right {
    justify-content: flex-end;
}
.item .description {
    width: 33%;
    padding: 30px;
    color: #fff;
    background-color: rgba( 0,0,0,0.7);
}
.item .header {
    font-size: 150%;
    position: absolute;
    top: 0;
    left: auto;
    right: 0;
    padding: 10px 50px;
    color: #fff;
    background-color: #000;
}
.item .header.left {
    left: 0;
    right: auto;
}
.colour-animate {
    transition: background-color 0.3s;
}

动画箭头分隔线

在滚动时动画化箭头图形是一个非常有趣的问题。最好用CSS SVG解决。

首先应将箭头绘制为SVG矢量。您可以在矢量编辑器中执行此操作,或者由于它是非常简单的图形,因此手动进行操作可能会更容易。您的SVG代码如下所示:

<div class="item">
    <div class="header colour-animate">Title 1</div>
    <div class="description colour-animate">
        <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec sit amet ante malesuada, aliquam libero sit amet, varius lectus.</p>
    </div>
</div>

<div class="item right">
    <div class="header colour-animate left">Title 2</div>
    <div class="description colour-animate">
        <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec sit amet ante malesuada, aliquam libero sit amet, varius lectus.</p>
    </div>
</div>

<div class="item">
    <div class="header colour-animate">Title 3</div>
    <div class="description colour-animate">
        <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec sit amet ante malesuada, aliquam libero sit amet, varius lectus.</p>
    </div>
</div>

<div class="item right">
    <div class="header colour-animate left">Title 4</div>
    <div class="description colour-animate">
        <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec sit amet ante malesuada, aliquam libero sit amet, varius lectus.</p>
    </div>
</div>

<div class="item">
    <div class="header colour-animate">Title 5</div>
    <div class="description colour-animate">
        <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec sit amet ante malesuada, aliquam libero sit amet, varius lectus.</p>
    </div>
</div>

非常重要的是,您只能如上所述使用路径绘制它。

现在要在滚动时为黄色设置动画,您需要绘制与第一个相同的第二条路径,只是它是黄色的。并为其添加新的类名-假设您使用<svg width="100%" height="100px" viewBox="0 0 1000 100" preserveAspectRatio="none"> <path fill="none" stroke="#ffffff" stroke-width="2" d="M01000 0 L1000 50 L500 50 L 510 30 L510 70 L500 50 L 0 50 L0 100" /> </svg> 。您完整的SVG可能如下所示:

.scroll-animate

CSS Tricks上有一篇精彩的小文章,介绍了如何为SVG路径设置动画。基本上,您使用<svg width="100%" height="100px" viewBox="0 0 1000 100" preserveAspectRatio="none"> <path fill="none" stroke="#ffffff" stroke-width="2" d="M01000 0 L1000 50 L500 50 L 510 30 L510 70 L500 50 L 0 50 L0 100" /> <path fill="none" stroke="#ffd000" stroke-width="2" d="M01000 0 L1000 50 L500 50 L 510 30 L510 70 L500 50 L 0 50 L0 100" class="scroll-animate" /> </svg> 找到路径的长度,并使.getTotalLength()路径的笔划破折号长度等于该长度。这意味着您可以通过将路径的笔触偏移量从该长度设置为0来动画化从头到尾的路径。将其附加到滚动中,我们使笔触偏移量等于路径的长度乘以路径在视口中的滚动位置,除以视口高度。

.scroll-animate

当您向下滚动时,它不仅可以使黄色箭头动画化,而且在向上滚动时可以使黄色箭头反转。

结果

完整的代码(或者您可以查看其中的codepen):

var paths = document.getElementsByClassName( "scroll-animate" ),
    length = paths[ 0 ].getTotalLength();

function scroll() {
    for ( var i = 0; i < paths.length; i++ ) {
        paths[ i ].style.strokeDashoffset = length * ( paths[ i ].getBoundingClientRect().top / window.innerHeight );
    }
}

window.onscroll = function () {
    window.requestAnimationFrame(scroll); 
}
var items = document.getElementsByClassName( "item" ),
    paths = document.getElementsByClassName( "scroll-animate" ),
    length = paths[ 0 ].getTotalLength();

for ( var i = 0; i < paths.length; i++ ) {
    paths[ i ].style.strokeDasharray = length;
    paths[ i ].style.strokeDashoffset = length;
}

function scroll() {
    for ( var i = 0; i < items.length; i++ ) {
        var colours = items[ i ].getElementsByClassName( "colour-animate" );
        if ( items[ i ].getBoundingClientRect().top < ( window.innerHeight / 2 ) ) {
          for ( var j = 0; j < colours.length; j++ ) {
            colours[ j ].style.backgroundColor = "rgba( 255,208,0,0.7 )";
           }
        } else {
           for ( var j = 0; j < colours.length; j++ ) {
            colours[ j ].style.backgroundColor = "";
           }
        }
    }
    
    for ( var i = 0; i < paths.length; i++ ) {
        paths[ i ].style.strokeDashoffset = length * ( paths[ i ].getBoundingClientRect().top / window.innerHeight );
    }
}


window.onscroll = function () {
    window.requestAnimationFrame(scroll); 
} 
window.onload = scroll();
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
    background-color: #111;
    padding: 50px;
}
.item {
    background-image: url( https://upload.wikimedia.org/wikipedia/en/f/f7/Leger_railway_crossing.jpg );
    background-size: cover;
    position: relative;
    display: flex;
    justify-content: flex-start;
    margin: 10px auto;
}
.item.right {
    justify-content: flex-end;
}
.item .description {
    width: 33%;
    padding: 30px;
    color: #fff;
    background-color: rgba( 0,0,0,0.7);
}
.item .header {
    font-size: 150%;
    position: absolute;
    top: 0;
    left: auto;
    right: 0;
    padding: 10px 50px;
    color: #fff;
    background-color: #000;
}
.item .header.left {
    left: 0;
    right: auto;
}
.colour-animate {
    transition: background-color 0.3s;
}

答案 1 :(得分:1)

可能有很多方法可以做到这一点。具有透明部分的图像。边框颜色或简单边距的智能CSS用法。我不确定最好的方法是什么,因为我们不使用实际的代码,但现在更多的是模拟。

请考虑以下内容。

$(function() {
  var winHeight = $(window).height(),
    topLimit = winHeight * .2;

  $(window).on('scroll', function() {
    $('.parent').each(function() {
      var thisTop = $(this).offset().top - $(window).scrollTop();
      if (thisTop <= topLimit) {
        $(this).addClass('highlight');
      } else {
        $(this).removeClass('highlight');
      }
    });
    $(".line-wrap").each(function() {
      var thisTop = $(this).offset().top - $(window).scrollTop();
      if (thisTop <= topLimit) {
        if ($(".mid-line", this).hasClass("top-right")) {
          $(this).css("background-image", "linear-gradient(to right, rgba(255,255,0,0), rgba(255,255,0,1))");
        } else {
          $(this).css("background-image", "linear-gradient(to left, rgba(255,255,0,0), rgba(255,255,0,1))");
        }
      } else {
        $(this).css("background-image", "");
      }
    });
  });
});
.content {
  padding: 0;
  margin: 0;
  background: #000;
}

.parent {
  margin-top: 50px;
  height: 250px;
  background-color: black;
}

.img-col {
  width: 50%;
  height: 250px;
  background-color: black;
  float: left;
}

.text-col {
  width: 50%;
  height: 250px;
  background-color: blue;
  float: right;
}

.highlight .text-col {
  background-color: yellow;
}

.line-wrap {
  /* Line Color */
  background: #FFF;
}

.mid-line {
  /* Spacing and Borders */
  height: 19px;
  width: calc(100% - 1px);
  background: black;
  border: 0;
}

.top-right {
  /* Verticals Sides */
  margin-top: 50px;
  margin-right: 1px;
  margin-bottom: 1px;
}

.top-left {
  /* Verticals Sides */
  margin-top: 50px;
  margin-left: 1px;
  margin-bottom: 1px;
}

.bottom-left {
  margin-left: 1px;
}

.bottom-right {
  margin-right: 1px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div class="content">
  <div class="parent">
    <div class="img-col"></div>
    <div class="text-col">Some text here</div>
  </div>

  <div class="line-wrap">
    <div class="mid-line top-right">
    </div>
    <div class="mid-line bottom-left">
    </div>
  </div>

  <div class="parent">
    <div class="text-col" style="float: left;">Some text here</div>
    <div class="img-col" style="float: right;"></div>
  </div>

  <div class="line-wrap">
    <div class="mid-line top-left">
    </div>
    <div class="mid-line bottom-right">
    </div>
  </div>

  <div class="parent">
    <div class="img-col"></div>
    <div class="text-col">Some text here</div>
  </div>

  <div class="line-wrap">
    <div class="mid-line top-right">
    </div>
    <div class="mid-line bottom-left">
    </div>
  </div>

  <div class="parent">
    <div class="text-col" style="float: left;">Some text here</div>
    <div class="img-col" style="float: right;"></div>
  </div>

  <div class="parent"></div>
</div>

使用相同的进度代码,您只需为不同的背景着色。我认为有些CSS风格可能很好,因此透明渐变背景。如果您想执行更多步骤并更改或增大渐变,则只需要进一步滚动即可。

希望有帮助。

答案 2 :(得分:1)

$(document).ready(function() {
    var winHeight = $(window).height(),
        topLimit = winHeight * .2;

    $(window).on('scroll', function() {
        $('.parent').each(function() {
            var thisTop = $(this).offset().top - $(window).scrollTop();
            if (thisTop <= topLimit) {
                $(this).addClass('highlight');
                $(this).next('.middle-line').addClass('is-active');
            } else {
                $(this).removeClass('highlight');
                $(this).next('.middle-line').removeClass('is-active');
            }
        });
    });
});
.parent {
  margin-top: 50px;
  height: 250px;
}

.img-col {
  width: 50%;
  height: 250px;
  background-color: green; 
  float:left;
}

.text-col {
  width: 50%;
  height: 250px;
  background-color: blue; 
  float: right;
}

.highlight .text-col {
  background-color: yellow;
}

.middle-line.is-active::before,
.middle-line.is-active::after {
  width: 50%;
}

.middle-line.is-active .vertical-bottom,
.middle-line.is-active .vertical-top {
  height: 20px;
}

.middle-line.is-active::before {
  transition: width 0.2s 0.2s ease-in;
}

.middle-line.is-active::after {
  transition: width 0.2s 0.4s ease-out;
}

.middle-line.is-active .vertical-bottom {
  transition: height 0.2s 0.6s ease-out;
}

.middle-line.is-active .vertical-top {
  transition: height 0.2s ease-in;
}

.middle-line {
  height: 1px;
  width: 100%;
  position: relative;
  margin-top: 50px;
}

.middle-line::before,
.middle-line::after {
  content: '';
  position: absolute;
  background: #000;
  height: 100%;
  width: 0;
}

.middle-line::before {
  transition: width 0.2s 0.4s ease-out;
  right: 0;
}

.middle-line::after {
  transition: width 0.2s 0.2s ease-in;

  right: 50%;
}

.middle-line.alternate::before {
  left: 0;
}

.middle-line.alternate::after {
  left: 50%;
}

.middle-line.alternate .vertical-top {
  left: 0;
  right: auto;
}

.middle-line.alternate .vertical-bottom {
  left: auto;
  right: 0;
}

.vertical-top {
  transition: height 0.2s 0.6s ease-out;
  height: 0;
  width: 1px;
  background: #000;
  position: absolute;
  top: -20px;
  right: 0;
  bottom: 0;
}

.vertical-bottom {
  transition: height 0.2s ease-in;
  height: 0;
  width: 1px;
  background: #000;
  position: absolute;
  left: 0;
  top: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<html>
<body>
<div class="parent">
    <div class="img-col"></div>
    <div class="text-col">Some text here</div>
</div>

<div class="middle-line">
  <div class="vertical-top"></div>
  <div class="vertical-bottom"></div>
</div>

<div class="parent">
    <div class="text-col" style="float: left;">Some text here</div>
    <div class="img-col" style="float: right;"></div>
</div>

<div class="middle-line alternate">
  <div class="vertical-top"></div>
  <div class="vertical-bottom"></div>
</div>

<div class="parent">
    <div class="img-col"></div>
    <div class="text-col">Some text here</div>
</div>

<div class="middle-line">
  <div class="vertical-top"></div>
  <div class="vertical-bottom"></div>
</div>

<div class="parent">
    <div class="text-col" style="float: left;">Some text here</div>
    <div class="img-col" style="float: right;"></div>
</div>

<div class="middle-line alternate">
    <div class="vertical-top"></div>
    <div class="vertical-bottom"></div>
</div>

<div class="parent"></div>
</body>
</html>

我已经编辑了您的标记,并通过CSS来管理动画。