Skip to content

eckz/bevy_flair

Repository files navigation

About

Crates.io docs.rs

Bevy Flair brings CSS-like styling to Bevy UI, letting you define appearance and layout using familiar CSS syntax.

It enables you to style UI components, taking advantage of the power of CSS.

Features

  • Apply CSS assets directly to Bevy UI elements.

  • Inherited stylesheets. Specify a NodeStyleSheet on a root node and all children inherit it automatically.

  • Property inheritance support (e.g. color, font-family).

  • Font loading with @font-face.

  • Animated property changes via transition.

  • Custom animations with @keyframes.

  • Hot-reloading: edit your .css file and see styles re-applied on the fly.

    • This is one of the main advantages over specifying the styles directly in code.
  • Broad support for existing Bevy UI components and properties:

  • Shorthand properties like border, grid, margin, etc.

    • Shorthand properties parse into individual properties, like margin becomes margin-left, margin-right, etc.
    • Transitions and animations are supported for shorthand properties as well.
  • Non-standard CSS extensions for ImageNode

    • Example: background-image: url("panel-border-030.png"), -bevy-image-mode: sliced(20.0px).
  • Color parsing. (e.g. red,#ff0000,rgb(255 0 0),hsl(0 100% 50% / 50%),oklch(40.1% 0.123 21.57))

  • Common CSS selectors and combinators (via selectors crate):

    • :root, #id (using Name), .class (using ClassList), type selectors (via TypeName), :hover, :active, :focus, :nth-child, :first-child.
    • descendant (ul li), child (ul > li), sibling (img + p, img ~ p).
    • :not(), :has(), :is(), :where().
  • Attribute selectors (via AttributeList).

  • Nested selectors: e.g. &:hover { ... }.

  • Importing other stylesheets with @import.

  • Custom properties with var() (Fallback is currently not supported).

  • Basic calc() expressions (mainly useful with variables).

    • This is currently limited by Bevy support of mixing different Val types. This wouldn't work: calc(100% - 20px).
    • Is valuable only to do calculations using vars. For example: calc(var(--spacing) * 2).
  • @media queries (prefers-color-scheme, width, height, resolution, aspect-ratio).

  • @layer support.

  • Inline CSS properties.

  • Pseudo-elements ::before and ::after (enabled with PseudoElementsSupport).

  • Different stylesheets per subtree. With the use of a different NodeStyleSheet per subtree. It's even possible to not apply any style for a given subtree.

  • Use of custom times for transitions and animations (See https://github.com/eckz/bevy_flair/blob/main/examples/animations.rs).

  • Supports for custom properties. (Example TBA).

  • Supports for custom parsing. (See https://github.com/eckz/bevy_flair/blob/main/examples/custom_parsing.rs)

Missing features and limitations

  • Only one stylesheet per entity (workaround: by using @import).
  • No global stylesheets.
  • No real support for !important.
    • Currently, !important is detected but ignored with a warning.
  • Limited font support: only single fonts via @font-face. No local or fallback fonts.
  • No advanced color functions like color-mix() or relative color syntax (e.g. lch(from blue calc(l + 20) c h)).
  • No individual animation or transition properties like animation-name, transition-duration, etc.

Showcase

Example styled entirely with CSS:

game-menu.mov

(View source CSS)

Getting started

  1. Add bevy_flair to your Cargo.toml.

  2. Create your UI structure and attach NodeStyleSheet the root:

main.rs:

use bevy::prelude::*;
use bevy_flair::prelude::*;

fn main() {
    App::new()
        .add_plugins((DefaultPlugins, FlairPlugin))
        .add_systems(Startup, setup)
        .run();
}

fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
    commands.spawn(Camera2d);
    commands.spawn((
        Node::default(),
        NodeStyleSheet::new(asset_server.load("my_stylesheet.css")),
        children![(Button, children![Text::new("Button")])],
    ));
}

Save your css file under assets/my_stylesheet.css:

:root {
  display: flex;
  width: 100%;
  height: 100%;
  align-items: center;
  justify-content: center;

  /* font-size and color are inherited */
  font-size: 35px;
  color: rgb(30% 30% 30%);
}

button {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 150px;
  height: 65px;
  background-color: rgb(15%, 15%, 15%);
  border-radius: 10px;
  transition: background-color 0.5s;

  &:hover {
    color: #ddd;
    background-color: rgb(30%, 30%, 25%);
  }

  &:active {
    color: #ddd;
    background-color: rgb(35%, 65%, 35%);
  }

  text {
    /* Color transitions need to happen in the text element */
    transition: color 0.5s;
  }
}

Another good place to start are the examples in the examples folder.

Project goals

  • Full CSS-based styling for Bevy UI.
  • Efficient and reactive when applying styles.
    • No unnecessary style re-application if the UI tree hasn’t changed.
    • When modifications are detected in the UI tree, just the minimum affected nodes should get their style reapplied.
  • Strict CSS validation and reporting:
    • Invalid or unknown properties are reported, not ignored.
    • Errors in one rule don’t block others.
    • No panics from malformed CSS.
  • Css that would make your application panic should be rejected and reported.
    • If any correctly parsed css can cause a panics in bevy, it should be treated as a bug.

Non goals

  • Dictating how Bevy UI elements are spawned
    • If you want to use any fancy macro to spawn your bevy UI elements, or if you want to do it in a manual way, it should not matter, it should work the same way.
    • Once bsn! macro gets implemented, this crate should keep working as before.
  • Define a default style.
    • By default, if a property is not defined, such property will not be modified. This means that is up to the author to set up fallback styling if it's needed.
    • There is support for initial values, which uses the component's default value.
  • Supporting every CSS feature / property.
    • CSS is a vast specification, so there are plenty of features that might not make sense to support.
  • Strict CSS spec compliance (some deviations for practical reasons).
    • CSS is a standard and such it defines certain behaviours very well, for example, current implementation of animation or transition is quite possible not 100% consistent with the standard.
  • Implementing missing Bevy UI features (e.g. unsupported units like em, or properties like text-decoration).

Bevy compatibility

bevy bevy_flair
0.17 0.5
0.16 0.2, 0.3, 0.4
0.15 0.1

Contributing

Contributions are welcome! Feel free to fork the repository and submit a pull request.

License

This project is licensed under the MIT License. See the LICENSE file for more details.

The assets included in this repository (for our examples) fall under different open licenses.

Assets

About

Bevy UI styling using CSS

Resources

License

Stars

Watchers

Forks

Packages

No packages published