【问题标题】:Migrating from clip to clip-path to use percent values从剪辑迁移到剪辑路径以使用百分比值
【发布时间】:2021-04-20 06:25:59
【问题描述】:

我目前正在使用scss 为“移动”边框编写动画。动画主要基于clip

$box-size-w: 80px;
$box-size-h: 50px;

    @keyframes clipMe {
        0%, 100% {
            clip: rect(0, $box-size-w, $path-width, 0);
        }
        25% {
            clip: rect(0, $path-width, $box-size-h, 0);
        }
        50% {
            clip: rect(resolveCalc($box-size-h, $path-width), $box-size-w, $box-size-h, 0);
        }
        75% {
            clip: rect(0, $box-size-w, $box-size-h, resolveCalc($box-size-w, $path-width));
        }
    }

起初动画只适用于方形块(w === h),然后我对其进行了调整,以便可以单独指定 withheight

然后需要再次调整脚本,使其接受percent 值,而不仅仅是pixels。我做了一些研究,发现了这篇文章Clipping and Masking in CSS。从文章看来:

  • 旧语法:clip: rect(10px, 20px, 30px, 40px);
  • 新语法:clip-path: inset(10px 20px 30px 40px);

我进行了更改,似乎以下应该可以工作:

$box-size-w: 100%;
$box-size-h: 100%;

    @keyframes clipMe {
        0%, 100% {
            clip-path: inset(0 $box-size-w $path-width 0);
        }
        25% {
            clip-path: inset(0 $path-width $box-size-h 0);
        }
        50% {
            clip-path: inset(resolveCalc($box-size-h, $path-width) $box-size-w $box-size-h 0);
        }
        75% {
            clip-path: inset(0 $box-size-w $box-size-h resolveCalc($box-size-w, $path-width));
        }
    }

但是在此更改后动画不起作用。我试着玩这个,但结果不是很好,似乎新的 api 也改变了它的工作方式。如何修改 keyframes 使其与 % 值一起使用?

完整的scss代码:

    $anime-time: 8s;

    $box-size-w: 80px;
    $box-size-h: 50px;
    $path-width: 1px;

    $main-color: #000;

    @function resolveCalc($s, $f) {
        @return calc(#{$s} - #{$f});
    }

    %full-fill {
        position: absolute;
        top: 0;
        bottom: 0;
        left: 0;
        right: 0;
    }

    .box {
        width: $box-size-w;
        height: $box-size-h;
        margin: auto;
        color: $main-color;
        box-shadow: inset 0 0 0 1px rgba($main-color, .1);
        position:relative;

        &::before,
        &::after {
            @extend %full-fill;
            content: '';
            z-index: -1;
            margin:0;
            box-shadow: inset 0 0 0 $path-width;
        }

        &.active {
            &::before {
                animation: clipMe $anime-time linear infinite;
                animation-delay: $anime-time * -.5;
            }
            &::after {
                animation: clipMe $anime-time linear infinite;
            }

            // for debug
            &:hover {
                &::after,
                &::before {
                    background-color: rgba(#fff, .3);
                }
            }
        }

    }

    @keyframes clipMe {
        0%, 100% {
            clip: rect(0, $box-size-w, $path-width, 0);
        }
        25% {
            clip: rect(0, $path-width, $box-size-h, 0);
        }
        50% {
            clip: rect(resolveCalc($box-size-h, $path-width), $box-size-w, $box-size-h, 0);
        }
        75% {
            clip: rect(0, $box-size-w, $box-size-h, resolveCalc($box-size-w, $path-width));
        }
    }

    html,
    body {
        height: 100%;
    }

    body {
        position: relative;
    }

    .wrap {
        width:50%;
        height:25%;
        margin:50px auto;
    }

    *,
    *::before,
    *::after {
        box-sizing: border-box;
    }

工作(编译为 css)演示:

.box::before, .box::after {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
}

.box {
  width: 80px;
  height: 50px;
  margin: auto;
  color: #000;
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.1);
  position: relative;
}

.box::before, .box::after {
  content: '';
  z-index: -1;
  margin: 0;
  box-shadow: inset 0 0 0 1px;
}

.box.active::before {
  animation: clipMe 8s linear infinite;
  animation-delay: -4s;
}

.box.active::after {
  animation: clipMe 8s linear infinite;
}

.box.active:hover::after, .box.active:hover::before {
  background-color: rgba(255, 255, 255, 0.3);
}

@keyframes clipMe {
  0%, 100% {
    clip: rect(0, 80px, 1px, 0);
  }
  25% {
    clip: rect(0, 1px, 50px, 0);
  }
  50% {
    clip: rect(calc(50px - 1px), 80px, 50px, 0);
  }
  75% {
    clip: rect(0, 80px, 50px, calc(80px - 1px));
  }
}

html,
body {
  height: 100%;
}

body {
  position: relative;
}

.wrap {
  width: 50%;
  height: 25%;
  margin: 10px auto;
}

*,
*::before,
*::after {
  box-sizing: border-box;
}
<div class="wrap">
    <div class="box active"></div>
</div>

【问题讨论】:

    标签: css sass css-animations clip-path


    【解决方案1】:

    我会为此使用掩码

    .box {
      width: 40%;
      height: 100px;
      margin: 10px auto;
      color: #000;
      box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.1);
      position: relative;
    }
    
    .box::before, .box::after {
      content: '';
      position: absolute;
      top: 0;
      bottom: 0;
      left: 0;
      right: 0;
      z-index: -1;
      box-shadow: inset 0 0 0 1px;
      -webkit-mask:linear-gradient(#fff 0 0) no-repeat;
      animation: 
        clipMe 2s linear infinite alternate,
        pos    8s linear infinite;
    }
    
    .box::before {
      animation-delay: -4s;
    }
    
    
    @keyframes clipMe {
      0% {
        -webkit-mask-size:100% 2px;
      }
      100% {
        -webkit-mask-size:2px 100%;
      }
    }
    
    @keyframes pos {
      0%,24.9% {
        -webkit-mask-position:top left;
      }
      25%,49.9% {
        -webkit-mask-position:bottom left;
      }
      50%,74.9% {
        -webkit-mask-position:bottom right;
      }
      75%,100% {
        -webkit-mask-position:top right;
      }
    }
    <div class="box"></div>
    
    <div class="box" style="width:50%;height:150px;"></div>

    使用clip-path,您可以执行以下操作:

    .box {
      width: 40%;
      height: 100px;
      margin: 10px auto;
      color: #000;
      box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.1);
      position: relative;
    }
    
    .box::before,
    .box::after {
      content: '';
      position: absolute;
      top: 0;
      bottom: 0;
      left: 0;
      right: 0;
      z-index: -1;
      box-shadow: inset 0 0 0 1px;
      animation: clipMe 4s linear infinite;
    }
    
    .box::before {
      animation-delay: -2s;
    }
    
    @keyframes clipMe {
      0%, 100% {
        clip-path: inset(0 0 calc(100% - 1px) 0);
      }
      25% {
        clip-path: inset(0 calc(100% - 1px) 0 0);
      }
      50% {
        clip-path: inset(calc(100% - 1px) 0 0 0);
      }
      75% {
        clip-path: inset(0 0 0 calc(100% - 1px));
      }
    }
    <div class="box"></div>
    
    <div class="box" style="width:50%;height:150px;"></div>

    【讨论】:

    • 这是一份扎实的工作,正是我想要的。还有一件事,你能告诉我哪种方法是领先的(如果有的话),例如从浏览器支持或性能的角度来看?
    • @Mevia clip-path 有更好的支持,但掩码很快就会适用于所有现代浏览器。对于性能我不知道,但我认为它们都是等效的(您可能需要运行一些性能测试并查看两种情况下 CPU 的使用情况)
    • 完美,谢谢。目前我将使用剪辑路径解决方案,但对于任何正在寻找类似问题的人来说,这两者都很好。
    猜你喜欢
    • 2019-05-13
    • 1970-01-01
    • 2016-09-18
    • 1970-01-01
    • 2019-06-07
    • 2019-09-25
    • 2017-10-24
    • 1970-01-01
    相关资源
    最近更新 更多