当前位置: 首页 > article >正文

CSS线性渐变拼接,一个完整的渐变容器(div),要拆分成多个渐变容器(div),并且保持渐变效果一致

1 需求

一个有渐变背景的div,需要替换成多个渐变背景div拼接,渐变效果需要保持一致(不通过一个大的div渐变,其他子的div绝对定位其上并且背景透明来解决)

2 分析

主要工作:

  1. 计算完整div背景线性渐变时的渐变开始线和结束线(假设中心点为几何中心)
  2. 计算各个独立div背景线性渐变时的渐变开始线和结束线(假设中心点为几何中心)
  3. 重新计算各个子div的渐变开始线和结束线(百分比)

3 实现

3.1 水平拼接

在这里插入图片描述

解释:

  • 黑色虚线为各个子div的水平和垂直中心线
  • 红色虚线为整个div的水平和垂直中心线
  • 绿色虚线为渐变方向上的中心线,和黑色虚线的夹角为各个子div的渐变角
  • 紫色虚线为渐变方向上的中心线,和红色虚线的夹角为整个div的渐变角
  • 蓝色虚线为渐变开始线和结束线,垂直于渐变方向上的中心线
  • 蓝色圆为各个子div独立渐变时的渐变起始中心点,绿色圆为各个子div独立渐变时的渐变结束中心点
  • 紫色圆为整个div的渐变起始中心点,红色圆为整个div的渐变结束中心点
  • 蓝色紫色双圆为当前子div独立渐变时和其作为整个div整体渐变的一部分时的共同渐变起始中心点,是重合的
  • 绿色红色双圆为当前子div独立渐变时和其作为整个div整体渐变的一部分时的共同渐变结束中心点,是重合的
  • 蓝色实线段为整个渐变路径,其长度为渐变长度,也就是颜色值后面的参数0-100%
  • 绿色实线段为为了作为整体渐变一部分而需要增加的渐变路径
<template>
  <div class="container gradient"></div>
  <div class="container">
    <div
      class="container-column"
      v-for="(col, index) in itemList"
      :key="index"
      :style="{
        width: col.width + 'px',
        height: col.height + 'px',
        background: getGradient(col, index)
      }"
    ></div>
  </div>
</template>

<script setup lang="ts">
const itemList = ref([
  {
    width: 100,
    height: 400
  },
  {
    width: 200,
    height: 400
  },
  {
    width: 300,
    height: 400
  }
]);
const angle = ref(45);

const getGradient = (item, index) => {
  const beforeWidth = itemList.value.slice(0, index).reduce((a, b) => a + b.width, 0);
  const afterWidth = itemList.value.slice(index + 1).reduce((a, b) => a + b.width, 0);
  const startPosition = `calc(100% - (${beforeWidth} * sin(${angle.value}deg) / (2 * (${item.width / 2} * tan(${angle.value}deg) + ${item.height / 2}) * cos(${angle.value}deg)) + 1) * 100%)`;
  const endPosition = `calc((${afterWidth} * sin(${angle.value}deg) / (2 * (${item.width / 2} * tan(${angle.value}deg) + ${item.height / 2}) * cos(${angle.value}deg)) + 1) * 100%)`;
  const ret = `linear-gradient(${angle.value}deg,
        red ${startPosition},
        blue ${endPosition}
      )`;
  return ret;
};
</script>
<style scoped lang="scss">
.container {
  width: 600px;
  height: 400px;
  display: inline-block;

  .container-column {
    display: inline-block;
  }
}
.gradient {
  background: linear-gradient(45deg, red 0%, blue 100%);
}
</style>


效果:

在这里插入图片描述

加上边框更清晰点:

在这里插入图片描述

3.2 垂直拼接

在这里插入图片描述

解释:

  • 黑色虚线为各个子div的水平和垂直中心线
  • 红色虚线为整个div的水平和垂直中心线
  • 绿色虚线为渐变方向上的中心线,和黑色虚线的夹角为各个子div的渐变角
  • 紫色虚线为渐变方向上的中心线,和红色虚线的夹角为整个div的渐变角
  • 蓝色虚线为渐变开始线和结束线,垂直于渐变方向上的中心线
  • 蓝色圆为各个子div独立渐变时的渐变起始中心点,绿色圆为各个子div独立渐变时的渐变结束中心点
  • 紫色圆为整个div的渐变起始中心点,红色圆为整个div的渐变结束中心点
  • 蓝色紫色双圆为当前子div独立渐变时和其作为整个div整体渐变的一部分时的共同渐变起始中心点,是重合的
  • 绿色红色双圆为当前子div独立渐变时和其作为整个div整体渐变的一部分时的共同渐变结束中心点,是重合的
  • 蓝色实线段为整个渐变路径,其长度为渐变长度,也就是颜色值后面的参数0-100%
  • 绿色实线段为为了作为整体渐变一部分而需要增加的渐变路径
<template>
  <div class="container gradient"></div>
  <div class="container">
    <div
      class="container-column"
      v-for="(col, index) in itemList"
      :key="index"
      :style="{
        width: col.width + 'px',
        height: col.height + 'px',
        background: getGradient(col, index)
      }"
    ></div>
  </div>
</template>

<script setup lang="ts">
const itemList = ref([
  {
    width: 400,
    height: 100
  },
  {
    width: 400,
    height: 200
  },
  {
    width: 400,
    height: 300
  },
  {
    width: 400,
    height: 300
  }
]);
const angle = ref(45);

const getGradient = (item, index) => {
  const afterHeight = itemList.value.slice(0, index).reduce((a, b) => a + b.height, 0);
  const beforeHeight = itemList.value.slice(index + 1).reduce((a, b) => a + b.height, 0);
  const startPosition = `calc(100% - (${beforeHeight} * cos(${angle.value}deg) / (2 * (${item.width / 2} * tan(${angle.value}deg) + ${item.height / 2}) * cos(${angle.value}deg)) + 1) * 100%)`;
  const endPosition = `calc((${afterHeight} * cos(${angle.value}deg) / (2 * (${item.width / 2} * tan(${angle.value}deg) + ${item.height / 2}) * cos(${angle.value}deg)) + 1) * 100%)`;
  const ret = `linear-gradient(${angle.value}deg,
        red ${startPosition},
        blue ${endPosition}
      )`;
  return ret;
};
</script>
<style scoped lang="scss">
.container {
  width: 400px;
  height: 900px;
  display: inline-block;
  & + .container {
    margin-left: 10px;
  }
  line-height: 0;
  .container-column {
    display: inline-block;
  }
}
.gradient {
  background: linear-gradient(45deg, red 0%, blue 100%);
}
</style>

</style>


效果:

在这里插入图片描述

加上边框更清晰点:

在这里插入图片描述

3.3 矩阵拼接

在这里插入图片描述

图上画线太多,下图画个稍微简明点的

在这里插入图片描述

解释:

  • 黑色虚线为各个子div的水平和垂直中心线
  • 红色虚线为整个div的水平和垂直中心线
  • 绿色虚线为渐变方向上的中心线,和黑色虚线的夹角为各个子div的渐变角
  • 紫色虚线为渐变方向上的中心线,和红色虚线的夹角为整个div的渐变角
  • 蓝色虚线为渐变开始线和结束线,垂直于渐变方向上的中心线
  • 蓝色圆为各个子div独立渐变时的渐变起始中心点,绿色圆为各个子div独立渐变时的渐变结束中心点
  • 紫色圆为整个div的渐变起始中心点,红色圆为整个div的渐变结束中心点
  • 蓝色紫色双圆为当前子div独立渐变时和其作为整个div整体渐变的一部分时的共同渐变起始中心点,是重合的
  • 绿色红色双圆为当前子div独立渐变时和其作为整个div整体渐变的一部分时的共同渐变结束中心点,是重合的
  • 蓝色实线段为整个渐变路径,其长度为渐变长度,也就是颜色值后面的参数0-100%
  • 绿色实线段为为了作为整体渐变一部分而需要增加的渐变路径
<template>
  <div class="container gradient"></div>
  <div class="container">
    <div class="container-row" v-for="(row, rowIndex) in itemList" :key="rowIndex">
      <div
        class="container-column"
        v-for="(col, colIndex) in row"
        :key="colIndex"
        :style="{
          width: col.width + 'px',
          height: col.height + 'px',
          background: getGradient(col, colIndex, rowIndex)
        }"
      ></div>
    </div>
  </div>
</template>

<script setup lang="ts">
const itemList = ref([
  [
    {
      width: 100,
      height: 100
    },
    {
      width: 300,
      height: 100
    }
  ],
  [
    {
      width: 200,
      height: 200
    },
    {
      width: 100,
      height: 200
    },
    {
      width: 100,
      height: 200
    }
  ],
  [
    {
      width: 100,
      height: 300
    },
    {
      width: 100,
      height: 300
    },
    {
      width: 100,
      height: 300
    },
    {
      width: 100,
      height: 300
    }
  ],
  [
    {
      width: 400,
      height: 300
    }
  ]
]);
const angle = ref(45);

const getGradient = (item, colIndex, rowIndex) => {
  const afterHeight = itemList.value.slice(0, rowIndex).reduce((a, b) => a + b[0].height, 0);
  const beforeHeight = itemList.value.slice(rowIndex + 1).reduce((a, b) => a + b[0].height, 0);
  const beforeWidth = itemList.value[rowIndex].slice(0, colIndex).reduce((a, b) => a + b.width, 0);
  const afterWidth = itemList.value[rowIndex].slice(colIndex + 1).reduce((a, b) => a + b.width, 0);
  const startPosition = `calc(100% - ((${beforeHeight} * cos(${angle.value}deg) + ${beforeWidth} * sin(${angle.value}deg))/ (2 * (${item.width / 2} * tan(${angle.value}deg) + ${item.height / 2}) * cos(${angle.value}deg)) + 1) * 100%)`;
  const endPosition = `calc(((${afterHeight} * cos(${angle.value}deg) + ${afterWidth} * sin(${angle.value}deg)) / (2 * (${item.width / 2} * tan(${angle.value}deg) + ${item.height / 2}) * cos(${angle.value}deg)) + 1) * 100%)`;
  const ret = `linear-gradient(${angle.value}deg,
        red ${startPosition},
        blue ${endPosition}
      )`;
  return ret;
};
</script>
<style scoped lang="scss">
.container {
  width: 400px;
  height: 900px;
  display: inline-block;
  & + .container {
    margin-left: 10px;
  }
  .container-row {
    line-height: 0;
    .container-column {
      display: inline-block;
    }
  }
}
.gradient {
  background: linear-gradient(45deg, red 0%, blue 100%);
}
</style>


效果:

在这里插入图片描述

加上边框更清晰点:

在这里插入图片描述

4 最后

还可以有更复杂的情况:

  • 矩阵中的跨行跨列,大家可自行探索(其实投篮的办法是可以把跨行跨列的单元再进行拆分,使得所有单元都不出现跨行跨列,那么上面第三种矩阵拼接就可以使用了)
  • 多个颜色(中间的颜色需要根据当前百分比位置和增加的距离得到最终的百分比位置)
  • 非线性渐变的情况(感觉稍微有点复杂)

http://www.kler.cn/news/284263.html

相关文章:

  • YeAudio音频工具的介绍和使用
  • 【系统架构设计师】论文:论需求分析方法及应用
  • TCP/IP五层模型
  • 算法学习:一维数组的排序算法
  • 深入解析 Spring Boot 中 MyBatis 自动配置的流程
  • Python 如何操作 Excel 文件(openpyxl, xlrd)
  • 计算机学习
  • java框架第二课(Reflection反射机制)
  • 最短路算法详解(Dijkstra 算法,Bellman-Ford 算法,Floyd-Warshall 算法)
  • 【手机取证】智能手机位置数据提取方法
  • 《黑神话:深度探索与攻略指南》——虎先锋隐藏门在哪里
  • Python生成指定数量的随机XML文件
  • 华为云征文|部署私有云和文档管理系统 Kodcloud
  • 利用流水线实现版本一键发布
  • 【生日视频制作】奔驰梅赛德斯小汽车提车交车仪式AE模板修改文字软件生成器教程特效素材【AE模板】
  • 【精选】基于Hadoop的热点事件分析的设计与实现(全网最新定制,独一无二)
  • (最新)华为 2024 届秋招-硬件技术工程师-单板硬件开发—机试题—(共12套)(每套四十题)
  • deepin(深度)社区亮相2024 RISC-V中国峰会,全力推动RISC-V生态发展
  • Python中的“for循环”:探索其无限潜力
  • 别让努力付之东流!私域增长停滞不前的7大冲突解析
  • ThermoParser 介绍
  • 【设计模式-代理】
  • Java算法之选择排序(Selection Sort)
  • 神经网络—卷积层
  • Zookeeper的监听机制及原理解析
  • Selenium 自动化测试框架 API 详解
  • Nginx中的权重轮询机制:实现高效负载均衡
  • 使用Lora微调LLM——笔记
  • EmguCV学习笔记 VB.Net 第9章 视频操作
  • maven的5种打包方式:springboot-maven-plugin详解