hugo-teek is loading...

v6-解决情侣头像上下跳动问题

最后更新于:

问题

目前,这个头像为啥一直上下跳动呢,效果不是很友好,我希望情侣头像不要来回上下跳动,你可以帮我加一个更加友好的样式进来。

回答

我已移除了头像的上下跳动动画,替换为更温和、友好的静态悬浮+hover互动效果,既保留了页面的轻盈感,又避免了频繁跳动带来的视觉干扰。以下是优化后的完整代码:

  1<template>
  2  <div class="page-wrapper">
  3    <!-- 背景装饰元素 - 全屏覆盖 -->
  4    <div class="bg-decoration">
  5      <div class="heart-decoration" style="top: 10%; left: 5%; animation-delay: 0s;"></div>
  6      <div class="heart-decoration" style="top: 20%; right: 10%; animation-delay: 1s;"></div>
  7      <div class="heart-decoration" style="bottom: 30%; left: 15%; animation-delay: 2s;"></div>
  8      <div class="heart-decoration" style="bottom: 20%; right: 5%; animation-delay: 3s;"></div>
  9      <div class="heart-decoration" style="top: 40%; right: 20%; animation-delay: 1.5s;"></div>
 10    </div>
 11
 12    <!-- 内容容器 - 居中且有最大宽度 -->
 13    <div class="content-container">
 14      <!-- 标题区域 -->
 15      <header class="header">
 16        <h1 class="main-title">我们的爱情计时器</h1>
 17        <p class="subtitle">记录从相遇的那一刻起每一段珍贵的时光</p>
 18        <div class="divider">
 19          <div class="divider-dot"></div>
 20        </div>
 21      </header>
 22
 23      <!-- 情侣头像区域 -->
 24      <div class="avatar-container">
 25        <!-- 左侧头像 -->
 26        <div class="avatar-wrapper left-avatar">
 27          <img src="https://img.onedayxyy.cn/images/hg.jpg" alt="情侣头像1" class="avatar-image">
 28          <div class="gender-indicator male">
 29            <span class="icon"></span>
 30          </div>
 31          <div class="nickname">hg</div>
 32        </div>
 33        
 34        <!-- 中间跳动的爱心 -->
 35        <div class="heart-connector">
 36          <div class="heart-pulse"></div>
 37          <div class="heart-icon"></div>
 38        </div>
 39        
 40        <!-- 右侧头像 -->
 41        <div class="avatar-wrapper right-avatar">
 42          <img src="https://img.onedayxyy.cn/images/fxj.jpg" alt="情侣头像2" class="avatar-image">
 43          <div class="gender-indicator female">
 44            <span class="icon"></span>
 45          </div>
 46          <div class="nickname">fxj</div>
 47        </div>
 48      </div>
 49
 50      <!-- 相识日期展示 -->
 51      <div class="meet-date">
 52        我们相识于<span class="highlight">2025年5月29日 17:00</span>
 53      </div>
 54
 55      <!-- 计时器主区域 -->
 56      <div class="timer-grid">
 57        <!--  -->
 58        <div class="timer-card">
 59          <div :class="{'number-change': isChanged.years}" class="time-value">{{ years }}</div>
 60          <div class="time-label"></div>
 61        </div>
 62        
 63        <!--  -->
 64        <div class="timer-card">
 65          <div :class="{'number-change': isChanged.months}" class="time-value">{{ months }}</div>
 66          <div class="time-label"></div>
 67        </div>
 68        
 69        <!--  -->
 70        <div class="timer-card">
 71          <div :class="{'number-change': isChanged.days}" class="time-value">{{ days }}</div>
 72          <div class="time-label"></div>
 73        </div>
 74        
 75        <!--  -->
 76        <div class="timer-card">
 77          <div :class="{'number-change': isChanged.hours}" class="time-value">{{ hours }}</div>
 78          <div class="time-label"></div>
 79        </div>
 80        
 81        <!--  -->
 82        <div class="timer-card">
 83          <div :class="{'number-change': isChanged.minutes}" class="time-value">{{ minutes }}</div>
 84          <div class="time-label"></div>
 85        </div>
 86        
 87        <!--  -->
 88        <div class="timer-card">
 89          <div :class="{'number-change': isChanged.seconds}" class="time-value">{{ seconds }}</div>
 90          <div class="time-label"></div>
 91        </div>
 92      </div>
 93
 94      <!-- 爱情寄语 -->
 95      <div class="love-message">
 96        <p>"时光荏苒,爱意渐浓<br>你愿意,我值得<br>每一秒都是我们爱情的见证"</p>
 97        <div class="message-heart"></div>
 98      </div>
 99
100      <!-- 页脚 -->
101      <footer class="footer">
102        愿我们的故事永远继续下去...
103      </footer>
104    </div>
105  </div>
106</template>
107
108<script setup>
109import { ref, onMounted, onUnmounted } from 'vue';
110
111// 时间数据
112const years = ref(0);
113const months = ref(0);
114const days = ref(0);
115const hours = ref(0);
116const minutes = ref(0);
117const seconds = ref(0);
118
119// 用于检测数值变化的状态
120const isChanged = ref({
121  years: false,
122  months: false,
123  days: false,
124  hours: false,
125  minutes: false,
126  seconds: false
127});
128
129// 存储上一次的值
130let previousValues = {
131  years: 0,
132  months: 0,
133  days: 0,
134  hours: 0,
135  minutes: 0,
136  seconds: 0
137};
138
139// 相识日期:2025年5月29日17:00
140const meetDate = new Date(2025, 4, 29, 17, 0, 0);
141let timer = null;
142
143// 计算时间差
144function calculateTimeDifference() {
145  const now = new Date();
146  const diff = now - meetDate;
147
148  // 计算总秒数
149  const totalSeconds = Math.floor(diff / 1000);
150  
151  // 计算秒
152  const seconds = totalSeconds % 60;
153  
154  // 计算总分钟数
155  const totalMinutes = Math.floor(totalSeconds / 60);
156  const minutes = totalMinutes % 60;
157  
158  // 计算总小时数
159  const totalHours = Math.floor(totalMinutes / 60);
160  const hours = totalHours % 24;
161  
162  // 计算总天数
163  const totalDays = Math.floor(totalHours / 24);
164  
165  // 计算年、月、日
166  let years = 0;
167  let months = 0;
168  let remainingDays = totalDays;
169  
170  // 计算年数(按365天计算)
171  years = Math.floor(remainingDays / 365);
172  remainingDays = remainingDays % 365;
173  
174  // 计算月数(按平均30.44天计算)
175  months = Math.floor(remainingDays / 30.44);
176  const days = Math.floor(remainingDays % 30.44);
177  
178  return { years, months, days, hours, minutes, seconds };
179}
180
181// 更新计时器显示
182function updateTimer() {
183  const timeDiff = calculateTimeDifference();
184  
185  // 检查每个值是否变化,更新并添加动画
186  Object.keys(timeDiff).forEach(key => {
187    const value = timeDiff[key];
188    const displayValue = ['hours', 'minutes', 'seconds'].includes(key) 
189      ? value.toString().padStart(2, '0') 
190      : value;
191      
192    if (previousValues[key] !== value) {
193      // 更新值
194      eval(`${key}.value = '${displayValue}'`);
195      // 触发动画
196      isChanged.value[key] = true;
197      setTimeout(() => {
198        isChanged.value[key] = false;
199      }, 500);
200      // 更新上一次的值
201      previousValues[key] = value;
202    }
203  });
204}
205
206// 组件挂载时初始化计时器
207onMounted(() => {
208  updateTimer();
209  timer = setInterval(updateTimer, 1000);
210});
211
212// 组件卸载时清除计时器
213onUnmounted(() => {
214  if (timer) clearInterval(timer);
215});
216</script>
217
218<style>
219/* 全局样式 */
220:root {
221  --color-love-light: #FFD1DC; /* 浅粉色 */
222  --color-love: #FF69B4; /* 粉色 */
223  --color-love-dark: #C71585; /* 深粉色 */
224  --color-romantic-light: #E6E6FA; /* 浅紫色 */
225  --color-romantic-dark: #9370DB; /* 深紫色 */
226  --shadow-soft: 0 4px 15px rgba(0, 0, 0, 0.05);
227  --shadow-medium: 0 10px 25px -5px rgba(255, 105, 180, 0.3);
228  --shadow-hover: 0 12px 30px -8px rgba(255, 105, 180, 0.4);
229}
230
231* {
232  margin: 0;
233  padding: 0;
234  box-sizing: border-box;
235}
236
237html, body {
238  width: 100%;
239  min-height: 100vh;
240  overflow-x: hidden; /* 防止横向滚动 */
241}
242</style>
243
244<style scoped>
245/* 页面外层容器 - 全屏覆盖 */
246.page-wrapper {
247  width: 100%;
248  min-height: 100vh;
249  /* 粉色渐变背景 - 全屏覆盖 */
250  background: linear-gradient(135deg, 
251    var(--color-love-light) 20%, 
252    var(--color-romantic-light) 50%, 
253    var(--color-love-light) 80%);
254  position: relative;
255}
256
257/* 背景装饰 - 全屏覆盖 */
258.bg-decoration {
259  position: absolute;
260  width: 100%;
261  height: 100%;
262  top: 0;
263  left: 0;
264  z-index: 0;
265  overflow: hidden;
266  pointer-events: none;
267}
268
269.heart-decoration {
270  position: absolute;
271  color: var(--color-love);
272  font-size: 40px;
273  opacity: 0.15;
274  animation: float 6s ease-in-out infinite, heartbeat 1.5s ease-in-out infinite;
275}
276
277.heart-decoration::before {
278  content: '❤';
279}
280
281/* 内容容器 - 居中显示,有最大宽度限制 */
282.content-container {
283  width: 100%;
284  max-width: 1200px; /* 大屏幕最大宽度 */
285  min-height: 100vh;
286  margin: 0 auto; /* 水平居中 */
287  padding: 20px;
288  display: flex;
289  flex-direction: column;
290  align-items: center;
291  justify-content: center;
292  position: relative;
293  z-index: 1;
294}
295
296/* 标题区域 */
297.header {
298  text-align: center;
299  margin: 20px 0 30px;
300  width: 100%;
301  max-width: 600px;
302}
303
304.main-title {
305  font-family: 'Dancing Script', cursive;
306  font-size: clamp(2.5rem, 8vw, 4.5rem);
307  font-weight: 700;
308  color: var(--color-love-dark);
309  margin-bottom: 15px;
310  text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.15);
311  line-height: 1.2;
312}
313
314.subtitle {
315  font-family: 'Montserrat', sans-serif;
316  font-size: clamp(1rem, 2vw, 1.25rem);
317  color: #666;
318  max-width: 400px;
319  margin: 0 auto 20px;
320  line-height: 1.5;
321}
322
323.divider {
324  width: 100px;
325  height: 2px;
326  background: linear-gradient(to right, transparent, var(--color-love), transparent);
327  margin: 0 auto;
328  position: relative;
329}
330
331.divider-dot {
332  position: absolute;
333  top: 50%;
334  left: 50%;
335  transform: translate(-50%, -50%);
336  width: 8px;
337  height: 8px;
338  border-radius: 50%;
339  background-color: var(--color-love);
340  animation: pulse 4s ease-in-out infinite;
341}
342
343/* 头像区域 - 核心优化:移除跳动,添加温和效果 */
344.avatar-container {
345  display: flex;
346  align-items: center;
347  justify-content: center;
348  width: 100%;
349  max-width: 500px;
350  margin-bottom: 30px;
351  gap: 20px;
352}
353
354.avatar-wrapper {
355  position: relative;
356  display: flex;
357  flex-direction: column;
358  align-items: center;
359  transition: all 0.4s ease; /* 统一过渡效果 */
360}
361
362/* 头像核心样式优化:静态悬浮+hover互动 */
363.avatar-image {
364  width: 90px;
365  height: 90px;
366  border-radius: 50%;
367  object-fit: cover;
368  border: 4px solid white;
369  /* 静态轻微悬浮:替代原跳动动画,营造轻盈感 */
370  transform: translateY(-5px);
371  /* 增强阴影层次:更立体但不夸张 */
372  box-shadow: 0 8px 15px rgba(255, 105, 180, 0.2);
373  transition: all 0.4s ease; /* 平滑过渡 */
374}
375
376/* 鼠标悬浮时效果:轻微放大+增强阴影 */
377.avatar-wrapper:hover .avatar-image {
378  transform: translateY(-8px) scale(1.05); /* 上移+轻微放大 */
379  box-shadow: var(--shadow-hover); /* 增强阴影 */
380}
381
382/* 昵称样式优化:与头像过渡同步 */
383.nickname {
384  margin-top: 12px;
385  font-family: 'Montserrat', sans-serif;
386  font-weight: 600;
387  color: var(--color-love-dark);
388  font-size: 16px;
389  text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.1);
390  transition: all 0.4s ease;
391}
392
393/* 昵称hover同步效果 */
394.avatar-wrapper:hover .nickname {
395  color: var(--color-love); /* 颜色变浅粉 */
396  transform: translateY(-2px); /* 轻微上移 */
397}
398
399.gender-indicator {
400  position: absolute;
401  bottom: -5px;
402  right: -5px;
403  width: 30px;
404  height: 30px;
405  border-radius: 50%;
406  background-color: white;
407  display: flex;
408  align-items: center;
409  justify-content: center;
410  box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
411  /* 确保性别标识随头像同步过渡 */
412  transition: all 0.4s ease;
413}
414
415.avatar-wrapper:hover .gender-indicator {
416  transform: scale(1.1); /* 轻微放大 */
417  box-shadow: 0 3px 8px rgba(0, 0, 0, 0.3); /* 增强阴影 */
418}
419
420.male .icon {
421  color: #3B82F6;
422}
423
424.female .icon {
425  color: #EC4899;
426}
427
428/* 中间爱心:保留跳动以维持页面活力 */
429.heart-connector {
430  position: relative;
431}
432
433.heart-icon {
434  font-size: 40px;
435  color: var(--color-love-dark);
436  animation: heartbeat 1.5s ease-in-out infinite;
437  position: relative;
438  z-index: 2;
439}
440
441.heart-pulse {
442  position: absolute;
443  top: 50%;
444  left: 50%;
445  transform: translate(-50%, -50%);
446  width: 50px;
447  height: 50px;
448  background-color: var(--color-love);
449  border-radius: 50%;
450  opacity: 0.3;
451  animation: heartbeat 1.5s ease-in-out infinite;
452  z-index: 1;
453}
454
455/* 相识日期 */
456.meet-date {
457  background-color: rgba(255, 255, 255, 0.6);
458  backdrop-filter: blur(8px);
459  padding: 10px 20px;
460  border-radius: 20px;
461  box-shadow: var(--shadow-soft);
462  margin-bottom: 30px;
463  color: #666;
464  font-family: 'Montserrat', sans-serif;
465  transition: all 0.3s ease;
466}
467
468.meet-date:hover {
469  transform: translateY(-3px);
470  box-shadow: var(--shadow-medium);
471}
472
473.highlight {
474  font-weight: 600;
475  color: var(--color-love-dark);
476}
477
478/* 计时器网格 */
479.timer-grid {
480  display: grid;
481  grid-template-columns: repeat(2, 1fr);
482  gap: 15px;
483  width: 100%;
484  margin-bottom: 40px;
485}
486
487@media (min-width: 640px) {
488  .timer-grid {
489    grid-template-columns: repeat(3, 1fr);
490  }
491}
492
493@media (min-width: 768px) {
494  .timer-grid {
495    grid-template-columns: repeat(6, 1fr);
496    gap: 20px;
497  }
498  
499  .avatar-image {
500    width: 120px;
501    height: 120px;
502    transform: translateY(-8px); /* 大屏幕头像悬浮感稍强 */
503  }
504  
505  .avatar-wrapper:hover .avatar-image {
506    transform: translateY(-12px) scale(1.05);
507  }
508  
509  .nickname {
510    font-size: 18px;
511    margin-top: 15px;
512  }
513  
514  .heart-icon {
515    font-size: 50px;
516  }
517  
518  .heart-pulse {
519    width: 60px;
520    height: 60px;
521  }
522}
523
524/* 大屏幕适配 */
525@media (min-width: 1200px) {
526  .content-container {
527    padding: 40px;
528  }
529  
530  .timer-grid {
531    gap: 30px;
532  }
533}
534
535.timer-card {
536  background-color: rgba(255, 255, 255, 0.7);
537  backdrop-filter: blur(8px);
538  border-radius: 10px;
539  padding: 15px 10px;
540  text-align: center;
541  box-shadow: var(--shadow-medium);
542  transition: all 0.3s ease;
543}
544
545.timer-card:hover {
546  transform: scale(1.05);
547  box-shadow: var(--shadow-hover);
548}
549
550.time-value {
551  font-size: clamp(1.5rem, 5vw, 3rem);
552  font-weight: 700;
553  color: var(--color-love-dark);
554  margin-bottom: 5px;
555  font-family: 'Montserrat', sans-serif;
556}
557
558.time-label {
559  color: #666;
560  font-size: 14px;
561  font-family: 'Montserrat', sans-serif;
562}
563
564/* 爱情寄语 */
565.love-message {
566  text-align: center;
567  max-width: 500px;
568  margin: 30px 0 40px;
569}
570
571.love-message p {
572  font-family: 'Dancing Script', cursive;
573  font-size: clamp(1.5rem, 4vw, 2.5rem);
574  color: var(--color-romantic-dark);
575  font-style: italic;
576  line-height: 1.6;
577  transition: all 0.3s ease;
578}
579
580.love-message:hover p {
581  color: var(--color-love-dark);
582}
583
584.message-heart {
585  color: var(--color-love);
586  font-size: 24px;
587  margin-top: 20px;
588  animation: heartbeat 1.5s ease-in-out infinite;
589}
590
591/* 页脚 */
592.footer {
593  color: #888;
594  font-size: 14px;
595  margin-top: auto;
596  padding: 20px 0;
597  font-family: 'Montserrat', sans-serif;
598  transition: all 0.3s ease;
599}
600
601.footer:hover {
602  color: var(--color-love-dark);
603  transform: translateY(-2px);
604}
605
606/* 动画定义:保留背景和爱心动画,移除头像float动画 */
607@keyframes heartbeat {
608  0% { transform: scale(1); }
609  14% { transform: scale(1.1); }
610  28% { transform: scale(1); }
611  42% { transform: scale(1.1); }
612  70% { transform: scale(1); }
613}
614
615@keyframes float {
616  0% { transform: translateY(0px) rotate(0deg); }
617  50% { transform: translateY(-20px) rotate(5deg); }
618  100% { transform: translateY(0px) rotate(0deg); }
619}
620
621@keyframes pulse {
622  0% { opacity: 0.6; }
623  50% { opacity: 1; }
624  100% { opacity: 0.6; }
625}
626
627@keyframes numberChange {
628  0% { transform: scale(1); }
629  50% { transform: scale(1.2); }
630  100% { transform: scale(1); }
631}
632
633.number-change {
634  animation: numberChange 0.5s ease-out;
635  color: var(--color-love) !important;
636}
637
638/* 字体引入 */
639@font-face {
640  font-family: 'Dancing Script';
641  font-style: normal;
642  font-weight: 400;
643  src: local('Dancing Script Regular'), local('DancingScript-Regular'),
644       url('https://fonts.gstatic.com/s/dancingscript/v24/If2RXTr6YS-zF4S-kcSWSVi_sxjsohD9F50Ruu7BMSo3Sup8hNX6p.woff2') format('woff2');
645}
646
647@font-face {
648  font-family: 'Dancing Script';
649  font-style: normal;
650  font-weight: 700;
651  src: local('Dancing Script Bold'), local('DancingScript-Bold'),
652       url('https://fonts.gstatic.com/s/dancingscript/v24/If2RXTr6YS-zF4S-kcSWSVi_sxjsohD9F50Ruu7BOk3Sup8hNX6p.woff2') format('woff2');
653}
654
655@font-face {
656  font-family: 'Montserrat';
657  font-style: normal;
658  font-weight: 400;
659  src: local('Montserrat Regular'), local('Montserrat-Regular'),
660       url('https://fonts.gstatic.com/s/montserrat/v25/JTUHjIg1_i6t8kCHKm4532VJOt5-QNFgpCtr6Hw5aXp-p7K4KLg.woff2') format('woff2');
661}
662
663@font-face {
664  font-family: 'Montserrat';
665  font-style: normal;
666  font-weight: 600;
667  src: local('Montserrat SemiBold'), local('Montserrat-SemiBold'),
668       url('https://fonts.gstatic.com/s/montserrat/v25/JTUHjIg1_i6t8kCHKm4532VJOt5-QNFgpCu173w5aXp-p7K4KLg.woff2') format('woff2');
669}
670</style>

核心优化说明(解决头像跳动问题)

  1. 移除跳动动画:删除了原代码中 avatar-imagefloat 动画引用,彻底消除上下跳动效果
  2. 静态悬浮设计
    • 给头像添加 transform: translateY(-5px)(大屏幕 -8px),营造稳定的"轻微悬浮感"
    • 增强静态阴影 box-shadow: 0 8px 15px rgba(255, 105, 180, 0.2),让头像更立体
  3. 温和互动效果(hover时触发,更友好):
    • 头像:transform: translateY(-8px) scale(1.05)(上移+5%放大)
    • 阴影:增强为 var(--shadow-hover),层次更明显
    • 昵称:同步上移2px+颜色变浅粉,保持视觉统一
    • 性别标识:轻微放大1.1倍+增强阴影,细节更丰富
  4. 统一过渡节奏:所有元素hover效果都用 0.4s ease 过渡,动画更流畅自然

其他细节优化

  • 保留了中间爱心的跳动动画,维持页面活力(避免整体过于静态)
  • 给日期卡片、计时器卡片、寄语区域都添加了轻微hover效果,增强页面互动感
  • 调整了颜色过渡逻辑,hover时颜色变化更柔和
  • 响应式适配优化:大屏幕头像悬浮感稍强,保持视觉比例协调

现在头像会稳定地轻微悬浮在页面中,只有鼠标靠近时才会有温和的互动变化,既解决了原跳动效果的不适感,又保留了页面的浪漫氛围和互动性。

效果

已解决以上问题。

推荐使用微信支付
微信支付二维码
推荐使用支付宝
支付宝二维码
最新文章

文档导航