CSS Styling Deep Dive
Project Code:https://github.com/euv-dev/euv
Styling is a critical part of any frontend application, and euv provides a powerful set of tools for applying CSS to your components. This article takes an in-depth look at the class! macro, CSS variables, the var! macro, and how to create sophisticated styling patterns in your euv applications.
The class! Macro
The class! macro is euv's primary mechanism for applying CSS classes to elements. It goes far beyond simple class name strings — it supports pseudo-classes, media queries, conditional classes, and animations.
Basic CSS Classes
At its simplest, the class! macro generates a CSS class string that you can apply to elements:
use euv::*;
fn app() -> VirtualNode {
html! {
div {
class: class!("container"),
p { class: class!("text-large"), "Hello, World!" }
}
}
}
mount("#app", app);
The class! macro takes one or more class names and returns a string that can be used as the class attribute on any element.
Multiple Classes
You can combine multiple classes by passing multiple arguments:
html! {
div {
class: class!("container", "shadow", "rounded"),
"Multiple classes applied"
}
}
Conditional Classes
One of the most powerful features of the class! macro is its support for conditional classes. You can use expressions to determine which classes are applied:
use euv::*;
fn app() -> VirtualNode {
let count: Signal<i32> = use_signal(|| 0);
html! {
div {
class: class!(
"base-style",
if count.get() > 0 { "positive" } else { "non-positive" }
),
"Count: " {count}
}
}
}
mount("#app", app);
Here, the class list dynamically changes based on the value of the count signal. When the signal updates, euv automatically re-evaluates the class expression.
Combining class! with Reactive Signals
The class! macro integrates seamlessly with euv's reactive system. You can embed signals directly in class expressions:
use euv::*;
fn app() -> VirtualNode {
let is_active: Signal<bool> = use_signal(|| true);
html! {
div {
class: class!(
"panel",
if is_active.get() { "active" } else { "inactive" }
),
"Panel Content"
}
}
}
mount("#app", app);
Pseudo-classes and Nested Selectors
The class! macro supports CSS pseudo-classes and nested selector patterns:
let hover_style = class!(
"button",
":hover { background-color: blue; }",
":active { background-color: darkblue; }"
);
This generates CSS rules for hover and active states, which are scoped to elements with the button class.
Media Queries
Responsive design is straightforward with the class! macro's media query support:
let responsive_style = class!(
"container",
"@media (max-width: 768px) { flex-direction: column; }",
"@media (min-width: 1200px) { max-width: 1140px; }"
);
This applies different CSS rules based on the viewport width, enabling fully responsive layouts.
Animations with class!
The class! macro supports CSS animations through keyframe definitions:
let animated_style = class!(
"fade-in",
"@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }",
"animation: fadeIn 0.3s ease-in;"
);
You can combine this with euv's built-in animation and transition features for rich interactive experiences.
CSS Variables and the var! Macro
euv provides first-class support for CSS custom properties (variables) through the css-vars! and var! macros.
Defining CSS Variables
Use the css-vars! macro to define CSS custom properties:
use euv::*;
fn app() -> VirtualNode {
css-vars!(
"--primary-color", "#3498db",
"--secondary-color", "#2ecc71",
"--font-size-base", "16px"
);
html! {
div {
h1 { "Styled with CSS Variables" }
p { "This text uses CSS custom properties." }
}
}
}
mount("#app", app);
Using the var! Macro
Reference CSS variables in your styles using the var! macro:
use euv::*;
fn app() -> VirtualNode {
html! {
div {
style: "color: var(--primary-color); font-size: var(--font-size-base);",
"Styled text"
}
}
}
mount("#app", app);
Dynamic CSS Variables
CSS variables can be made reactive by combining them with signals:
use euv::*;
fn app() -> VirtualNode {
let hue: Signal<i32> = use_signal(|| 200);
css-vars!(
"--dynamic-color", format!("hsl({}, 70%, 60%)", hue.get())
);
html! {
div {
style: "background-color: var(--dynamic-color);",
"Dynamic color background"
}
}
}
mount("#app", app);
Styling Patterns
Pattern 1: Theme Variables
Define a set of CSS variables for your application's theme:
fn apply_theme() {
css-vars!(
"--color-bg", "#ffffff",
"--color-text", "#333333",
"--color-primary", "#3498db",
"--color-success", "#2ecc71",
"--color-danger", "#e74c3c",
"--spacing-sm", "8px",
"--spacing-md", "16px",
"--spacing-lg", "24px",
"--border-radius", "4px"
);
}
Pattern 2: Conditional Styling Based on State
Combine signals with the class! macro for state-driven styling:
use euv::*;
fn todo_item(text: &str, done: bool) -> VirtualNode {
html! {
li {
class: class!(
"todo-item",
if done { "completed" } else { "pending" }
),
text
}
}
}
fn app() -> VirtualNode {
html! {
ul {
{todo_item("Learn euv", true)}
{todo_item("Build an app", false)}
}
}
}
mount("#app", app);
Pattern 3: Responsive Grid Layout
Use media queries in the class! macro for responsive layouts:
fn app() -> VirtualNode {
html! {
div {
class: class!(
"grid",
"@media (min-width: 768px) { grid-template-columns: repeat(2, 1fr); }",
"@media (min-width: 1024px) { grid-template-columns: repeat(3, 1fr); }"
),
div { class: class!("grid-item"), "Item 1" }
div { class: class!("grid-item"), "Item 2" }
div { class: class!("grid-item"), "Item 3" }
}
}
}
mount("#app", app);
Styling and the html! Macro
The html! macro supports inline styles through the style attribute:
html! {
div {
style: "color: red; font-size: 14px;",
"Inline styled text"
}
}
However, for maintainability, prefer using the class! macro for most styling needs. Reserve inline styles for truly dynamic values that can't be expressed in CSS:
use euv::*;
fn app() -> VirtualNode {
let progress: Signal<f64> = use_signal(|| 0.5);
html! {
div {
class: class!("progress-bar"),
div {
class: class!("progress-fill"),
style: format!("width: {}%;", progress.get() * 100.0),
""
}
}
}
}
mount("#app", app);
Transitions
CSS transitions work naturally with euv's reactive system. Define the transition in your CSS:
let transition_style = class!(
"panel",
"transition: all 0.3s ease;"
);
When the state changes and the class updates, the browser automatically animates the transition:
use euv::*;
fn app() -> VirtualNode {
let expanded: Signal<bool> = use_signal(|| false);
html! {
div {
class: class!(
"panel",
"transition: all 0.3s ease;",
if expanded.get() { "expanded" } else { "collapsed" }
),
button {
onclick: move || { expanded.set(!expanded.get()); }
"Toggle"
}
}
}
}
mount("#app", app);
Summary
euv provides a comprehensive set of styling tools through the class! macro, css-vars! macro, and var! macro. The class! macro supports conditional classes, pseudo-classes, media queries, and animations. CSS variables enable theming and dynamic styling. By combining these tools with euv's reactive signals, you can create sophisticated, responsive, and maintainable styles for your applications.
Project Code:https://github.com/euv-dev/euv
Top comments (0)