Spinning in a clockwise direction for 180 degrees, followed by a full

I am seeking a solution to rotate a cog icon clockwise by 180 degrees when activated with the class "cards__cog cards__cog-active" and then rotate another 180 degrees clockwise back to its deactivated state using the class "cards__cog cards__cog-inactive". In my React project, I am updating the state when the cog is clicked in order to achieve this animation.

Although the current code works, I have encountered some issues:

1) The animation triggers on page load due to the initial "cards__cog-inactive" class. Is there a better approach to prevent this?

2) The implementation feels cumbersome and could possibly be simplified. Are there any suggestions for improvement?

Thank you

.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);
      }
    }

Answer №1

When implementing transitions for movements, it's important to note that using it for both can result in one of them moving backwards.

Avoid using animations for the initial state to prevent potential issues.

In this scenario, setting the inactive state at 360 degrees allows for a smooth transition from 180 to 360, while utilizing an animation to switch from inactive to active between 0 and 180 degrees.

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>

Answer №2

In your React project, consider moving the rotation logic from CSS into the component itself to avoid the need for extra classes and keyframes. You can achieve the desired effect using only a combination of transition and transform.

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" />

To achieve a CSS-only solution, you could utilize transition along with the rotateY(-180deg) hack on a parent element:

.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>

Answer №3

If your symbol has symmetry, you can explore 2 elements and transition in this manner.

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

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

Answer №4

This answer presents a unique solution using a triangle in place of a cog.

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" />

Answer №5

When working with React, it is recommended to utilize a Component for better organization. By keeping the <button> element and animation styling separate, you can ensure that the button state persists independently from the transition state, allowing the animation to occur only on click events rather than reloads.

// Example Image: Smiley face
const SMILEY_PNG = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3culE8AAAABmJLR0QA/wD/AP+gvaeTAAAAB3RJTUUH4AMCCik6uOTA9gAACo5...continent-6534.jpg';

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

  render() {
    // Function to handle button click event
    const handleClick = () => {
      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={handleClick} 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>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Exploring Safari Mobile's object-position feature

I'm inquiring about an issue with Safari Mobile and the CSS object-position/object-fit property. I attempted to use it, but unfortunately, it's not working for me. I've come across conflicting answers regarding Safari Mobile's support ...

Captivating images paired with informative captions

I am trying to display a picture with a description inline, but I am facing some issues. While I was able to align two pictures using div block:inline, adding a description to the first picture caused it to extend in width (despite setting margin: 0 and a ...

Organizing Pictures in a Gridded Design

My dilemma lies in displaying a set of thumbnail images within a div. The width of the div can vary depending on the screen size. Each image is fixed at 150px * 150px with a padding of 5px. I aim to arrange these thumbnails in a grid layout while ensuring ...

Insert more text following the existing content

Is it feasible to include text using pseudo-elements ::after or ::before to a specific word? For example, I am interested in placing a PDF icon consistently beside the word "Download". [PDF] Download Alternatively, are there other methods available? ...

Is there a way to confirm if all div elements have a designated background color?

I have a scenario where I have dynamically added several divs with a specific class to my webpage. These divs change color when the user hovers over them. I am trying to trigger a specific function once the last div has been set to a particular backgroun ...

What is the process for including icons on buttons?

I have been researching how to use Font Awesome software to incorporate icons into my HTML elements, but I am uncertain about the implementation process for my specific case. Currently, I have created a basic webpage with buttons and I would like to includ ...

What is the best way to align headings directly above their own bottom border?

Is there a way to make a heading align perfectly with its bottom border? Can negative padding achieve this effect, or should I use underline instead? Perhaps positioning it at the top border of the element below is an option. Thank you! h1 { font: bol ...

CSS code to modify background color upon mouse hover

I am currently working on creating a navigation menu. Check out the code snippet here: http://jsfiddle.net/genxcoders/ZLh3F/ /* Menu */ .menu { height: 100px; float: right; z-index: 100; } .menu ...

Ensure consistency in CSS3 background color transitions

There are multiple elements on the webpage with background transitions that change from one color to another: @-moz-keyframes backgroundTransition /* Firefox */ { 0% {background-color:#ff7b7b;} 33% {background-color:#7fceff;} 66% {backgr ...

Leveraging ng-class with an Angular $scope attribute

My HTML structure includes: <div class="myDiv"> <div style="width:200px; height:200px;background-image:url('img/200x200/{{largeImg}}.png');" ng-class="{'magictime foolishIn': 1}"> <span> { ...

I am attempting to create a captivating image for a "jumbotron"

My goal is to achieve a full-width image that stretches across the entire website. Furthermore, I want the image to remain centered and shrink from the sides as the window size decreases. Here's what I've attempted: HTML <div class="site-ban ...

Make HTML design responsive to any screen size

After completing the design of a mobile app interface with dimensions 750w by 1334H, I encountered an issue where it appears too large on the app testing screen. I am seeking a way to automatically adjust the design to fit all screens without compromising ...

The button text in Bootstrap 5 is black instead of white as shown in their demo

During the installation of Bootstrap 5, I encountered an issue where many of my buttons are displaying a black font instead of the expected white font as shown in the Bootstrap 5 Documentation For instance, the .btn-primary button on the official Bootstra ...

Using jQuery for slide shows in Ruby on Rails framework

I'm attempting to create a slideshow using jQuery and have the images stored in an array. However, I'm struggling with the implementation of the slideshow functionality. I've checked out 'http://jquery.malsup.com/cycle/' for guidan ...

Using the div tag will result in a new line being created

Whenever I try to create an element with a div, I notice there is always some space between the content and the border (blue line). On the other hand, using span causes the content to break, appearing outside the borders. Here is my CSS code: #m ...

Looking to spice up your email template with stacked elements?

For a challenging task of creating an email template, I encountered a problem with stacking one element on top of another: Usually in HTML/CSS, it would look like this: <div class="element"> <div class="icon"></div> <div class="c ...

HTML combined with the Internet Explorer versions 6, 7, 8, and 9 can result in a div element that

My HTML code includes a <div>Some text</div>, and I am looking to ensure it is unclickable (allowing elements under the div to be selected instead), unselectable (preventing users from selecting text inside the div), while still being visible.. ...

Is there a way to utilize jQuery to determine the distance the user has scrolled down?

Looking for some help with changing the style of an element based on scroll position using jQuery. Specifically, I want to add a class name to a div once the user has scrolled beyond 200 pixels and then remove the class name when they scroll back up to l ...

I need to display a VARCHAR variable retrieved from PHP in a visually appealing way with HTML/CSS. What is the best way to automatically format it to prevent it from appearing as one long, uninterrupted sentence?

Is there a way to automatically format the text retrieved from a VARCHAR variable in a MySQL database via PHP so that it displays correctly with line breaks? Currently, when I display it on an HTML page, it appears as one long string. I've considered ...

It is not possible to decrease the size of the image that is currently used as the background image

Three images are arranged in this manner: https://i.stack.imgur.com/u4PdK.png The HTML code for this setup is as follows: <div class="lb-controlContainer"> <div class="lb-closeContainer"> <a class="lb-close"&g ...