Search code examples
javajavafxjavafx-css

JavaFX Animate item on hover effect using .css file


I have the following .CSS code:

.button:hover {
-fx-scale-x: 1.5;
-fx-scale-y: 1.5;
-fx-scale-z: 1.5;

}

Which Scales the button when it is hovered. However I would like to also implement a transition between these scales. and -fx-transition-duration: 0.3s; does not seems to be working


Solution

  • Note: CSS transitions require JavaFX 23+.


    Documentation

    From the JavaFX CSS Reference Guide for JavaFX 23:

    Transitions

    JavaFX supports implicit transitions for properties that are styled by CSS. When a property value is changed by CSS, it transitions to its new value over a period of time. Implicit transitions are supported for all primitive types, as well as for types that implement javafx.animation.Interpolatable.

    Transitions can be defined for any node in the JavaFX scene graph with the following properties:

    CSS Property Values Default Comments
    transition-property [ none | all | <custom‑ident># ] all The name of the CSS property to which the transition is applied.
    transition-duration <duration># 0s The duration of the transition, not including an optional delay before the transition starts.
    transition-timing-function <easing‑function># ease The easing function that is used to calculate the intermediate values.
    transition-delay <duration># 0s The delay after which the transition starts. If a negative delay is specified, the transition starts as if it had already been running for the specified time.
    transition <single-transition># where <single‑transition> = [ none | all | <custom‑ident> ] || <duration> || <easing‑function> || <duration> Short-hand notation for the individual properties. Note that while the order of the values generally doesn't matter, the first duration is always assigned to the transition-duration property, while the second duration is always assigned to the transition-delay property.

    A transition is not started (or cancelled if already running) in any of these scenarios:

    1. The property value is set programmatically
    2. The property is bound
    3. The node (or any of its parents) is invisible, as indicated by the Node.visible property
    4. The node is removed from the scene graph

    Nodes fire TransitionEvent to signal the creation, beginning, completion and cancellation of transitions.

    Example

    A button that smoothly changes its opacity on mouse-hover can be defined in a stylesheet like this:

    .button {
        -fx-opacity: 0.8;
        transition-property: -fx-opacity;
        transition-duration: 0.5s;
    }
    
    .button:hover {
        -fx-opacity: 1;
    }
    

    JavaFX 24+ will support CSS transitions for backgrounds and borders by making the related classes implement Interpolatable. See JDK-8332895 – Support interpolation for backgrounds and borders for more information.


    Example

    Here's an example that scales a button on hover (like in your question).

    Source Code

    Main.java

    import javafx.application.Application;
    import javafx.scene.Scene;
    import javafx.scene.control.Button;
    import javafx.scene.layout.StackPane;
    import javafx.stage.Stage;
    
    public class Main extends Application {
    
      private static final String STYLESHEET =
          """
          .button {
            transition-property: -fx-scale-x, -fx-scale-y;
            transition-duration: 0.3s;
            -fx-scale-x: 1.0;
            -fx-scale-y: 1.0;
          }
    
          .button:hover {
            -fx-scale-x: 1.5;
            -fx-scale-y: 1.5;
          }
          """;
    
      @Override
      public void start(Stage primaryStage) {
        var button = new Button("Button");
        button.setOnAction(_ -> System.out.println("Hello, World!"));
    
        var scene = new Scene(new StackPane(button), 500, 300);
        scene.getStylesheets().add("data:text/css," + STYLESHEET);
    
        primaryStage.setScene(scene);
        primaryStage.setTitle("CSS Transition Demo");
        primaryStage.show();
      }
    
      public static void main(String[] args) {
        launch(Main.class);
      }
    }
    

    *.css

    The above includes the stylesheet in the source code as a text block and adds it to the scene using a data URI. This was done to make it easier to run the example, but here is the CSS separately as well:

    .button {
      transition-property: -fx-scale-x, -fx-scale-y;
      transition-duration: 0.3s;
      -fx-scale-x: 1.0;
      -fx-scale-y: 1.0;
    }
    
    .button:hover {
      -fx-scale-x: 1.5;
      -fx-scale-y: 1.5;
    }
    

    Output

    GIF of running demo