Supported CSS attributes

This is a list of CSS attributes that are currently implemented. They work inthe same way as on a regular web page, except if noted otherwise:

  • border-radius
  • background-color
  • color (also as an non-standard alias: font-color)
  • letter-spacing
  • border, border-top, border-bottom, border-left, border-right
  • padding, padding-top, padding-bottom, padding-left, padding-right
  • margin, margin-top, margin-bottom, margin-left, margin-right
  • background [see #1]
  • font-size
  • font-family
  • box-shadow, box-shadow-top, box-shadow-bottom, box-shadow-left, box-shadow-right [see #2]
  • line-height
  • position: [static | relative | absolute]
  • top, left, right, bottom (only affects relative and absolute positioned items)
  • width, min-width, max-width
  • height, min-height, max-height
  • overflow, overflow-x, overflow-y
  • text-align [see #3]
  • flex-direction
  • flex-grow
  • flex-shrink (parses, but currently has no effect)
  • flex-wrap (parses, but currently has no effect)
  • justify-content (also as an non-standard alias: align-main-axis)
  • align-items (also as an non-standard alias: align-cross-axis)

Supported pseudo selectors

  • :first
  • :nth-child(x)
  • :last
  • :hover [WIP]
  • :active [WIP]
  • :focus [WIP]You can limit the inheritance of properties either to direct children only (using >) or to all children(using ). I.e. div#my_div.class has a different effect than div #my_div .class or div > #my_div > .class.

Notes:

  • image() takes an ID instead of a URL. Images and fonts are external resourcesthat have to be cached. Use app.add_image("id", my_image_data) orapp_state.add_image(), then you can use the "id" in the CSS to selectyour image.If an image is not present on a displayed div (i.e. you added it to the CSS,but forgot to add the image), the following happens:
    • In debug mode, the app crashes with a descriptive error message
    • In release mode, the app doesn't display the image and logs the error
  • box-shadow-xxx are non-standard extensions. They are used to clip a box-shadow toonly one border of a rectangle. The rule is:- If box-shadow is specified, a regular box shadow is drawn- If box-shadow-top and box-shadow-bottom are specified, the shadow appears on thetop and bottom of the rectangle. Same with a pair of box-shadow-left / box-shadow-right.- It isn't possible to display a box shadow on 3 sides, only on one or twoopposite borders.- If all 4 borders are specified, the value for box-shadow-top is taken.
  • Justified text is not (yet) supported
  • The pseudo selectors marked as [WIP] currently parse, but have no effect.

Creating CSS stylesheets

When you create a window, you have to give it a certain CSS stylesheet.This stylesheet cannot be modified during runtime, which is an importantlimitation. You can, however, create "dynamic properties", which can be dynamicallyupdated.

Azul has four modes on how the CSS is created:

TODO: The following APIs are outdated since #70 (refactoring CSS parsing into external crate)!

  • Css::new_from_str(&str) - parses and creates a stylesheet directly
  • Css::native() - creates the styles from the default, OS-native styles
  • Css::override_native(&str) - same as Css::new_from_str, but applies the user-definedstyles on top of the OS-native styles, i.e. it "overrides" the OS-native styles with user-defined ones.If you use a stylesheet that is saved to a separate file, Azul provides two extramodes, which are, however, only available in debug mode (with #[cfg(debug_assertions)]).

  • Css::hot_reload(FilePath) - hot-reloads a stylesheet from a file every 500ms, good for RAD.

  • Css::hot_reload_override_native(FilePath) - same as hot_reload, but applies the user-definedstyles on top of the OS-native styles, i.e. it "overrides" the OS-native styles with user-defined ones.If there are errors during parsing, the hot_reload function will print the error and use thelast stylesheet that could be parsed correctly.

Protected class names

In general, you should avoid defining any CSS classes in your stylesheet that startwith __azul-native- if you use Css::native(), override_native or hot_reload_override_native.Otherwise, you will override built-in native styles, unless that's what you're going for,it's better to not name your classes this way.

Static and dynamic CSS Ids

Azul knows about two types of CSS key-value pairs: static and dynamic. Becausethe CSS is only parsed once (at the start of the application), you cannot modify itduring runtime. However, you can specify IDs for certain properties, in order tochange the style of the application during runtime (for example to change the colorof a button on a On::Hover or On::MouseDown event). This API is also used foranimations (TODO) and :hover, :focus pseudo-selectors.

A static CSS property looks like this:

  1. .my_class {
  2. width: 500px;
  3. }

… while a dynamic property looks like this:

  1. .my_class {
  2. width: [[ my_property_id | 500px ]];
  3. }

The difference is that you can use the ID (in this case: "my_property_id" tochange the style dynamically from Rust):

  1. use azul::prelude::{CssProperty, LayoutWidth};
  2.  
  3. impl Layout for DataModel {
  4. fn layout(&self, _info: LayoutInfo<Self>) -> Dom<Self> {
  5. Dom::new(NodeType::Div)
  6. .with_class("my_class")
  7. .with_css_override("my_property_id", CssProperty::Width(LayoutWidth::px(700.0)))
  8. }
  9. }

This will "override" the CSS property to 700 px on the specific div. If the .with_css_overrideisn't present, the width would be 500px wide (every DynamicCssProperty need a "default" case).If you want to specify the default width to be automatically inferred from how much space thereis left in the parent node, you can use auto like this:

  1. .my_class {
  2. width: [[ my_property_id | auto ]];
  3. }

For example, this is useful if you want to have panels that expand an contract on clicking a button orif you want to drag content (so you need to overwrite `margin-top / margin-left to actually move the div)in the layout.

Notice that we don't have to un-set the width again. This is because dynamicCSS properties only stay active for one frame, and need to be re-applied on eachframe - this is a concious design choice to not make the visual style depend on asequence of actions that have to be executed and thereby make the style moreunit-testing friendly.

Also notice: If the set_dynamic_property gets a different type for your ID (let's say youtyped height instead of width, it will not override the target value, but print anerror (if logging is enabled)).

Layout system

The layout model follows closely to the CSS flexbox model (although many properties aren't implemented yet):

  • align the content across the main axis with flex-direction
  • If the width and height is not constrained, the rectangle will take up as much widthand height as possible, by default the width / height of the parent
  • Nest the layout to get more intricate and complicated layouts
  • When a rectangle is marked as position: absolute, it will search up the DOM tree for the nearestposition: relative or position: absolute rectangle and use the top, left, right, bottom propertiesto position itself relative to that rectangle
  • Z-indexing is currently only determined by the stacking order, there is no z-index attribute yet
  • inline blocks are non-existent. The reason for this is that if you need inline blocks, you'll likelyneed a bit more complicated layout. For this purpose, you can use absolute and relative positioning if youwant to lay rectangles behind the text and use the text metrics themselves to calculate the offsets.For regular inline-block content, just use flex-direction with a wrapper div.

Remarks

  • All measurements respect HiDPI screens and azul is fully HiDPI aware. Em valuesare measured as 1em = 16px
  • CSS key-value pairs are parsed from top to bottom, and get overwritten inthat order, for example:
  1. #my_div {
  2. background: image("Cat01");
  3. background: linear-gradient("105deg, red, blue");
  4. }

… will draw a linear gradient, not the image, since the linear-gradient valueoverwrote the image rule.

  • Attributes in CSS paths are not (and aren't planned to be) supported,since this is a fundamental difference between how HTML and the layout()function work.
  • auto as a value is only valid inside of dynamic CSS attributes, currentlyvalues such as auto and inherit do not work as general values.Animations are planned to be implemented with @keyframes, but this is not yet supported yet.You can create preliminary "animations" by using the dynamic CSS properties, but be aware thatevery repaint with dynamic CSS Ids requires a full re-layout, which can be performance intensive.