CR: Waybar CSS Performance — Implementation

Changes Applied

1. Removed box-shadow Declarations (8 instances)

GTK3 renders box-shadow entirely on CPU. Multi-line shadow stacks with alpha() compositing were the primary CPU driver.

Removed from window#waybar
/* REMOVED — 5-value box-shadow stack */
box-shadow:
    0 6px 20px alpha(@crust, 0.6),
    0 0 30px alpha(@blue, 0.12),
    0 0 60px alpha(@mauve, 0.05),
    inset 0 1px 0 alpha(@surface2, 0.3);
Removed from tooltip
/* REMOVED */
box-shadow: 0 4px 12px alpha(@crust, 0.5);
Removed from #custom-power:hover
/* REMOVED */
box-shadow: 0 0 15px alpha(@red, 0.4);
Removed from @keyframes glow-pulse (3 frames)
/* REMOVED — replaced with opacity fallback */
0%   { box-shadow: 0 0 5px alpha(@blue, 0.3); }
50%  { box-shadow: 0 0 15px alpha(@blue, 0.5); }
100% { box-shadow: 0 0 5px alpha(@blue, 0.3); }
Removed from @keyframes border-glow-cycle (4 frames)
/* REMOVED — retained border-color only */
0%   { border-color: ...; box-shadow: 0 0 8px alpha(@blue, 0.3); }
33%  { border-color: ...; box-shadow: 0 0 8px alpha(@mauve, 0.3); }
66%  { border-color: ...; box-shadow: 0 0 8px alpha(@teal, 0.3); }
100% { border-color: ...; box-shadow: 0 0 8px alpha(@blue, 0.3); }

2. Disabled Infinite CSS Animations (7 → 0 always-on)

Infinite animations force GTK to repaint every frame. Each repaint recalculates all box-shadow and alpha() properties.

Selector Animation Action

#workspaces button.active

glow-pulse 2s ease infinite

Commented out

#custom-arch

text-flicker 4s linear infinite

Commented out

#clock

subtle-breathe 3s ease-in-out infinite

Commented out

#custom-power

border-glow-cycle 6s linear infinite

Removed

#network:not(.disconnected)

subtle-breathe 2s ease-in-out infinite

Commented out

Table 1. Retained (conditional — only fire on state change, not continuously)
Selector Animation Rationale

#workspaces button.urgent

pulse 1s ease infinite

Only fires when a workspace is urgent (rare)

#temperature.critical

pulse 0.5s ease infinite

Only fires at critical temp (emergency indicator)

#battery.critical:not(.charging)

pulse 0.5s ease infinite

Only fires at critical battery (emergency indicator)

3. Disabled transition: all (4 instances)

transition: all tells GTK to interpolate every CSS property on state change. With modules updating every 2-5 seconds, this triggers constant transition computation.

Selector Line

#workspaces button

96

#cpu, #memory, #temperature, …​ (grouped modules)

302

#custom-arch

495

#custom-power

519

4. Restored custom/media Module

The media module (playerctl -F) was temporarily removed during investigation to test if playerctl follow-mode caused the CPU spike. It did not. Restored to modules-center.

Future Considerations

Safe Visual Alternatives

Removed Effect Safe Replacement Why

box-shadow depth

border with alpha() colors

Borders are GPU-accelerated in GTK3

box-shadow glow

border-bottom: 2px solid alpha(@blue, 0.5)

Single-edge accent, zero CPU cost

transition: all

transition: background 0.2s ease (specific property)

Only interpolates one property, not all

Infinite animation

Remove, or use conditional selectors only (.urgent, .critical)

Conditional animations only fire on state change

Performance Testing Procedure

Before adding visual effects to waybar CSS:

# 1. Apply CSS change
# 2. Restart waybar
kill $(pgrep -x waybar) 2>/dev/null && waybar &disown 2>/dev/null

# 3. Wait 30 seconds for startup to settle
sleep 30

# 4. Check CPU — must be <2%
top -b -n1 | awk '/waybar/ {print "CPU:", $9"%"}'

# 5. If >2%, the CSS change is too expensive — revert