/* 🎤 语音消息组件样式 */ /* CSS变量定义 */ .voice-message-container { --primary-color: #007AFF; --primary-light: #5AC8FA; --success-color: #34C759; --warning-color: #FF9500; --danger-color: #FF3B30; --background-light: #F2F2F7; --background-dark: #1C1C1E; --text-primary: #000000; --text-secondary: #8E8E93; --border-color: #E5E5EA; --shadow-light: 0 2rpx 8rpx rgba(0, 0, 0, 0.1); --radius-medium: 12rpx; --radius-large: 20rpx; } /* 🌙 深色模式支持 */ @media (prefers-color-scheme: dark) { .voice-message-container { --primary-color: #0A84FF; --background-light: #2C2C2E; --background-dark: #1C1C1E; --text-primary: #FFFFFF; --text-secondary: #8E8E93; --border-color: #38383A; --shadow-light: 0 2rpx 8rpx rgba(0, 0, 0, 0.3); } } .voice-message-container { max-width: 100%; width: 100%; margin: 8rpx 0; position: relative; box-sizing: border-box; } /* 🎨 语音气泡 */ .voice-bubble { display: flex; align-items: center; padding: 24rpx; border-radius: var(--radius-large); box-shadow: var(--shadow-light); transition: all 0.3s ease; min-width: 200rpx; position: relative; overflow: hidden; width: 100%; max-width: 100%; box-sizing: border-box; } /* 自己发送的消息 - 使用聊天气泡的绿色 */ .voice-message-container.self .voice-bubble { background: #4DD1A1; color: white; } /* 他人发送的消息 - 使用聊天气泡的灰色 */ .voice-message-container.other .voice-bubble { background: #D9D9D9; color: var(--text-primary); border: 1rpx solid rgba(255,255,255,0.03); } /* 播放状态 */ .voice-message-container.playing .voice-bubble { transform: scale(1.02); } .voice-message-container.self.playing .voice-bubble { background: #3CB88F; /* 稍微深一点的绿色表示播放中 */ } .voice-message-container.other.playing .voice-bubble { background: #C0C0C0; /* 稍微深一点的灰色表示播放中 */ border-color: #A0A0A0; } /* 🎵 播放按钮 */ .play-button { width: 80rpx; height: 80rpx; border-radius: 50%; display: flex; align-items: center; justify-content: center; margin-right: 24rpx; transition: all 0.3s ease; position: relative; box-sizing: border-box; overflow: hidden; flex-shrink: 0; /* 不允许在flex布局中被压缩 */ flex: 0 0 auto; /* 宽高由自身决定 */ min-width: 80rpx; /* 保底宽度,维持正圆 */ } .voice-message-container.self .play-button { background: rgba(255, 255, 255, 0.3); /* 在绿色背景上更明显的白色按钮 */ } .voice-message-container.other .play-button { background: rgba(0, 0, 0, 0.15); /* 在灰色背景上的深色按钮 */ } .play-button:active { transform: scale(0.95); } .play-icon { display: flex; align-items: center; justify-content: center; transition: all 0.3s ease; } .play-icon .icon { font-size: 32rpx; font-weight: bold; } .voice-message-container.self .play-icon .icon { color: white; /* 白色图标在绿色背景上 */ } .voice-message-container.other .play-icon .icon { color: #333333; /* 深色图标在灰色背景上 */ } /* 播放动画 */ .play-icon.play .icon { animation: pulse 2s infinite; } @keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.7; } } /* 🌊 语音波形 */ .voice-waveform { flex: 1; margin-right: 24rpx; height: 60rpx; display: flex; align-items: center; min-width: 0; /* 允许在狭窄容器中收缩,避免溢出 */ overflow: hidden; } .waveform-container { display: flex; align-items: center; justify-content: space-between; width: 100%; height: 100%; gap: 4rpx; } .wave-bar { width: 6rpx; border-radius: 3rpx; transition: all 0.3s ease; min-height: 8rpx; } .voice-message-container.self .wave-bar { background: rgba(255, 255, 255, 0.5); /* 在绿色背景上更明显的波形 */ } .voice-message-container.other .wave-bar { background: rgba(0, 0, 0, 0.2); /* 在灰色背景上的深色波形 */ } .voice-message-container.self .wave-bar.active { background: white; transform: scaleY(1.2); } .voice-message-container.other .wave-bar.active { background: rgba(0, 0, 0, 0.5); /* 深色波形激活状态 */ transform: scaleY(1.2); } /* 波形动画 */ .voice-message-container.playing .wave-bar.active { animation: waveAnimation 1.5s ease-in-out infinite; } @keyframes waveAnimation { 0%, 100% { transform: scaleY(1); } 50% { transform: scaleY(1.5); } } /* ⏱️ 语音时长 */ .voice-duration { min-width: 60rpx; text-align: right; } .duration-text { font-size: 24rpx; font-weight: 500; } .voice-message-container.self .duration-text { color: rgba(255, 255, 255, 0.95); /* 白色时长文字在绿色背景上 */ } .voice-message-container.other .duration-text { color: rgba(0, 0, 0, 0.6); /* 深色时长文字在灰色背景上 */ } /* 📊 播放进度条 */ .progress-container { margin-top: 16rpx; padding: 0 24rpx; } .progress-bar { height: 4rpx; background: var(--border-color); border-radius: 2rpx; overflow: hidden; margin-bottom: 8rpx; } .progress-fill { height: 100%; background: var(--primary-color); border-radius: 2rpx; transition: width 0.1s linear; } .progress-time { display: flex; justify-content: space-between; align-items: center; } .current-time, .total-time { font-size: 20rpx; color: var(--text-secondary); } /* 🔄 加载状态 */ .loading-container { position: absolute; top: 0; left: 0; right: 0; bottom: 0; display: flex; align-items: center; justify-content: center; background: rgba(0, 0, 0, 0.1); border-radius: var(--radius-large); backdrop-filter: blur(10rpx); } .loading-spinner { width: 40rpx; height: 40rpx; border: 3rpx solid rgba(255, 255, 255, 0.3); border-top: 3rpx solid white; border-radius: 50%; animation: spin 1s linear infinite; margin-right: 16rpx; } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } .loading-text { font-size: 24rpx; color: white; } /* ⚠️ 错误状态 */ .error-container { position: absolute; top: 0; left: 0; right: 0; bottom: 0; display: flex; align-items: center; justify-content: center; background: rgba(255, 59, 48, 0.1); border-radius: var(--radius-large); backdrop-filter: blur(10rpx); gap: 12rpx; } .error-icon { font-size: 32rpx; } .error-text { font-size: 24rpx; color: var(--danger-color); } .retry-button { font-size: 24rpx; color: var(--primary-color); text-decoration: underline; transition: all 0.2s ease; } .retry-button:active { opacity: 0.7; } /* 🎨 特殊效果 */ .voice-bubble::before { content: ''; position: absolute; top: 0; left: 0; right: 0; bottom: 0; background: linear-gradient(45deg, transparent 30%, rgba(255, 255, 255, 0.1) 50%, transparent 70%); opacity: 0; transition: opacity 0.3s ease; pointer-events: none; } .voice-bubble:active::before { opacity: 1; } /* 📱 响应式设计 */ /* 去除设备宽度相关的硬编码,统一依赖父容器宽度以避免溢出 */ /* 🎭 动画增强 */ .voice-message-container { animation: slideIn 0.3s ease-out; } @keyframes slideIn { from { opacity: 0; transform: translateY(20rpx); } to { opacity: 1; transform: translateY(0); } } /* 长按效果 */ .voice-bubble { user-select: none; -webkit-user-select: none; } .voice-bubble:active { transform: scale(0.98); } /* 可访问性 */ .voice-bubble[aria-pressed="true"] { outline: 2rpx solid var(--primary-color); outline-offset: 4rpx; } /* 状态指示器 */ .voice-message-container::after { content: ''; position: absolute; top: -4rpx; right: -4rpx; width: 16rpx; height: 16rpx; border-radius: 8rpx; opacity: 0; transition: all 0.3s ease; } .voice-message-container.playing::after { opacity: 1; background: var(--success-color); animation: pulse 2s infinite; }