HTML + CSS 创建图片倒影的 5 种方法

HTML + CSS 创建图片倒影的 5 种方法

目标:掌握多种生成“图片倒影 / Reflection”效果的实现思路,理解兼容性、性能差异与最佳实践,方便在真实业务(商品展示、相册、登陆页面视觉强化)中安全使用。


总览对比

方法核心技术代码量兼容性动态内容适配可控性适用场景
1. -webkit-box-reflect私有 CSS 属性最少仅 WebKit (Chrome / Safari / Edge)自动快速 Demo / 营销页
2. 伪元素 + transform: scaleY(-1)标准 CSS所有现代浏览器良好高(可自定义遮罩)通用首选
3. 伪元素 + mask-image / -webkit-maskCSS MaskSafari / Chromium (Firefox 部分实验)良好很高(渐隐更自然)高端展示
4. SVG 复制 + 渐变遮罩内联 SVG全面 (IE 除外)良好很高(滤镜/形变)复杂视觉 / 批量渲染
5. Canvas 二次绘制<canvas>全面需手动重绘最高(像素级)动态生成 / 后处理

选择建议:

  1. 追求最少代码 & 不顾部分浏览器:用 1。
  2. 需要兼容性 + 易维护:用 2。
  3. 想要柔和渐隐过渡、无多余 DOM:用 3。
  4. 大型可视化 / 复杂滤镜链:用 4。
  5. 需要最终导出合成图 / 动态内容(如生成分享海报):用 5。

方法一:-webkit-box-reflect(最简单 / 兼容性受限)

<style>.reflect-webkit {width: 240px;-webkit-box-reflect: below 6px linear-gradient(to bottom, rgba(0, 0, 0, 0.25), transparent70%);}
</style>
<img class="reflect-webkit" src="demo.jpg" alt="Product" />

说明:

  • 语法:-webkit-box-reflect: <direction> <offset> <mask>
  • linear-gradient 充当倒影的渐隐遮罩。
    优点:单行 + 自动跟随宽高。
    缺点:仅 WebKit 内核(Firefox 不支持)。
    适合:临时视觉增强、非核心信息。

方法二:伪元素复制 + 反转(推荐通用方案)

思路:利用容器包裹图片,伪元素 ::after 再绘制同一张图像,垂直翻转并添加渐变。

<div class="reflection-box"><img src="demo.jpg" alt="Phone" />
</div><style>.reflection-box {position: relative;width: 240px;}.reflection-box img {display: block;width: 100%;}.reflection-box::after {content: '';position: absolute;left: 0;right: 0;top: 100%;height: 100%;background: url('demo.jpg') center/cover no-repeat;transform: scaleY(-1);transform-origin: top;opacity: 0.6;/* 渐隐叠加 */mask-image: linear-gradient(to bottom,rgba(0, 0, 0, 0.8),rgba(0, 0, 0, 0));-webkit-mask-image: linear-gradient(to bottom,rgba(0, 0, 0, 0.8),rgba(0, 0, 0, 0));}
</style>

处理动态 src:

  • 如果图片 URL 需动态绑定,可用行内 style="--src:url('xxx')" + background: var(--src) 或用 JS 设置伪元素。
  • 亦可直接复制 <img> 节点再 scaleY(-1),如下:
<div class="reflect-wrap"><img src="demo.jpg" alt="Phone" class="origin" /><img src="demo.jpg" alt="Phone reflection" class="mirror" />
</div><style>.reflect-wrap {width: 240px;position: relative;}.reflect-wrap .origin {display: block;width: 100%;}.reflect-wrap .mirror {display: block;width: 100%;transform: scaleY(-1);transform-origin: top;margin-top: 6px;mask-image: linear-gradient(to bottom, rgba(0, 0, 0, 0.6), transparent);-webkit-mask-image: linear-gradient(to bottom,rgba(0, 0, 0, 0.6),transparent);opacity: 0.8;}
</style>

优点:标准、兼容好、可扩展。
注意:双份图片会触发两次解码,可用 <img decoding="async" loading="lazy"> 或复用绘制(JS 画到 canvas 再生成 DataURL)。


方法三:伪元素 + Mask(强化渐隐 & 灵活形状)

核心区别:不直接复制图片,而是使用 CSS 变量引用同一来源,搭配 mask-image 形成更可控的透明衰减(可变换曲线)。

<figure class="mask-reflect" style="--src:url('demo.jpg')"><img src="demo.jpg" alt="Laptop" />
</figure><style>.mask-reflect {position: relative;width: 260px;}.mask-reflect img {width: 100%;display: block;}.mask-reflect::after {content: '';position: absolute;inset: 0;top: 100%;height: 100%;background: var(--src) center/cover no-repeat;transform: scaleY(-1);transform-origin: top;/* 自定义遮罩——使用非线性渐变模拟更柔的衰减 */mask-image: linear-gradient(to bottom,rgba(0, 0, 0, 0.9) 0%,rgba(0, 0, 0, 0.4) 35%,rgba(0, 0, 0, 0.15) 60%,rgba(0, 0, 0, 0) 100%);-webkit-mask-image: linear-gradient(to bottom,rgba(0, 0, 0, 0.9) 0%,rgba(0, 0, 0, 0.4) 35%,rgba(0, 0, 0, 0.15) 60%,rgba(0, 0, 0, 0) 100%);opacity: 0.85;filter: blur(0.4px) saturate(0.95);}
</style>

拓展:

  • 横向拉伸 / 倾斜效果:附加 transform: scaleY(-1) skewX(3deg);
  • 波纹倒影:叠加 filter: url(#turbulence)(需 SVG filter)。

方法四:SVG 复制 + 渐变遮罩

适合批量渲染(一个 SVG 中包含多个倒影)或需要滤镜(模糊、色偏、波浪)。

<svg width="260" viewBox="0 0 260 360" class="svg-reflect"><defs><linearGradient id="fade" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="black" stop-opacity="0.8" /><stop offset="70%" stop-color="black" stop-opacity="0" /></linearGradient><mask id="mask-fade" maskUnits="userSpaceOnUse"><rect x="0" y="180" width="260" height="180" fill="url(#fade)" /></mask></defs><!-- 原图 --><image href="demo.jpg" x="0" y="0" width="260" height="180" /><!-- 倒影 --><g transform="translate(0,180) scale(1,-1)" mask="url(#mask-fade)"><image href="demo.jpg" x="0" y="0" width="260" height="180" opacity="0.9" /></g>
</svg>

优点:

  • 所有可视操作可在 SVG 内完成(模糊、波纹、颜色矩阵)。
  • 单文件可复制多份资源。
    缺点:语法冗长;与普通 DOM 混排需处理层级。

扩展滤镜(波纹):

<filter id="ripple" x="-20%" y="-20%" width="140%" height="140%"><feTurbulence baseFrequency="0.01 0.15" numOctaves="2" result="turb"/><feDisplacementMap in2="turb" in="SourceGraphic" scale="6" xChannelSelector="R" yChannelSelector="G"/>
</filter>

然后在倒影 <g> 里加 filter="url(#ripple)"


方法五:Canvas 动态绘制(可导出 / 像素级)

适合:

  • 需要合成单张最终图(下载 / 分享)。
  • 倒影需要与原图进行额外像素操作(模糊、曲面映射、噪声)。
<canvas id="c" width="260" height="360"></canvas>
<script>const img = new Image();img.src = 'demo.jpg';img.onload = () => {const h = 180;const w = 260;const canvas = document.getElementById('c');const ctx = canvas.getContext('2d');// 原图ctx.drawImage(img, 0, 0, w, h);// 倒影:缩放坐标系ctx.save();ctx.translate(0, h * 2); // 移到下面ctx.scale(1, -1);ctx.drawImage(img, 0, 0, w, h);ctx.restore();// 渐隐:创建渐变遮罩const gradient = ctx.createLinearGradient(0, h, 0, h * 2);gradient.addColorStop(0, 'rgba(0,0,0,0.6)');gradient.addColorStop(0.7, 'rgba(0,0,0,0)');ctx.globalCompositeOperation = 'destination-in';ctx.fillStyle = gradient;ctx.fillRect(0, h, w, h);ctx.globalCompositeOperation = 'source-over';};
</script>

延伸:

  • 添加 Blur:使用离屏 canvas 再 ctx.filter = 'blur(2px)'
  • 曲面:对每一行像素裁剪后重新绘制(实现较复杂)。
  • 封装为函数供多个图片批量处理。

性能与内存考量

关注点说明建议
重复解码伪元素背景与 <img> 均触发使用缓存(同 src 浏览器已缓存),或使用单 <img>+CSS 复制(方法二第二种 DOM 方式)
Reflow倒影高度改变影响布局给容器固定高度 / 使用绝对定位避免抖动
重绘成本CSS 滤镜 / SVG 滤镜会增加渲染成本降低滤镜强度;按需加载(IntersectionObserver)
Canvas 占用多张大图 + 离屏操作控制尺寸,复用 canvas
动态数据src 频繁变化Debounce 更新;避免在视口外构建倒影

常见坑 & 解决方案

问题场景解决
图片加载时闪烁背景方式倒影先出现空白onload 后再添加反射 class
高 DPI 模糊Canvas 导出在 Retina 模糊canvas.width = cssWidth * devicePixelRatio 再缩放绘制
Mask 失效Firefox 对 mask-image 支持差异降级:在 Firefox 检测后改用透明渐变 PNG 覆盖
滤镜太重卡顿多个 blur(8px)降级为较小 blur + opacity
SEO 影响额外 <img> 计入图片索引第二种 DOM 复制时给倒影图 aria-hidden="true" + alt=""

可复用 CSS 片段(方法二封装)

.reflect {position: relative;display: inline-block;
}
.reflect > img {display: block;
}
.reflect::after {content: '';position: absolute;left: 0;right: 0;top: 100%;height: var(--reflect-height, 100%);background: var(--reflect-src) center/contain no-repeat;transform: scaleY(-1);transform-origin: top;opacity: var(--reflect-opacity, 0.7);mask-image: linear-gradient(to bottom, rgba(0, 0, 0, 0.9), transparent);-webkit-mask-image: linear-gradient(to bottom,rgba(0, 0, 0, 0.9),transparent);
}

使用:

<divclass="reflect"style="--reflect-src:url('demo.jpg'); --reflect-height:100%; --reflect-opacity:.6"
><img src="demo.jpg" alt="Phone" />
</div>

JS 动态设置:

const wrap = document.querySelector('.reflect');
const img = wrap.querySelector('img');
img.addEventListener('load', () => {wrap.style.setProperty('--reflect-src',`url('${img.currentSrc || img.src}')`);
});

进阶创意玩法

创意说明关键点
波浪倒影倒影加 feTurbulence 位移SVG 过滤或 Canvas 位移
动态闪光倒影上加渐变动画keyframes 改变 mask 的角度
颜色偏移倒影轻微冷色filter: hue-rotate(5deg) saturate(.9)
模糊加速滚动远离时加大模糊IntersectionObserver + class 切换
多层折射多个伪元素多次缩放性能注意:限制层数

选择决策树(简化)

  1. 是否需要导出最终合成图?→ 是:Canvas。
  2. 是否需要复杂滤镜 / 波纹?→ 是:SVG / Canvas。
  3. 是否关键页面全平台必须统一?→ 是:伪元素方案。
  4. 是否只是临时视觉点缀且不在意 Firefox?→ -webkit-box-reflect
  5. 想要更丝滑衰减边缘?→ 增强 Mask(方法三)。

快速小抄(Cheat Sheet)

目标推荐代码片段
最快 Demo-webkit-box-reflect: below 4px linear-gradient(...)
通用实现伪元素 + scaleY(-1) + mask-image
柔和渐隐多段 stop 的 linear-gradient 遮罩
波纹特效SVG feTurbulence + feDisplacementMap
导出图片Canvas 绘制 + toDataURL()
性能优化只为首屏可见元素添加倒影 / 复用 src

总结

图片倒影本质是:复制 → 翻转 → 衰减透明度 +(可选)附加滤镜。选型关键在 兼容性、性能、是否需后处理 / 导出、视觉精细度 之间的平衡。实际项目中建议封装成组件(接收:图片源、倒影高度、衰减曲线、滤镜强度),统一管理,避免随处散落临时写法。

思路优先,技巧其次。掌握“复制 + 翻转 + 遮罩”内核,再延伸任意创意。

(完)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/921294.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/921294.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

一个文件被打开io流和不打卡 inode

1. 磁盘 最小基本单位 扇区 机器磁盘的io效率 &#xff08;读和取&#xff09;2. 文件系统 对磁盘分区 &#xff0c;最小的文件单位块组&#xff0c;快组内部已经划分好区域&#xff0c;巴拉巴拉&#xff0c;总之&#xff0c;每次使用数据&#xff0c;以操作系统的处理都是块级…

ThermoSeek:热稳定蛋白数据库

这篇论文提出了ThermoSeek&#xff0c;一个综合性的网络资源&#xff0c;用于分析来自嗜热和嗜冷物种的蛋白质序列和结构。具体来说&#xff0c;数据收集&#xff1a;从美国国家生物技术信息中心&#xff08;NCBI&#xff09;的基因组数据库中收集了物种的分类ID&#xff0c;并…

leetcode算法刷题的第二十七天

1.leetcode 56.合并区间 题目链接 class Solution { public:static bool cmp(const vector<int>& a,const vector<int>& b){return a[0]<b[0];}vector<vector<int>> merge(vector<vector<int>>& intervals) {vector<v…

解决 Apache/WAF SSL 证书链不完整导致的 PKIX path building failed 问题

文章目录解决 Apache/WAF SSL 证书链不完整导致的 PKIX path building failed 问题为什么会出现证书链错误&#xff1f;常见场景直连服务器正常&#xff0c;但经过 WAF 出错Windows/Linux 下证书文件说明引入 WAF 或其他中间层&#xff1a;解决方法方法一&#xff1a;单独配置 …

十一、标准化和软件知识产权基础知识

1 标准化基础知识 1.1 基本概念 1.1.1 标准的分类 1.1.1.1 按使用范围分类 国际标准&#xff1a;由国际组织如 ISO、IEC 制定的标准。国家标准&#xff1a;由国家标准化机构制定的标准&#xff0c;如中国的 GB&#xff0c;美国 ANSI。行业标准&#xff1a;由行业主管部门制定的…

计算机毕设选题:基于Python数据挖掘的高考志愿推荐系统

精彩专栏推荐订阅&#xff1a;在 下方专栏&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f496;&#x1f525;作者主页&#xff1a;计算机毕设木哥&#x1f525; &#x1f496; 文章目录 一、项目介绍二…

什么是PCB工艺边?猎板给您分享设计要点

什么是PCB工艺边&#xff1f;猎板给您分享设计要点在PCB设计和制造领域&#xff0c;工艺边是一个看似简单却至关重要的概念&#xff0c;它直接关系到生产流程的顺畅性与最终产品的质量。本文将为您详细解析PCB工艺边的定义、作用、设计要点&#xff0c;并分享猎板PCB在高精度制…

Rustdesk搭建与客户端修改与编译

Rustdesk是一个开源的远程桌面工具&#xff0c;客户端可以自己定制修改编译 这里主要记录一下搭建的过程 服务端搭建 主要是参考了这篇文章&#xff0c;感觉作者分享~ 在 Linux VPS 上创建 RustDesk 服务器 - 知乎 https://zhuanlan.zhihu.com/p/1922729751656765374 这里主要…

数字人系统源码搭建与定制化开发:从技术架构到落地实践

随着元宇宙、直播电商、智能客服等领域的爆发&#xff0c;数字人从概念走向商业化落地&#xff0c;其定制化需求也从 “单一形象展示” 升级为 “多场景交互能力”。本文将从技术底层出发&#xff0c;拆解数字人系统的源码搭建逻辑&#xff0c;结合定制化开发中的核心痛点&…

2025国赛C题创新论文+代码可视化 NIPT 的时点选择与胎儿的异常判定

2025国赛C题创新论文代码可视化 NIPT 的时点选择与胎儿的异常判定基于多通道LED光谱优化的人体节律调节与睡眠质量评估模型摘要无创产前检测&#xff08;NIPT&#xff09;通过分析孕妇血浆中胎儿游离DNA来筛查染色体异常&#xff0c;其准确性很大程度上依赖于胎儿Y染色体浓度的…

2021/07 JLPT听力原文 问题一 4番

4番&#xff1a;女の人が新しい商品の紹介をしています。よく頭が痛くなる人は、どの商品を選びますか。女&#xff1a;こちら、新発売の中国茶をご案内します。今回皆様にご紹介いたしますのは、月・星・虹・空のお茶の4種類でございます。さあ、どうぞ召し上がってください。…

爆改YOLOv8 | 即插即用的AKConv让目标检测既轻量又提点

突破固定卷积核的局限,让卷积核形状随目标变化而动态调整 目标检测技术在当今计算机视觉领域扮演着至关重要的角色,而YOLO系列作为其中佼佼者,以其高速和高精度获得了广泛应用。但在实际应用中,传统的卷积操作存在一些固有缺陷**。本文介绍了一种创新性的改进方案——AKCon…

linux inotify 功能详解

内核宏开启机制inotify 功能依赖 Linux 内核宏 CONFIG_INOTIFY_USER CONFIG_INOTIFY_USER=y该宏控制用户态程序能否调用 inotify 相关系统调用,如 inotify_init(),inotify_add_watch() inotifywait 侧重实时响应,适合触发后续操作; inotifywatch 侧重数据统计,适合分析事件…

Docker Registry 实现原理、适用场景、常用操作及搭建详解

一、实现原理 Docker Registry 是基于 无状态服务架构 的镜像存储与分发系统&#xff0c;其核心设计包含以下关键点&#xff1a;存储驱动抽象层 Registry 通过 storagedriver.StorageDriver 接口实现存储解耦&#xff0c;支持多种后端存储&#xff1a; 本地存储&#xff1a;默认…

【LeetCode热题100道笔记】轮转数组

题目描述 给定一个整数数组 nums&#xff0c;将数组中的元素向右轮转 k 个位置&#xff0c;其中 k 是非负数。 示例 1: 输入: nums [1,2,3,4,5,6,7], k 3 输出: [5,6,7,1,2,3,4] 解释: 向右轮转 1 步: [7,1,2,3,4,5,6] 向右轮转 2 步: [6,7,1,2,3,4,5] 向右轮转 3 步: [5,6,7…

【Linux我做主】细说进程等待

Linux进程等待Linux进程等待github地址0. 前言1. 进程等待的必要性1.1 避免僵尸进程与资源泄漏1.2 僵尸进程不可被直接清除1.3 获取子进程的运行结果2. 进程等待的三个问题1. 为什么要有进程等待2. 进程等待是什么3. 怎么实现进程等待3. 僵尸进程演示4. waitwait的手册声明wait…

大语言模型对齐

大语言模型对齐的重要性与目标研究 一、引言 随着大语言模型 (LLM) 能力的不断提升和应用场景的日益广泛,这些模型在为人类社会带来巨大便利的同时,也引发了一系列关于安全性、可靠性和伦理问题的担忧(9)。大语言模型的对齐 (alignment) 作为确保这些强大的 AI 系统与人类价…

数组(4)

int mid min (key - arr[min]) / (arr[max] - arr[min]) * (max - min);17.数组常见算法4 分块查找18.数组常见算法5 冒泡排序笔记小程序错误#include<stdio.h> int main() {/*冒泡排序&#xff1a;1.相邻的元素两两比较&#xff0c;大的放右边&#xff0c;小的放左边2…

STM32 读写备份寄存器

本章节功能利用备份寄存器&#xff08;BKP&#xff09;实现数据的掉电保存&#xff0c;并通过按键和OLED显示屏进行交互。使能电源&#xff08;PWR&#xff09;和备份域&#xff08;BKP&#xff09;的时钟&#xff08; RCC_APB1PeriphClockCmd 函数&#xff09;&#xff0c;并…

RabbitMinQ(模拟实现消息队列项目)02

目录 十.整合数据库和文件数据 创建DiskDataManager类 十一.内存结构设计 创建MeneryDataCenter类: 实现集合操作: 对MemoryDataCenter类功能测试: 十二.整合内存和磁盘数据 创建VirtualHost类: Exchange: MSGQueue: Binding: 创建Router类 对Router类的TOPIC匹配…