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:
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
__azul-native-progressbar-container { } // style the ProgressBar container
__azul-native-progressbar-bar { } // style the ProgressBar bar
__azul-native-progressbar-label { } // style the ProgressBar label
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 expandedAfter 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