feat(web): enhance user message contrast for better visual distinction#1159
feat(web): enhance user message contrast for better visual distinction#1159miaomaolei1114-debug wants to merge 3 commits intoMoonshotAI:mainfrom
Conversation
Add high-contrast styling to user messages in the Web UI: - Blue gradient background instead of subtle gray - White text for improved readability - "You" label indicator above user messages - Smooth entrance animation - Dark mode support This improves accessibility and makes it easier to distinguish user messages from assistant messages in long conversations. Fixes #XXX (reference to user feedback)
web/src/index.css
Outdated
| .is-user [class*="rounded-2xl"] *, | ||
| .is-user [class*="rounded-2xl"] p, | ||
| .is-user [class*="rounded-2xl"] span, | ||
| .is-user [class*="rounded-2xl"] div { | ||
| color: white !important; | ||
| } |
There was a problem hiding this comment.
🟡 Overly broad [class*="rounded-2xl"] * selector forces white text on all descendants, not just the message bubble
The selector .is-user [class*="rounded-2xl"] * (lines 463-466) forces color: white !important on every descendant element of any element whose class attribute contains the substring rounded-2xl inside .is-user, without the [class*="bg-secondary"] qualifier that the bubble selector on line 442 correctly uses.
Detailed Explanation
The bubble-specific selector on line 442 correctly scopes to the message bubble:
.is-user [class*="rounded-2xl"][class*="bg-secondary"] { ... }But the text color selector on lines 463-466 drops the bg-secondary qualifier:
.is-user [class*="rounded-2xl"] *,
.is-user [class*="rounded-2xl"] p,
.is-user [class*="rounded-2xl"] span,
.is-user [class*="rounded-2xl"] div {
color: white !important;
}This means if any future element with rounded-2xl in its class is added as a descendant of .is-user (e.g., a badge, an action button, a tooltip trigger), all its text would be forced to white regardless of its own background color. Currently, the only rounded-2xl descendant inside .is-user is UserMessageContent, so this doesn't cause a visible problem today, but it is a fragile selector that will silently break when the component structure evolves.
Impact: Low impact currently but creates a maintenance hazard. The selector should include [class*="bg-secondary"] to match the bubble selector's specificity.
| .is-user [class*="rounded-2xl"] *, | |
| .is-user [class*="rounded-2xl"] p, | |
| .is-user [class*="rounded-2xl"] span, | |
| .is-user [class*="rounded-2xl"] div { | |
| color: white !important; | |
| } | |
| .is-user [class*="rounded-2xl"][class*="bg-secondary"] *, | |
| .is-user [class*="rounded-2xl"][class*="bg-secondary"] p, | |
| .is-user [class*="rounded-2xl"][class*="bg-secondary"] span, | |
| .is-user [class*="rounded-2xl"][class*="bg-secondary"] div { | |
| color: white !important; | |
| } | |
Was this helpful? React with 👍 or 👎 to provide feedback.
…pacing Replace margin-top with padding-top for the .is-user class to avoid overriding the dynamic spacing logic from spacingClass. This fixes the issue where the fixed margin was breaking context-aware spacing calculations (e.g., first message vs. subsequent messages, different spacing based on previous message role). The padding-top still provides the necessary space for the "You" label without interfering with the component's dynamic margin logic.
| .is-user { | ||
| animation: user-message-appear 200ms ease-out; | ||
| } |
There was a problem hiding this comment.
🔴 User message entrance animation replays on every scroll in virtualized list
The CSS animation user-message-appear applied to .is-user replays every time a user message scrolls back into the viewport, causing a distracting visual flicker during normal scrolling.
Root Cause
The app uses react-virtuoso (web/src/features/chat/components/virtualized-message-list.tsx:26) for rendering the message list. Virtuoso unmounts DOM elements when they scroll out of the viewport and remounts them when they scroll back in. Each remount creates a fresh DOM element, which re-triggers the CSS animation.
At web/src/index.css:525-526, the animation is unconditionally applied to all .is-user elements:
.is-user {
animation: user-message-appear 200ms ease-out;
}This means every time a user scrolls up and then back down through a conversation, user messages will fade-in and scale-up as if they were newly sent. In a long conversation with many user messages, this creates a visually jarring experience where messages appear to "pop in" repeatedly.
Impact: Degraded user experience during scrolling in any conversation with user messages. The animation was intended only for newly sent messages but fires on every scroll-driven remount.
Prompt for agents
The animation should only play when a user message is first added to the conversation, not on every virtualized remount. Since this is a CSS-only change, the cleanest fix would be to remove the animation entirely (lines 514-527 of web/src/index.css), or alternatively, add a JS-driven approach: add a temporary class like `is-new` to the Message component when a message is first created, and only apply the animation to `.is-user.is-new`. The temporary class should be removed after the animation completes. This requires changes in both the CSS file and the virtualized-message-list.tsx component.
Was this helpful? React with 👍 or 👎 to provide feedback.
- Remove redundant CSS selectors - Consolidate text color rules - Improve code comments - Keep padding-top approach to preserve dynamic spacing
Summary
Improves visual distinction between user and assistant messages in the Web UI by adding high-contrast styling to user messages.
Problem
In long conversations, user messages (right-aligned) and assistant messages (left-aligned) have similar gray backgrounds, making it difficult to:
Solution
Added CSS enhancements to
web/src/index.cssthat provide:Visual Improvements
oklch(0.55 0.15 250)→oklch(0.65 0.12 250)) instead of subtle grayuser-message-appear)Technical Details
.is-userclass already applied by theMessagecomponent[class*="rounded-2xl"][class*="bg-secondary"]selectorScreenshots
Before:
bg-secondary/50)After:
Accessibility
Testing
Browser Compatibility
Related
Addresses user feedback about difficulty distinguishing user messages in long conversations.