如何根据 media-query 个断点被命中来实现 CSS 动画?

How to implement CSS animations based on media-query breakpoints being hit?

作为使我们的网络系统响应移动设备的一部分,我使用 CSS 媒体查询在 header 栏和汉堡菜单之间交替。

现在我认为如果它在桌面用户调整浏览器大小时 window 超出媒体查询定义的范围时在两种布局之间进行动画处理,那将是一个不错的噱头。作为一个 proof-of-concept 测试,我一直在试验我们的大徽标和小徽标之间的 t运行 位置。

我的 animations.scss 文件包含这两个动画:

@mixin ToSmallLogo() {
    background-image: url('../../../../PageAssets/fissmall.png');
    width: 7%;
    animation-iteration-count: 1;
    animation-timing-function: ease-in;
    animation-duration: 1s;
    animation-name: SwapToSmallLogo;

    @keyframes SwapToSmallLogo {
        0% {
            width: 100%;
            background-image: url('../../../PageAssets/Fis.png');
        }

        100% {
            background-image: url('../../../../PageAssets/fissmall.png');
            width: 7%;
        }
    }
}

@mixin SwapToBigLogo() {
    width: 100%;
    background-image: url('../../../PageAssets/Fis.png');
    animation-iteration-count: 1;
    animation-timing-function: ease-in;
    animation-duration: 1s;
    animation-name: SwapToBigLogo;

    @keyframes SwapToBigLogo {
        0% {
            background-image: url('../../../../PageAssets/fissmall.png');
            width: 7%;
            width: 100%;
            background-image: url('../../../PageAssets/Fis.png');
        }

        100% {
            width: 100%;
            background-image: url('../../../PageAssets/Fis.png');
        }
    }
}

然后我有一个专门用于媒体查询的 SCSS 文件,包含:

@import '../../Variables/Sizes.scss';
@import '../Animations/animations.scss';

@media screen and (max-width: $bigToSmallFISLogo) {
    #franklin {
        @include ToSmallLogo();
    }
}

@media screen and (min-width: $bigToSmallFISLogo){
    #franklin{
        @include SwapToBigLogo();
    }
}

而应用媒体查询之前的CSS是这样的:

#franklin {
    display: block;
    width: 100%;
    background-image: url('../../../PageAssets/Fis.png');
    background-repeat: no-repeat;
    background-size: 100%;
    height: 72px;
}

我的问题是,虽然将屏幕缩小到超过定义的尺寸效果很好,但返回时只会捕捉到没有动画的较大图像。我认为罪魁祸首是我在应用媒体查询之前在 CSS 中定义了图像,所以我删除了那部分;但这只是导致没有图像。

然后在输入这个问题时我想到了使用媒体查询来确定动画的方向,如下所示:

@mixin SwapLogo() {
/*    background-image: url('../../../../PageAssets/fissmall.png');
    width: 7%;*/
    animation-iteration-count: 1;
    animation-timing-function: ease-in;
    animation-duration: 1s;
    animation-name: SwapLogo;

    @media screen and (max-width: $bigToSmallFISLogo) {
        animation-direction: normal;
        background-image: url('../../../../PageAssets/fissmall.png');
        width: 7%;
    }

    @media screen and (min-width: $bigToSmallFISLogo) {
        animation-direction: reverse;
        width: 100%;
        background-image: url('../../../PageAssets/Fis.png');
    }

    @keyframes SwapLogo {
        0% {
            width: 100%;
            background-image: url('../../../PageAssets/Fis.png');
        }

        100% {
            background-image: url('../../../../PageAssets/fissmall.png');
            width: 7%;
        }
    }
}

这导致动画在页面加载时 运行,但在调整大小时没有。

有什么方法可以满足我的要求吗?

选项 1 包含一些错误 css

您已在 SwapToBigLogo

上将起点设置为 width: 100%;
    @keyframes SwapToBigLogo {
        0% {
            background-image: url('../../../../PageAssets/fissmall.png');
            width: 7%;
            width: 100%; <---- culprit
            background-image: url('../../../PageAssets/Fis.png');
        }

本质上,您是从 width: 100%width:100% 的动画。如果您删除该行,它可能会起作用。

选项 2 棘手的反转

反转动画时,不会重置动画的迭代次数和进度。
IE 如果你 'reverse' 一个动画在 100% 完成。它只会应用 'reverse' 状态的 100% 完成。 不是从 0% 反转开始并动画到 100% 反转

如果您想规避

,请参阅我对此的回答

替代方案,改用过渡

如果您不需要复杂的动画,只想从一种状态平滑过渡到另一种状态。
我更愿意使用 css 转换。

#franklin {
    display: block;
    width: 100%;
    background-image: url('../../../PageAssets/Fis.png');
    background-repeat: no-repeat;
    background-size: 100%;
    height: 72px;
    transition: width 2s ease-in; // <--- this will animate when the media query kicks in.
}


@media screen and (max-width: $bigToSmallFISLogo) {
    #franklin {
       background-image: url('../../../../PageAssets/fissmall.png');
       width: 7%; 
    }
}

@media screen and (min-width: $bigToSmallFISLogo){
    #franklin{
         width: 100%;
         background-image: url('../../../PageAssets/Fis.png');
    }
}

奖金

您可以将过渡应用于 * 选择器。 (对于生产级网站,我不建议这样做,但玩起来很有趣。)当您的媒体查询发生变化时,它将使一切顺利过渡 widths/layouts.

* {
  transition: all 2s;
}

body {
  background-color: red;
  color: black;
  font-size: 30px;
}

.logo {
  width: 200px;
  border: 5px solid black;
  border-radius: 30px;
  padding:20px;
}


/* On screens that are 992px wide or less, the background color is blue */

@media screen and (max-width: 630px) {
  body {
    background-color: blue;
    color: white;
    font-size: 20px;
  }
  .logo {
    width: 100px;
    border: 3px solid orange;
    border-radius: 10px;
    padding:10px;
  }
}


/* On screens that are 600px wide or less, the background color is olive */

@media screen and (max-width: 400px) {
  body {
    background-color: lime;
    color: white;
    font-size: 12px;
  }
  .logo {
    width: 50px;
    border: 1px solid indigo;
    border-radius: 5px;
    padding:2px;
  }
}
<h1>Resize window</h1>
<p>
  <img class="logo" src="http://placekitten.com/200/300" alt="logo">
</p>

经过大量实验,我终于猜到了。本质上,正如拉斯指出的那样,我忘记删除了一些位;但是我最终得到的解决方案(看起来更平滑一些,因为它将一个图像淡入另一个图像)是将基础 CSS 设置为:

#franklin {
    display: block;
    background-repeat: no-repeat;
    background-size: 100%;
    height: 72px;
}

然后 mixin 应用动画如下:

@mixin SwapLogo($img, $width, $startIMG, $startWidth, $animationName) {
    animation-iteration-count: 1;
    animation-timing-function: ease-in;
    animation-duration: 1s;
    animation-name: $animationName;
    background-image: $img;
    width: $width;

    @keyframes #{$animationName} {
        0% {
            width: $startWidth;
            background-image: $startIMG;
        }

        100% {
            background-image: $img;
            width: $width;
        }
    }
}

媒体查询为:

@media screen and (max-width: calc($bigToSmallFISLogo + 10px)) { //This overlap of 10px basically allows for the animation to take effect as the other animation is removed. 
    #franklin {
        @include SwapLogo(url('../../../../PageAssets/fissmall.png'), 7%, url('../../../../PageAssets/Fis.png'), 100%, LogoGoSmall);
        margin-top: 13px;
    }
}

@media screen and (min-width: $bigToSmallFISLogo) {
    #franklin {
        @include SwapLogo(url('../../../../PageAssets/Fis.png'), 100%, url('../../../../PageAssets/fissmall.png'), 7%, LogoGoBig);
    }
}

@media screen and (max-width: $minSizeForDesktopMenu) and (min-width: $bigToSmallFISLogo) {
    #franklin {
        margin-top: 26px;
    }
}

@media screen and (min-width: $minSizeForDesktopMenu) {
    #franklin {
        margin-top: 13px;
    }
}