Styling with css!

The css! macro generates a class with given styles and the css attribute assigns it to the element. Besides regular properties it supports:

  • pseudo-classes like :hover and pseudo-elements like :before (write them with a single colon) as nested blocks,
  • @media queries as nested blocks, which need to be ended with a semicolon,
  • Rust expressions in braces, like {accent} below, inserted using their Display.
    use vertigo::{css, dom};

    let accent = "#e07020";

    let button_css = css! {"
        padding: 6px 12px;
        border: 2px solid {accent};
        background-color: white;
        color: black;
        cursor: pointer;

        :hover {
            background-color: {accent};
            color: white;
        }

        @media (prefers-color-scheme: dark) {
            background-color: #222;
            color: #eee;
        };

        @media screen and (max-width: 600px) {
            width: 100%;
        };
    "};

    dom! {
        <button css={button_css}>"Click me"</button>
    }

Styling other elements

Instead of a selector, another css! value can be referenced in brackets. This allows to style an element depending on the state of its parent:

    use vertigo::{css, dom};

    let tooltip_css = css! {"
        visibility: hidden;
        position: absolute;
        top: 100%;
        left: 0;
        padding: 4px 8px;
        background-color: black;
        color: white;
    "};

    // Shows the tooltip when the mouse is over the label
    let label_css = css! {"
        position: relative;
        border-bottom: 1px dotted gray;

        :hover [tooltip_css] {
            visibility: visible;
        }
    "};

    dom! {
        <span css={label_css}>
            "Hover me"
            <span css={tooltip_css}>"Hello from the tooltip!"</span>
        </span>
    }

Animations and dynamic styles

Animation keyframes are written right after the animation property, in a nested block. Styles can be added together with + (or extend), and a Computed of Css changes the styles whenever its value changes:

    use vertigo::{bind, css, dom, Value};

    let spinner_css = css! {"
        width: 24px;
        height: 24px;
        border: 3px solid #ccc;
        border-top-color: #e07020;
        border-radius: 50%;

        animation: 1s linear infinite {
            0% {
                transform: rotate(0deg);
            }
            100% {
                transform: rotate(360deg);
            }
        };
    "};

    let active = Value::new(false);

    let item_css = active.map(|active| {
        let base = css! {"
            padding: 4px;
            cursor: pointer;
        "};

        if active {
            base + css! {"
                font-weight: bold;
                background-color: #e07020;
            "}
        } else {
            base
        }
    });

    let toggle = bind!(active, |_| active.change(|active| *active = !*active));

    dom! {
        <div>
            <div css={spinner_css} />
            <div css={item_css} on_click={toggle}>"Click to toggle"</div>
        </div>
    }