将背景图像(颜色)从左向右更改,就像连续运动一样



右上角的切换开关按钮可从亮模式切换到暗模式,反之亦然。背景是一张放大的图像。

目前,它从转移

切换到暗模式时从左到右
  • 切换到灯光模式时从右向左
  • 但我希望它自己朝一个方向移动。比如,假设它处于亮模式,当我将其切换到暗模式时,背景图像会像预期的那样向右移动(左>右(,然后当我将它切换到亮模式时,我希望背景图像再次从左向右移动(左>右(。

    有点像一个连续的循环,但有一个切换按钮。

    我有什么办法做到这一点吗?

    我想它可能适用于不确定的关键帧和动画。但是有没有一种方法可以在JS中做到这一点而不需要关键帧?

    不要介意下面的代码,因为我不得不从我的react项目中截取它,所以可能不需要一些CSS属性。

    let Dark = false
    const DarkOrLight = () => {
    const container = document.getElementsByClassName('Login-container')[0]
    if (!Dark) {
    container.style.backgroundPosition = 'right'
    } else {
    container.style.backgroundPosition = 'left'
    }
    Dark = !Dark
    }
    .toggle-container {
    position: fixed;
    top: 5px;
    right: 5%;
    }
    .toggle {
    appearance: none;
    width: 50px;
    height: 30px;
    background-image: linear-gradient(120deg, #383030 0%, #22282e 100%);
    cursor: pointer;
    border-radius: 20px;
    }
    .toggle:focus {
    outline: 0;
    }
    .toggle::after {
    content: '';
    background-image: linear-gradient(120deg, rgb(182, 244, 146), rgb(51, 139, 147));
    position: absolute;
    top: 5px;
    left: 5px;
    width: 25px;
    height: 25px;
    border-radius: 50%;
    transition: all 1s ease;
    }
    .toggle:checked {
    background-color: #b6f492;
    background-image: linear-gradient(120deg, #b6f492, rgb(51, 139, 147));
    }
    .toggle:checked::after {
    transform: translateX(23px);
    background-image: linear-gradient(120deg, #383030 0%, #22282e 100%);
    }
    .Login-container {
    position: relative;
    background-image: linear-gradient(120deg, #b6f492, #338b93, #383030, #22282e);
    background-size: 400%;
    background-position: left;
    width: 100%;
    height: 100vh;
    display: flex;
    justify-content: end;
    transition: all 1s ease;
    font-family: Merriweather;
    }
    <div class="Login-container">
    <div class="toggle-container">
    <input class="toggle" type="checkbox" onClick=DarkOrLight()></input>
    </div>
    </div>

    修复颜色停止

    • 您的背景大小为400%
    • 但您只使用4颜色停止(而不是5(

    问题是:通过简单地从左到右设置动画,您当前的代码就会发生这种情况:

    |left                          right|       bg-position left-to-right
    |#1         |#2         |#3         |#4     4 colors-stops 
    |0%      |100%    |200%    |300%    |400%   bg-size
    | light  |     (anim)      |  dark  |       mode
    |░░░░░░░░|▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒|▓▓▓▓▓▓▓▓|          
    

    你知道100%的颜色是什么吗没有
    你知道300%的确切颜色是什么吗没有
    是否看到不一致?颜色停止被关闭一个

    上述问题的一些可能解决方案:

    • 再添加一个颜色停止-或
    • 将宽度减小到300%-或
    • 使用CSSlinear-gradient()停止在所需的%位置

    建议

    为具有所需背景的子元素制作动画:

    • 宽度400%
    • 5个颜色停止,其中最后一个与第一个匹配
    |0%               |200%             |400%   animate left by -%
    |#1      |#2      |#3      |#4      |#1     5 colors-stops 
    |0%      |100%    |200%    |300%    |400%   width
    | light  | (anim) |  dark  | (anim) |       mode 
    |░░░░░░░░|▒▒▒▒▒▒▒▒|▓▓▓▓▓▓▓▓|▒▒▒▒▒▒▒▒|░░...
    

    正如您所看到的,在400%时,我们又回到了颜色#1-非常适合循环逻辑!并且通过";向左动画化-%">我的意思是动画GPU加速的transform: translateX()属性值。

    但是等等!如果我想设置背景位置的动画而不是Element子对象,该怎么办
    不是background-position: 100% 0吗;与background-position: right 0完全相同
    很遗憾,是的。100%不会将其设置在其初始状态(0%(。如果我们将子元素设置为-200%left位置的步长,则上表将是有意义的
    有关此(背景位置(问题的深入解释,请阅读:在线性梯度上使用具有背景位置的百分比值。

    解决方案

    你可以:

    1. 使用设置为4×父元素(width: 400%;(宽度的子元素(背景(。然后在JS中,将其向左移动-200%,在transitionend事件中,您可以使用Modulo(Reminder(运算符%将其位置重置为0(如果返回到Light模式(。

    2. 否则,移动背景的数学运算实际上是三分之一:

    公式:100 / 3 * totModes * counter
    下表中为bgX = 100 / 3 * 2 * (1) = 66.66666666666667等…

    |0%               |66.66%           |133.33% bg-position by %
    |#1      |#2      |#3      |#4      |#1      5 colors-stops 
    |0%      |100%    |200%    |300%    |400%    bg-size
    | light  | (anim) |  dark  | (anim) |        mode 
    |░░░░░░░░|▒▒▒▒▒▒▒▒|▓▓▓▓▓▓▓▓|▒▒▒▒▒▒▒▒|░░...
    

    示例:

    // DOM utility functions:
    const find = (selector, parent) => (parent || document).querySelector(selector);
    
    // Task:
    const elContainer = find("#login");
    let c = 0; // position counter
    const toggleDarkMode = () => {
    c += 1;
    const bgX = 100 / 3 * 2 * c;
    console.log(bgX)
    elContainer.style.backgroundPosition = `${bgX}%`;
    };
    find("#toggleMode").addEventListener("input", toggleDarkMode);
    * {
    margin: 0;
    }
    .toggle-container {
    position: fixed;
    z-index: 1000;
    top: 20px;
    left: 20px;
    }
    .Login-container {
    background-image: linear-gradient(to right,
    #fff,
    red,
    #000,
    blue,
    #fff /*back to home*/
    );
    background-size: 400%;
    background-position: 0% 0;
    background-repeat: repeat-x;
    height: 100vh;
    transition: background 1s ease;
    }
    <label class="toggle-container">
    DARK MODE: <input id="toggleMode" class="toggle" type="checkbox">
    </label>
    <div id="login" class="Login-container"></div>

    对角线坡度

    正如您所看到的,只有当背景图像的linear-gradient()设置为90deg270degto rightto left时,以上操作才会起作用。

    对于对角线渐变任何其他度数,您可以复制值并移动一半。但在这种情况下,背景图像应该以负偏移进行定位。再说一遍,我认为animationend最终会发挥作用。

    不确定以上是否有帮助,但希望它能澄清一些想法,帮助你找到一个可行的解决方案。