解决 css 不同宽高下,DIV背景图片变形的问题 - 工作记录

最近项目有一个需求

这个项目类似大屏可视化,用到了不规则图片的div 背景,部分UI如图
在这里插入图片描述

遇到的问题

因为项目内容比较多,这种卡片的情况不同,宽高都不是固定的,所以直接把图片动态宽高的话会导致图片拉伸变形,根据每个宽高让UI老师切图也是不现实的,效率很低!

解决办法 - 做一个组件

  1. 首先找UI老师要一张这个背景图片 最高 和 最宽 的可能的背景图片,我要的是 960px * 960px 的,4个角固定,不随整体宽高做适配 dialog.jpg
    在这里插入图片描述
    2.新建 div 的四个角的子div,用 css 的 background-position
    css 的 background-position 切出 四个角

background-position 用来设置背景图像起始位置的CSS样式属性
background-position 配合 最高 最宽的背景图片,可以使四个角的样式不变形

  • 新建 TopLeft、TopRight、BottomRight、BottomLeft 四个角的div,分别定位到父div 的四个角
    在这里插入图片描述
  • 然后根据 background-position 分别从不同位置开始延伸宽高来拼凑样式,
    height: calc(100% - 100px);
    width: calc(100% - 100px);
    延伸的顺序不能重了,要不会出现样式重叠的情况

错误的
在这里插入图片描述
正确代码

<template>
  <div id="CustomDialog" :class="data.dialogClass" class="CustomDialog" :style="props.style">
    <div v-if="data.dialogClass === 'upgradeClass'" class="background_style">
      <div class="TopLeft"></div>
      <div class="TopRight"></div>
      <div class="BottomRight"></div>
      <div class="BottomLeft"></div>
    </div>
    <div class="content">
      <slot></slot>
    </div>
  </div>
</template>

<script lang="ts" setup>
  import { onMounted, reactive, defineProps } from 'vue'
  interface IProps {
    style: {
      width: string
      height: string
    }
  }
  const props = defineProps<IProps>()
  const data = reactive({
    dialogClass: '',
  })
  onMounted(() => {
    let dom = document.getElementById('CustomDialog') as HTMLElement
    let width = parseInt(dom.style.width.replace('px', ''))
    let height = parseInt(dom.style.height.replace('px', ''))
    if (width < 340 && height < 145) {
      data.dialogClass = 'simpleClass'
    } else {
      data.dialogClass = 'upgradeClass'
    }
  })
</script>
<style lang="less" scoped>
  .simpleClass {
    background: rgba(6, 21, 43, 0.75) !important;
    border: 1px solid #1fb8c5 !important;
    box-shadow: 0px 2px 8px 0px rgba(161, 234, 240, 0.44) !important;
    border-radius: 3px;
    .content {
      padding: 8px !important;
    }
  }
  .CustomDialog {
    position: relative;
    .background_style {
      position: absolute;
      z-index: -1;
      width: 100%;
      height: 100%;
      .TopLeft {
        background-image: url('/@/assets/dialog.jpg');
        position: absolute;
        background-position: top left;
        top: 0;
        left: 0;
        width: 100px;
        height: 100px;
      }
      .TopRight {
        background-image: url('/@/assets/dialog.jpg');
        position: absolute;
        background-position: top right;
        top: 0;
        right: 0;
        width: calc(100% - 100px);
        height: calc(100% - 100px);
      }
      .BottomRight {
        background-image: url('/@/assets/dialog.jpg');
        position: absolute;
        background-position: bottom right;
        bottom: 0;
        right: 0;
        width: calc(100% - 100px);
        height: 100px;
      }
      .BottomLeft {
        background-image: url('/@/assets/dialog.jpg');
        position: absolute;
        background-position: bottom left;
        bottom: 0;
        left: 0;
        width: 100px;
        height: calc(100% - 100px);
      }
    }
    .content {
      color: #1ae7f8;
      text-align: left;
      padding: 16px;
      position: absolute;
      width: 100%;
      height: 100%;
      z-index: 1;
    }
  }
</style>

3.使用组件

<template>
  <div>
    <CustomDialog :style="{ width: '340px', height: '145px' }">
      <div>123</div> 
    </CustomDialog>
  </div>
</template>

<script lang="ts" setup>
  import { onMounted, reactive } from 'vue'
  import CustomDialog from '/@/components/CustomDialog.vue'

  const data = reactive({})
  onMounted(() => {})
</script>
<style scoped></style>

在这里插入图片描述

  1. 上面我又多做了一个判断,如果宽高小于 340 和 145 ,也会导致 样式变形,340 和 145 是根据 右上角最小的宽度 + 左上角的宽度算出的,宽度也是如此

在这里插入图片描述
所以在 小于 指定宽高之后就取消背景图显示,给他用css 代码来实现简单的样式

.simpleClass {
    background: rgba(6, 21, 43, 0.75) !important;
    border: 1px solid #1fb8c5 !important;
    box-shadow: 0px 2px 8px 0px rgba(161, 234, 240, 0.44) !important;
    border-radius: 3px;
    .content {
      padding: 8px !important;
    }
  }

在这里插入图片描述
完整代码

<template>
  <div>
    <CustomDialog :style="{ width: '300px', height: '120px' }"><div>123</div> </CustomDialog>
  </div>
</template>

<script lang="ts" setup>
  import { onMounted, reactive } from 'vue'
  import CustomDialog from '/@/components/CustomDialog.vue'

  const data = reactive({})
  onMounted(() => {})
</script>
<style scoped></style>
<template>
  <div id="CustomDialog" :class="data.dialogClass" class="CustomDialog" :style="props.style">
    <div v-if="data.dialogClass === 'upgradeClass'" class="background_style">
      <div class="TopLeft"></div>
      <div class="TopRight"></div>
      <div class="BottomRight"></div>
      <div class="BottomLeft"></div>
    </div>
    <div class="content">
      <slot></slot>
    </div>
  </div>
</template>

<script lang="ts" setup>
  import { onMounted, reactive, defineProps } from 'vue'
  interface IProps {
    style: {
      width: string
      height: string
    }
  }
  const props = defineProps<IProps>()
  const data = reactive({
    dialogClass: 'upgradeClass',
  })
  onMounted(() => {
    let dom = document.getElementById('CustomDialog') as HTMLElement
    let width = parseInt(dom.style.width.replace('px', ''))
    let height = parseInt(dom.style.height.replace('px', ''))
    if (width < 340 && height < 145) {
      data.dialogClass = 'simpleClass'
    } else {
      data.dialogClass = 'upgradeClass'
    }
  })
</script>
<style lang="less" scoped>
  .simpleClass {
    background: rgba(6, 21, 43, 0.75) !important;
    border: 1px solid #1fb8c5 !important;
    box-shadow: 0px 2px 8px 0px rgba(161, 234, 240, 0.44) !important;
    border-radius: 3px;
    .content {
      padding: 8px !important;
    }
  }
  .CustomDialog {
    position: relative;
    .background_style {
      position: absolute;
      z-index: -1;
      width: 100%;
      height: 100%;
      .TopLeft {
        background-image: url('/@/assets/dialog.jpg');
        position: absolute;
        background-position: top left;
        top: 0;
        left: 0;
        width: 100px;
        height: 100px;
      }
      .TopRight {
        background-image: url('/@/assets/dialog.jpg');
        position: absolute;
        background-position: top right;
        top: 0;
        right: 0;
        width: calc(100% - 100px);
        height: calc(100% - 100px);
        //width: 300px;
        //height: 100px;
      }
      .BottomRight {
        background-image: url('/@/assets/dialog.jpg');
        position: absolute;
        background-position: bottom right;
        bottom: 0;
        right: 0;
        width: calc(100% - 100px);
        height: 100px;
      }
      .BottomLeft {
        background-image: url('/@/assets/dialog.jpg');
        position: absolute;
        background-position: bottom left;
        bottom: 0;
        left: 0;
        width: 100px;
        height: calc(100% - 100px);
        //height: 100px;
      }
    }
    .content {
      color: #1ae7f8;
      text-align: left;
      padding: 16px;
      position: absolute;
      width: 100%;
      height: 100%;
      z-index: 1;
    }
  }
</style>

我的掘金地址:https://juejin.cn/user/3826767556515063/posts

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值