overflow:hidden,padding,解决图片加载的抖动现象

本文介绍了一种利用div的padding属性配合overflow:hidden样式来为图片占位的方法,有效避免了在网络延迟时图片加载造成的页面抖动现象,确保了页面布局的稳定性和用户体验。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

利用overflow:hidden使用div的padding为图片占位,防止图片加载出现抖动现象

盒子模型的内容区域包括content+padding,即padding box,正常情况下元素只在content内排布,但是当内容溢出到padding时是允许的,overflow:hidden对此不影响。因此可以先用padding为图片占位,防止网络较慢加载图片时发生抖动现象。

<div class="wrapper">
	    <swiper-slide>
	    	<img class="swiper-img" src="http://mp-piao-admincp.qunarzz.com/mp_piao_admin_mp_piao_admin/admin/20191/d74b0949794af25e495727702c380f28.jpg_890x330_b315a134.jpg"/>
	    </swiper-slide>
	  </swiper>
  </div>
  
<style>
	.wrapper
		overflow:hidden
		width: 100%
		height: 0
		padding-bottom: 37.08%
		.swiper-img
			width: 100%
</style>

在图片未加载时由padding占位,图片加载后能正常显示,不会因为height为0且overflow为hidden而隐藏图片。
overflow:hidden这句代码注释掉也没什么影响,目前还不知这句代码的作用

<template> <div class=“ScrollData_containe”> <div class=“item_header”> <p v-for=“(item, index) in header” :key=“index”> <span v-if=“item.icon” ><i class=“iconfont” :class=“[item.icon]”></i ></span> {{ item.text }} </p> </div> <div class=“item_cont” ref=“topbox”> <div :class=“[‘font-list’, dynamicCls]” :style=“dynamicSty”> <div class=“scrollBox” ref=“fontbox”> <p v-for=“(item, index) in data” :key=“index”> <!-- :class=“[Math.floor(Math.random() * 18) == 2 ? ‘bgChange’ : ‘’]” --> <span>{{ item.one }}</span> <span>{{ item.two }}</span> <span>{{ item.three }}</span> <span>{{ item.four }}</span> <span>{{ item.five }}</span> </p> </div> <div class=“scrollBox” ref=“doubleData”> <p v-for=“(item, index) in data” :key=“index”> <!-- :class=“[Math.floor(Math.random() * 18) == 2 ? ‘bgChange’ : ‘’]” --> <span>{{ item.one }}</span> <span>{{ item.two }}</span> <span>{{ item.three }}</span> <span>{{ item.four }}</span> <span>{{ item.five }}</span> </p> </div> </div> </div> </div> </template> <script> export default { props: { data: Object, header: Array, pageDuration: { type: Number, default: 12 } }, data() { return { doubleData: false, // 是否需要双份数据 fontBox: null, // 文字容器 topBox: null, // 文字父级容器 countFlag: 0, // 切换clss类标识符 dynamicCls: “”, // 动态class类,切换使用解决数据更新后动画不重新开始问题 dynamicSty: {}, scrollIndex: 0, newScrollData: null, scrollTimer: null, scrollBox: null, speed: 30 // 滚动速度 }; }, methods: { calcHeight() { // 判断内容是否超出容器,如果超出容器、追加一份数据 if (this.fontBox.offsetHeight > this.topBox.offsetHeight) { this.doubleData = true; this.countFlag += 1; // 切换动画类名 this.dynamicCls = scroll-cls${this.countFlag % 2}; // 动态计算动画时长 this.dynamicSty = { animationDuration: ${ (this.fontBox.offsetHeight / this.topBox.offsetHeight) * this.pageDuration }s }; } else { this.doubleData = false; this.dynamicCls = “”; this.dynamicSty = { animationDuration: “0s” }; } } }, watch: { // 监听内容变化 data: { deep: true, handler(_val) { this.calcHeight(); } } }, mounted() { this.fontBox = this.$refs.fontbox; this.topBox = this.$refs.topbox; this.$nextTick(() => { this.calcHeight(); }); }, beforeDestroy() {} }; </script> <style lang=“scss” scoped> .scroll-cls0 { animation: translateY1 8s 0.5s linear infinite; } .scroll-cls1 { animation: translateY2 8s 0.5s linear infinite; } // .font-list:hover { // animation-play-state: paused; // } @keyframes translateY1 { from { transform: translateY(0); } to { transform: translateY(-50%); } } @keyframes translateY2 { from { transform: translateY(0); } to { transform: translateY(-50%); } } .bgChange { background: #211141 !important; span { text-shadow: 0 0 10px #f00; } } .item_header { display: flex; justify-content: space-between; height: 0.2125rem; background: #111843; p { color: #fff; flex: 1; line-height: 0.2125rem; padding-left: 0.0625rem; font-family: “OPPOSANS-M”; span { display: inline-block; width: 0.125rem; height: 0.125rem; line-height: 0.125rem; background: #304bfa; text-align: center; box-shadow: 0 0 10px #bc6fea; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; vertical-align: middle; border-radius: 0.0125rem; } .iconfont { color: #fff !important; font-size: 0.0875rem; } } } .item_cont { height: 1.875rem; box-sizing: border-box; overflow: hidden; position: relative; .scrollBox { // position: absolute; width: 100%; left: 0; p { display: flex; justify-content: space-between; background: #060a24; height: 0.2rem; line-height: 0.2rem; margin: 0.0125rem 0; color: #fff; font-size: 0.0875rem; font-family: “OPPOSANS-M”; span { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; padding: 0 0.0625rem; } } } } </style> 该vue组件在数据量大的情况下,会导致cpu卡死
03-08
控制按钮在视频上,可是由于设置了position:absolute,导致切换移动端时,按钮直接不见了,如以下代码;<template> <el-carousel class="box" ref="carouselRef"> <el-carousel-item v-for="(videoSrc,index) in videoList" :key="index"> <div class="contain"> <!--目的:按钮始终准确定位在视频区域的右下角,单靠.box无法固定,因为用的不是html的原生组件--> <video class="toy_video" autoplay loop muted playsinline @click=""> <!--playsinline允许网页内联播放--> <source :src="videoSrc" type="video/mp4" /> Your browser does not support the video tag. </video> </div> <!--buy按钮叠加在视频上--> <el-button class="buy" :style="{backgroundImage:`url(${buyImg})`}" ></el-button> </el-carousel-item> </el-carousel> </template> <style scoped lang="scss"> .box{ position: relative; /* 相对定位 */ border-radius: 25px; overflow: hidden; height: 100%; /* 用于调试布局高度 background: rgba(0,0,255,0.1);*/ margin-top: 0; line-height: 0; // 清除行高空隙 font-size: 0; // 防止文本撑开 } .contain{ position: relative; height: 100%; border-radius: 25px; } /* 设置.el-carousel 的每一层样式,用于清楚一些其自带的默认样式 */ ::v-deep .el-carousel { height: 100%; border-radius: 25px; margin: 0 !important; padding: 0 !important; } ::v-deep .el-carousel__container { height: 100%; border-radius: 25px; margin: 0 !important; padding: 0 !important; } ::v-deep .el-carousel__item { height: 100%; border-radius: 25px; margin: 0 !important; padding: 0 !important; line-height: 0; } /* 注意:必须确保整个布局链条上高度是明确传递下来的,否则<el-carousel class="box"> 的高度 不会受到 .left, .videos, .select 中 flex 样式的控制*/ .toy_video{ width: 100%; height: 100%; object-fit: contain; /* 视频覆盖满 */ z-index: 2; margin: 0; padding: 0; display: block; } .buy{ /* 直接写在css里不一定生效 background-image: url('@/assets/buy_new.png');*/ background-size: cover; /* 图片覆盖整个按钮 */ background-position: center; width: 198px; height: 96px; z-index: 6; /*确保按钮在视频上方*/ position: absolute; /* 绝对定位 */ right: 132px; bottom: 65px; /* 无效,因为绝对定位 (position: absolute) 的元素,不再受 margin 的正常流影响 margin-left: 6px; margin-bottom: 6px;*/ /* 用于调试布局高度 */ background: rgba(0,0,255,0.1); // background: rgba(0,0,0,0); // 清除按钮的默认底色:白色 border-radius: 30px; /*background-color: red; 临时测试 */ outline: none; /*去除焦点状态的轮廓线 */ border: none; /*去除按钮默认的边框 */ background-repeat: no-repeat; /* 防止重复 */ } </style>
08-05
<template> <div class="tug-of-war-container"> <!-- 背景图片铺满全屏 --> <img :src="background" class="background-image" alt="背景"/> <!-- 问题图片 --> <div class="question-container"> <img :src='questionImg' class="question-image" alt="图片不存在"/> </div> <el-select v-model="questionValue" placeholder="请选择" class="select-question"> <el-option v-for="item in allQuestions" :key="item.id" :label="item.questionNumber" :value="item.id" @click="handleClick(item)"> </el-option> </el-select> <Edit/> <!-- 移动图片(按比例放大) --> <div class="move-container"> <img :src="character" class="move-image" :style="{ transform: `translateX(${imagePosition}px)` }" alt="移动对象" /> </div> <!-- 选项按钮 --> <div class="options-container"> <button class="option-btn left-option" :disabled="answered" @click="checkAnswer(question.resultLeft,'left')" > {{ question.optionOne }} </button> <button class="option-btn right-option" :disabled="answered" @click="checkAnswer(question.resultRight,'right')" > {{ question.optionTwo }} </button> </div> <!-- 提示图片 --> <transition name="fade"> <img v-show="showCorrectLeft" :src="correctImg" class="feedback-image correct-feedback-left" alt="正确提示" /> </transition> <transition name="fade"> <img v-show="showCorrectRight" :src="correctImg" class="feedback-image correct-feedback-right" alt="正确提示" /> </transition> <transition name="fade"> <img v-show="showIncorrectLeft" :src="incorrectImg" class="feedback-image incorrect-feedback-left" alt="错误提示" /> </transition> <transition name="fade"> <img v-show="showIncorrectRight" :src="incorrectImg" class="feedback-image incorrect-feedback-right" alt="错误提示" /> </transition> </div> </template> <script setup lang="ts"> import {onMounted, onUnmounted, ref} from 'vue'; import {getQuestionAll, getQuestionImg} from '@/api/modules/tug.of.war' import Edit from './Edit.vue'; // 导入所有需要的图片 import questionImgOld from '@/image/1.jpg'; import background from '@/image/background.jpg' import character from '@/image/character.png' import correctImg from '@/image/correct.png'; import incorrectImg from '@/image/incorrect.png'; import {TugOfWar} from "@/types/api/tugOfWar"; // 定义选项 const questionImg = ref<string>(); questionImg.value = questionImgOld // 定义奖项配置 const question = ref( {optionOne: "", optionTwo: "", resultLeft: 1, resultRight: 0} ) //所有问题 const allQuestions = ref<TugOfWar[]>([]); const questionValue = ref<string>(); // 图片位置状态 const imagePosition = ref<number>(0); const initialPosition = ref<number>(0); // 答题状态 const answered = ref<boolean>(false); const showCorrectLeft = ref<boolean>(false); const showCorrectRight = ref<boolean>(false); const showIncorrectLeft = ref<boolean>(false); const showIncorrectRight = ref<boolean>(false); // 检查答案 const checkAnswer = (optionIndex: number, direction: String) => { if (answered.value) return; answered.value = true; if (optionIndex === 1) { if ("left" === direction) { showCorrectLeft.value = true; // 向左移动图片 imagePosition.value = -250; } if ("right" === direction) { showCorrectRight.value = true; imagePosition.value = 250; } } if (optionIndex === 0) { if ("left" === direction) { showIncorrectLeft.value = true; // 向右移动图片 imagePosition.value = 250; } if ("right" === direction) { showIncorrectRight.value = true; imagePosition.value = -250; } } // 3秒后重置状态 setTimeout(resetGame, 3000); }; // 重置游戏状态 const resetGame = () => { answered.value = false; showCorrectLeft.value = false; showCorrectRight.value = false; showIncorrectLeft.value = false; showIncorrectRight.value = false; imagePosition.value = 0; }; // 响应式调整布局 const handleResize = () => { // 在实际应用中,这里可以添加响应式布局调整逻辑 }; // 定义响应类型 interface ApiResponse { data: ArrayBuffer headers: { 'content-type': "image/jpeg" } } const handleClick = async (questionOne: TugOfWar) => { try { console.log(questionOne.id); const response = await getQuestionImg({id: questionOne.id}); console.log(response); // 转换为 Blob(指定 MIME 类型) const blob = new Blob([response], {type: "image/jpeg"}); console.log(blob); // 创建 Blob 对象 // 创建临时 URL questionImg.value = URL.createObjectURL(blob); // 生成临时 URL } catch (error) { console.error('Error loading image:', error) // 可以在此处添加错误处理逻辑 questionImg.value = questionImgOld } question.value.optionOne = questionOne.optionOne; question.value.optionTwo = questionOne.optionTwo; question.value.resultRight = questionOne.resultRight question.value.resultLeft = questionOne.resultLeft } onMounted(async () => { window.addEventListener('resize', handleResize); allQuestions.value = await getQuestionAll() console.log(allQuestions.value) }); onUnmounted(() => { window.removeEventListener('resize', handleResize); }); </script> <style scoped> /* 基础样式重置 */ * { margin: 0; padding: 0; box-sizing: border-box; } .tug-of-war-container { position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; overflow: hidden; display: flex; flex-direction: column; justify-content: space-between; background: linear-gradient(135deg, #1a2a6c, #b21f1f, #1a2a6c); } /* 背景图片铺满全屏 */ .background-image { position: absolute; top: 0; left: 56px; width: 93%; height: 100%; object-fit: cover; z-index: 1; opacity: 0.8; } /* 问题容器 */ .question-container { position: relative; z-index: 2; display: flex; justify-content: center; padding-top: 0px; } .question-image { width: 80%; max-width: 400px; height: 180px; object-fit: contain; border: 4px solid #ffd700; border-radius: 15px; background: rgba(255, 255, 255, 0.9); box-shadow: 0 8px 30px rgba(0, 0, 0, 0.5); } /* 移动图片容器 */ .move-container { position: relative; z-index: 3; display: flex; left: 52px; justify-content: center; align-items: center; height: 300px; margin: 20px 0; } .move-image { width: 1200px; /* 放大移动图片 */ height: 1200px; object-fit: contain; transition: transform 0.8s cubic-bezier(0.175, 0.885, 0.32, 1.275); filter: drop-shadow(0 6px 12px rgba(0, 0, 0, 0.5)); z-index: 4; } /* 选项按钮容器 */ .options-container { position: relative; z-index: 5; display: flex; justify-content: space-between; padding: 0 30%; margin-bottom: 30px; } .option-btn { padding: 20px 50px; font-size: 24px; font-weight: bold; border: none; border-radius: 60px; cursor: pointer; transition: all 0.4s ease; box-shadow: 0 8px 20px rgba(0, 0, 0, 0.3); position: relative; overflow: hidden; z-index: 6; } .left-option { background: linear-gradient(145deg, #ff416c, #ff4b2b); color: white; } .right-option { background: linear-gradient(145deg, #38ef7d, #11998e); color: white; } .option-btn:hover:not(:disabled) { transform: translateY(-8px) scale(1.05); box-shadow: 0 12px 25px rgba(0, 0, 0, 0.4); } .option-btn:active:not(:disabled) { transform: translateY(2px); } .option-btn:disabled { opacity: 0.7; cursor: not-allowed; } /* 添加发光效果 */ .option-btn::after { content: ''; position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: rgba(255, 255, 255, 0.1); border-radius: 60px; transform: scale(0); transition: transform 0.5s ease; } .option-btn:hover:not(:disabled)::after { transform: scale(1.5); opacity: 0; } /* 反馈图片样式 */ .feedback-image { position: absolute; transform: translate(-50%, -50%); width: 250px; height: 250px; object-fit: contain; z-index: 10; } .correct-feedback-left { top: 85%; left: 20%; animation: popIn 0.6s cubic-bezier(0.175, 0.885, 0.32, 1.275); } .correct-feedback-right { top: 85%; left: 80%; animation: popIn 0.6s cubic-bezier(0.175, 0.885, 0.32, 1.275); } .incorrect-feedback-left { top: 85%; left: 20%; animation: shake 0.8s cubic-bezier(0.36, 0.07, 0.19, 0.97); } .incorrect-feedback-right { top: 85%; left: 80%; animation: shake 0.8s cubic-bezier(0.36, 0.07, 0.19, 0.97); } /* 动画效果 */ @keyframes popIn { 0% { transform: translate(-50%, -50%) scale(0.5); opacity: 0; } 70% { transform: translate(-50%, -50%) scale(1.1); opacity: 1; } 100% { transform: translate(-50%, -50%) scale(1); } } @keyframes shake { 0%, 100% { transform: translate(-50%, -50%); } 10%, 30%, 50%, 70%, 90% { transform: translate(-52%, -50%); } 20%, 40%, 60%, 80% { transform: translate(-48%, -50%); } } .fade-enter-active, .fade-leave-active { transition: opacity 0.5s; } .fade-enter-from, .fade-leave-to { opacity: 0; } /* 响应式设计 */ @media (max-width: 768px) { .question-image { width: 90%; height: 150px; } .move-image { width: 120px; height: 120px; } .option-btn { padding: 15px 30px; font-size: 18px; } } @media (max-width: 480px) { .question-container { padding-top: 20px; } .question-image { height: 120px; } .move-image { width: 100px; height: 100px; } .option-btn { padding: 12px 25px; font-size: 16px; } .feedback-image { width: 180px; height: 180px; } .example-showcase .el-dropdown + .el-dropdown { margin-left: 15px; } .example-showcase .el-dropdown-link { cursor: pointer; color: var(--el-color-primary); display: flex; align-items: center; } } .select-question{ width: 100px; padding-left: 0px; } </style> 调整合适的比例放在一个页面上展示
最新发布
08-14
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值