CSS Transitions
Michael Strauß
michaelstrau2 at gmail.com
Tue Jul 11 19:52:34 UTC 2023
I've previously proposed to add implicit CSS transitions to JavaFX.
Compared to the previous proposal, this new and refined proposal is a
"minimally invasive" version that requires almost no new API. The
previous proposal did get some reactions on GitHub, and I hope that
this new proposal can attract enough support within the OpenJFX
community to move it forward:
Goals
-----
Support CSS Transitions [1] in JavaFX.
Non-Goals
---------
It is not a goal to
* change the semantics of explicit transitions and animations of the
`javafx.animation` framework
* provide a programmatic API for implicit transitions (i.e. implicit
tansitions can only be defined in stylesheets)
* support CSS Animations [2]
Motivation
----------
CSS Transitions [1] is a universally supported web standard that
allows developers to specify how a CSS property changes its value
smoothly from one value to another. Here's how an implicit transition
is defined in a stylesheet:
.button {
transition-property: -fx-opacity;
transition-duration: 1s;
}
CSS Transitions makes it easy to define animated transitions and
create rich and fluid user experiences. CSS Transitions also nicely
complements control skins: while skins define the structure and
semantics of a control, implicit transitions define its dynamic
appearance.
Alternatives
------------
Applications that want to offer animated user experiences can use the
existing `javafx.animation` framework. Animated controls can be
created by subclassing existing skins and hooking into different kinds
of input events and property change events to trigger animations.
However, this is very cumbersome compared to using CSS Transitions.
Description
-----------
The `transition` pseudo-property is added to styleable nodes. It is
special and distinct from all other CSS properties for three reasons:
1. There is no API to access this property in Java code.
2. It is not returned from `Node.getClassCssMetaData`.
3. It is guaranteed to be applied before all other properties.
When a property value is changed by the CSS subsystem, we look whether
a transition has been specified for the given property. If it has, the
value change is animated over time. This works for all primitive
property types, as well as object properties with
`javafx.animation.Interpolatable` values.
Note that in order for this to work, we must apply the `transition`
pseudo-property before all other properties, as otherwise the CSS
subsystem might not know that a transition was specified for a given
property by the time the property value is changed.
It is important to note that an implicit transition is only started
when the property value is changed by the CSS subsystem, but not when
it is changed programmatically by calling Property.setValue(T) or via
a binding. This maximizes compatibility with code that assumes that
programmatic value changes happen instantly.
Applications don't need to keep track of running transitions, as they
are automatically cancelled when their associated control is removed
from the scene graph, becomes invisible, or is eligible for garbage
collection.
TransitionEvent
---------------
The new event `javafx.css.TransitionEvent` signals the creation,
beginning, completion and cancellation of implicit CSS transitions
[3]. Applications can use this event to react to running transitions,
for example by allowing a running transition to complete before
reconfiguring the user interface or switching to a new page.
Easing Functions
----------------
CSS Transitions specifies the `transition-timing-function`
sub-property to define easing functions (see CSS Easing Functions
[4]). Here is a list of all easing functions available in CSS Easing
Functions:
* linear
* ease, ease-in, ease-out, ease-in-out, cubic-bezier(x1, y1, x2, y2)
* step-start, step-end, steps(intervals, step-position)
Easing functions are implemented using `javafx.animation.Interpolator`
in JavaFX. While it may seem straightforward to re-use existing
interpolator implementations like `Interpolator.EASE_IN`,
`Interpolator.EASE_OUT`, etc., the definitions of those interpolators
don't match the definitions of CSS Easing Functions. In order to
maximize compatibility with CSS Transitions, implicit transitions use
the CSS definitions, not the SMIL 3.0 definitions of the existing
interpolator implementations.
Note that step-wise interpolators are only available for CSS
Transitions, they are not exposed as new public API in the
`javafx.animation` framework. The reason for this is that step-wise
interpolators accept negative input values and can produce different
results depending on their `step-position` parameter (for details on
that, see "2.3.1. Output of a step easing function" [5]).
Since the `javafx.animation` framework does not provide negative input
values to interpolators, step-wise interpolators don't work with
explicit transitions and animations. This could be a future
enhancement.
Future enhancements
-------------------
* In a follow-up enhancement, `Insets`, `Background`,
`BackgroundFill`, and `CornerRadii` will implement the
`Interpolatable` interface to allow more types to be implicitly
animated.
* CSS Animations [2] might also be implemented, which is another
CSS-based animation framework.
* An API to programmatically define CSS transitions might be added.
Not doing this right away allows the implementation to move around a
bit (which it might do if we choose to also do CSS Animations).
* Expose step-wise interpolators as public API in the
`javafx.animation` framework.
[1] https://www.w3.org/TR/css-transitions-1/
[2] https://www.w3.org/TR/css-animations-1/
[3] https://www.w3.org/TR/css-transitions-1/#transition-events
[4] https://www.w3.org/TR/css-easing-1/
[5] https://www.w3.org/TR/css-easing-1/#step-easing-algo
More information about the openjfx-dev
mailing list