CSS styling

List of supported CSS attributes

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

name
example values
display
block, inline-block, flex (default)
float
left, right, both
box-sizing
border-box, content-box
color
red, green, ..., #efefef, rgb(), rgba(), hsl(), hsla()
font-size
10px, 5pt, 40%, 10em, 5rem
font-family
sans-serif, serif, ..., "Times New Roman"
text-align
left, center, right
letter-spacing
0.0 - infinite
line-height
0.0 - infinite
word-spacing
0.0 - infinite
tab-width
0.0 - infinite
cursor
help, wait, crosshair, grab, default, ...
width
10px, 5%, 10rem, 5em
height
10px, 5%, 10rem, 5em
min-width
10px, 5%, 10rem, 5em
min-height
10px, 5%, 10rem, 5em
max-width
10px, 5%, 10rem, 5em
max-height
10px, 5%, 10rem, 5em
position
static (default), relative, absolute, fixed
top
10px, 5%, 10rem, 5em (+position:absolute / fixed)
right
10px, 5%, 10rem, 5em (+position:absolute / fixed)
left
10px, 5%, 10rem, 5em (+position:absolute / fixed)
bottom
10px, 5%, 10rem, 5em (+position:absolute / fixed)
flex-wrap
wrap, no-wrap
flex-direction
row, column, row-reverse, column-reverse
flex-grow
0.0 - infinite
flex-shrink
0.0 - infinite
justify-content
stretch, center, flex-start, flex-end, space-between, space-around
align-items
stretch, center, flex-start, flex-end
align-content
stretch, center, flex-start, flex-end, space-between, space-around
overflow, overflow[-x, -y]
auto (default), scroll, hidden, visible
padding[-top, ...]
10px, 5%, 10rem, 5em
margin[-top, ...]
10px, 5%, 10rem, 5em
background
red, [linear-, radial-, conic-]gradient(), image(id)
background-position
10% 10%, 10px 10px, left top
background-size
auto, cover, contain, 10% 40%, 100px 200px
background-repeat
repeat, no-repeat
border-radius
10px, 5%, 10rem, 5e
border-top-left-radius
10px, 5%, 10rem, 5em
border-top-right-radius
10px, 5%, 10rem, 5em
border-bottom-left-radius
10px, 5%, 10rem, 5em
border-bottom-right-radius
10px, 5%, 10rem, 5em
border, border-[top, ...]
1px solid red, 10px dotted #efefef
border-top-width
10px, 10rem, 5em (NO PERCENTAGE)
border-right-width
10px, 10rem, 5em (NO PERCENTAGE)
border-left-width
10px, 10rem, 5em (NO PERCENTAGE)
border-bottom-width
10px, 10rem, 5em (NO PERCENTAGE)
border-top-style
solid, dashed, dotted, ...
border-right-style
solid, dashed, dotted, ...
border-left-style
solid, dashed, dotted, ...
border-bottom-style
solid, dashed, dotted, ...
border-top-color
red, green, ..., #efefef, rgb(), rgba(), hsl(), hsla()
border-right-color
red, green, ..., #efefef, rgb(), rgba(), hsl(), hsla()
border-left-color
red, green, ..., #efefef, rgb(), rgba(), hsl(), hsla()
border-bottom-color
red, green, ..., #efefef, rgb(), rgba(), hsl(), hsla()
opacity
0.0 - 1.0
transform
matrix(), translate(), scale(), rotate(), ...
perspective-origin
100px 100px, 50% 50%
transform-origin
100px 100px, 50% 50%
backface-visibility
visible (default), hidden
box-shadow
0px 0px 10px black inset
background-color
red, green, #efefefaa, rgb(), rgba(), hsl(), hsla()
background-image
id("my-id")

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.


If you want to add images, you need to add them to the application first (via app.add_image(id, ImageRef)), then you can reference the id in your CSS background-content:

const IMAGE: &[u8] = include_bytes!("my-image.png"); struct Data { } extern "C" fn myLayoutFn(data: &mut RefAny, _: LayoutInfo) -> StyledDom { let mut css = Css::from_str("div { background-image: id('my-id'); }"); Dom::div().style(&mut css) } fn main() { let config = AppConfig::new(LayoutSolver::Default); let mut app = App::new(RefAny::new(Data { }), config); // load the image before the app starts let decoded = RawImage::decode_image_bytes_any(IMAGE).unwrap(); let imageref = ImageRef::raw_image(image).unwrap(); app.add_image("my-id", imageref); app.run(WindowCreateOptions::new(myLayoutFn)); } // or load it dynamically inside of a callback: extern "C" fn loadImageOnClick(data: &mut RefAny, mut callbackinfo: CallbackInfo) -> Update { let decoded = RawImage::decode_image_bytes_any(IMAGE).unwrap(); let imageref = ImageRef::raw_image(image).unwrap(); callbackinfo.add_image("my-id", imageref); Update::DoNothing }

If Azul can't find an image, the background will be rendered as transparent.



DOM styling


A Dom object + a Css object results in a StyledDom. A StyledDom can be restyled via .restyle(Css) if necessary, however, this only exists so that the application can be restyled via global themes.

CSS properties can be set either on the nodes themselves (as inline properties), or via a CSS stylesheet:

let mut dom = Dom::div().with_id("my_id").with_class("my_class"); let styled_dom = dom.style(&mut Css::from_str(" #my_id { width: 100px; height: 100px; background: red; } "));

Builtin CSS classes

CSS classes starting with .__azul-native- are reserved for builtin widgets. You can use these classes in the .restyle() method to restyle native buttons while retaining all the behaviour of the code:

.__azul-native-button-container { } // style the container of the Button widget .__azul-native-button-content { } // style the text of the Button widget .__azul-native-checkbox-container { } // style the container of the CheckBox .__azul-native-checkbox-content { } // style the content of the CheckBox .__azul_native_color_input { } // style the content of the ColorInput .__azul-native-label { } // style the text of the Label widget .__azul-native-text-input-container { } // style the container of the TextInput widget .__azul-native-text-input-label { } // style the text of the TextInput widget

Animating CSS properties

In any callback you can animate CSS properties if they are animatable using callbackinfo.start_animation(nodeid, Animation). Azul does not support animations via CSS. The start_animation function returns a TimerId, which you can use to call stop_timer when you want to stop the animation again. For UI transitions it generally makes sense to set relayout_on_finish, which will call your main layout() function again when the animation / transition is finished.

def on_click(data, info): # TODO: ugly - need to create helper functions! anim = Animation( from=CssProperty.Opacity(OpacityValue.Exact(StyleOpacity(PercentageValue(FloatValue(0))))), to=CssProperty.Opacity(OpacityValue.Exact(StyleOpacity(PercentageValue(FloatValue(1000))))), duration=Duration.System(SystemTimeDiff(secs=1,nanos=0)), repeat=AnimationRepeat.NoRepeat, easing=AnimationEasing.EaseInOut, relayout_on_finish=True ) timer = info.start_animation(info.get_hit_node(), anim)

Additionally, you can also use set_css_property(nodeid, CssProperty) in order to change a CSS property once from a callback:

def on_drag_start(data, info): drag = info.get_mouse_state().current_drag new_prop = CssProperty.Transform(TransformValue.Exact(StyleTransform.Position(new_x, new_y))) info.set_css_property(info.get_hit_node(), new_prop)

Internally, Azul does nothing other than to start a timer with a callback function that only interpolates between the Animation.from and Animation.to CSS values.



Layout system

The layout system roughly follows the CSS flexbox model, although not quite:


  • First, all items are set to either their min-width, the intrinsic content width (text / image) or 0px.

  • Then, flex items are recursively expanded according to their flex-grow values, depending on how much space the parent has available

  • position:absolute items are not expanded

  • After all sizes have been calculated, text is reflown if it doesn't fit in the bounds of the parent

  • Items are positioned on the screen, depending on the flex-direction value.

Azul is completely HiDPI aware, however, there is no em-cascading done yet. Azul calculates 1em = 16px.



Back to overview