从剪辑迁移到剪辑路径以使用百分比值
Migrating from clip to clip-path to use percent values
我目前正在使用 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),然后我调整它以便可以单独指定 with
和 height
.
然后需要再次调整脚本,使其接受 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>
我会为此使用面具
.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>
我目前正在使用 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),然后我调整它以便可以单独指定 with
和 height
.
然后需要再次调整脚本,使其接受 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>
我会为此使用面具
.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>