顺时针旋转180然后360

时间:2018-09-05 23:47:12

标签: css css3 css-animations

我有一个齿轮图标,我想在激活时顺时针旋转180度(class =“ cards__cog cards__cog-active”),然后再顺时针旋转180deg以返回其停用状态(class =“ cards__cog cards__cog-inactive”)。我正在用React进行此操作,以应对单击齿轮时的状态变化。

以下方法可行,但我的问题是:

1)它会在页面加载时进行动画处理(这是有道理的,因为它具有cards__cog-inactive类,但有什么选择呢?)。

2)这很丑陋,必须有一种更简单的方法。

谢谢

.cards {
    &__cog {
            position: absolute;
            right: 20px;
            top: 20px;
            width: 10vh;
            cursor: pointer;

            &-active {
                 animation: rotate180 1s ease;
                animation-fill-mode: forwards;
            }
            &-inactive {
                animation: rotate180to359to0 1s ease;
                animation-fill-mode: forwards;
            }
       }
}


    @keyframes rotate180 {
      0% {
        transform: rotate(0deg);
      }
      100% {
        transform: rotate(180deg);
      }
    }

    @keyframes rotate180to359to0 {
      0% {
        transform: rotate(180deg);
      }
      99% {
        transform: rotate(359deg);
      }
      100% {
        transform: rotate(0deg);
      }
    }

5 个答案:

答案 0 :(得分:7)

您可以对其中一种动作使用过渡。但是两者都不一样,因为其中之一会倒退。

由于问题一,您不能将动画用于初始状态。

这使我们处于非活动状态,处于360度,因此它可以以正确的方式从180过渡到360,并且动画从0变为180,以便从非活动状态变为活动状态

function change () {

	var elem = document.getElementById("test");
	elem.classList.toggle('active');
}
.test {
  width: 200px;
  height: 100px;
  border: solid 4px red;
  margin: 20px;
  transform: rotate(360deg);
  transition: transform 1s;
}

.active {
  animation: activate 1s;
  transform: rotate(180deg);
}

@keyframes activate {
  from {transform: rotate(0deg);}
  to {transform: rotate(180deg);}
}
<div class="test" id="test">TEST</div>
<button onclick="change();">change</button>

答案 1 :(得分:5)

如果图标是对称的,则可以考虑2个元素并进行这样的过渡。

var e = document.querySelector('.box');
e.addEventListener('click',function() {
  e.classList.toggle('active');
})
.box {
  display:inline-block;
  margin:20px;
  transition:0s .5s;
}
.box > i {
  transition:.5s;
  color:red;
  display:block;
}
.box.active {
  transform:scaleX(-1);
}

.box.active i{
  transform:rotate(180deg);
}
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.3.1/css/all.css">
<div class="box">
  <i class="fas fa-cog fa-7x"></i>
</div>

答案 2 :(得分:5)

您已经提到您正在使用React。考虑到这一点,您可以尝试将旋转逻辑从CSS移到组件本身。这样做,您将不需要其他类,keyframes等。在这种情况下,仅需要transitiontransform组合。

class Cog extends React.Component {
  state = {
    isActive: false,
    togglesCount: 0
  }
  
  get rotationValue () {
    return `${this.state.togglesCount * 180}deg`
  }
  
  get cogStyle () {
    return {
      transition: 'transform 1s',
      transform: `rotateZ(${this.rotationValue})`
    }
  }
  
  toggle = () => {
    this.setState(s => ({ 
      isActive: !s.isActive,
      togglesCount: ++s.togglesCount
    }))
  }
  
  render() {
    return (
      <button onClick={this.toggle}>
        <i className="fas fa-cog fa-3x" style={this.cogStyle}/>
      </button>
    ) 
  }
}


ReactDOM.render(<Cog />, document.getElementById('root'))
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.3.1/css/all.css">
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

<div id="root" />

对于仅css的解决方案,您可以对父元素使用transitionrotateY(-180deg) hack:

.icon { 
  display: inline-block; 
}

.icon__inner {
  transition: transform 1s;
}

input:checked + .icon {
  transform: rotateY(-180deg);
}

input:checked + .icon .icon__inner {
  transform: rotateZ(-180deg);
}
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.3.1/css/all.css">

<input type='checkbox' />

<div class="icon">
  <i class="icon__inner fas fa-cog fa-3x"></i>
</div>

答案 3 :(得分:2)

这是另一个答案。因为我没有齿轮,所以我使用三角形

toggle.addEventListener("click", () => {
cog.className = (cog.className == "" || cog.className == "inactive") ? "active" : "inactive"
});
#cog{
  margin:0 auto;
  width:108px;
  outline:1px solid;
  transform-origin: 54px 108px;
}

#triangle{
  outline:1px solid;
  border:25px solid transparent;
  border-bottom:100px solid green;
  width:0px;
  height:1px;
  position:relative;
  margin:auto;
}

#triangle::before{
  content:"";
  width:16px; 
  height:16px;
  background:red;
  display:block;
  position:absolute;
  bottom:-108px;
  left:-8px;
  border-radius:50%;
}


 @keyframes rotate1 {
      100% {
        transform: rotate(180deg);
      }
    }

 @keyframes rotate2 {
       0% {
        transform: rotate(180deg);
      }
      100% {
        transform: rotate(360deg);
      }
    }

#cog.active{animation: rotate1 1s ease;
            animation-fill-mode: forwards;}

#cog.inactive{animation: rotate2 1s ease;
            animation-fill-mode: forwards;}
<div id="cog" class="">
  <div id="triangle"></div>
</div>


<input type="button" value="toggle-class" id="toggle" />

答案 4 :(得分:0)

由于您使用的是React,因此您可能更喜欢使用Component。继续使用<button>和动画样式,可以将持久按钮状态与过渡状态分开,这样动画仅在单击时发生,而在重新加载时不发生。

// Image src https://upload.wikimedia.org/wikipedia/commons/thumb/9/97/Twemoji_1f61d.svg/200px-Twemoji_1f61d.svg.png
const SMILEY_PNG = 'data:image/png;base64,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';

class AnimatedIcon extends React.Component {
  constructor() {
    super();
    this.state = {
      active: false,
      transitionStyle: {}
    };
  }

  render() {
    // On click set new state and add transition styling
    const onclk = () => {
      this.setState({
        active: !this.state.active,
        transitionStyle: this.state.active ? {animation: 'rotate-from-180 1s ease'} : {animation: 'rotate-to-180 1s ease'}
      });
    };
    
    return (
      <button onClick={onclk} className={this.state.active ? 'active' : 'inactive'}>
          <img src={SMILEY_PNG} style={this.state.transitionStyle} />
          ClickMe 
      </button>
    );
  }
}

ReactDOM.render( <AnimatedIcon /> , document.getElementById('root'));
button {
  margin: 10px;
  font-size: 20pt;
  color: red;
}

button img {
  padding: 10px;
  vertical-align: middle;
}

.active {
  color: green;
}

.active img {
  transform: rotate(180deg);
}

@keyframes rotate-to-180 {
  from { transform: rotate(0deg); }
  to   { transform: rotate(180deg); }
}

@keyframes rotate-from-180 {
  from { transform: rotate(180deg); }
  to   { transform: rotate(360deg); }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>