如何实现两个Div交集区域透明:穿透白色Div显示背景渐变
问题描述
我正在开发一个网站,页面背景设置为蓝色渐变效果。页面右上角有一个白色圆形Div,其上方放置了汉堡菜单的三条横向bar。我希望这些bar区域能够穿透白色圆形Div,显示出背后的背景渐变,同时bar本身保持黑色外观。以下是我的当前实现代码:
index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <link href="https://fonts.googleapis.com/css2?family=Anonymous+Pro&family=Lato&family=Ubuntu+Mono&display=swap" rel="stylesheet" /> <link rel="stylesheet" href="./style.css" /> <script src="./app.js" defer></script> <title>lBark</title> </head> <body> <div id="burger-menu"> <div class="circle"></div> <div class="menu"> <div class="menu-bar"></div> <div class="menu-bar"></div> <div class="menu-bar"></div> </div> </div> <!-- <button style="position: absolute; left: 50%; top: 50%; width: 10vw; height: 10vh; cursor: none;" onclick="alert('hello')"></button> --> <img id="cursor" style="opacity: 0;" src="./img/Cursor.svg"> <div style="width: 5vw; height: 10vh; background-color: red; position: absolute; left: 0; bottom: 0;"></div> <div style="width: 5vw; height: 10vh; background-color: green; position: absolute; left: 5vw; bottom: 0;"></div> <div style="width: 5vw; height: 10vh; background-color: blue; position: absolute; left: 10vw; bottom: 0;"></div> <p class="hero">Epicness</p> </body> </html>
style.css
* { padding: 0; margin: 0; box-sizing: border-box; background-color: transparent; } html { font-size: 62.5%; } body { display: flex; align-items: center; justify-content: center; width: 100vw; height: 100vh; overflow: hidden; /* cursor: none; */ background: linear-gradient( 135deg, rgba(95, 21, 242, 1) 0%, rgba(28, 127, 238, 1) 25%, rgba(47, 201, 226, 1) 50%, rgba(63, 218, 216, 1) 75%, rgba(79, 220, 74, 1) 100% ); } #cursor { position: absolute; transform: translate(-50%, -50%); mix-blend-mode: difference; background-color: transparent; pointer-events: none; width: 3rem; height: auto; transition: opacity ease-in-out 0.3s, width ease-in-out 0.1s; z-index: 1; } .hero { font-size: 15rem; font-family: 'Anonymous Pro'; font-weight: bold; color: white; background-color: transparent; } #burger-menu { position: absolute; top: 0; right: 0; width: 12vw; height: 12vw; background-color: transparent; } #burger-menu .circle { position: absolute; width: 100%; height: 100%; /* background: radial-gradient(circle at center, rgba(255,255,255,0.7) 30%,rgba(255,255,255,0) 70%); */ background-color: white; border-radius: 50%; transform: translate(40%, -40%); } #burger-menu .menu { display: flex; align-items: center; justify-content: space-between; flex-direction: column; position: absolute; top: 10%; right: 10%; width: 20%; height: 16%; } #burger-menu .menu-bar { width: 100%; height: 15%; border-radius: 3rem; background-color: black; }
app.js
// Variables {{{ let dotPositions = []; let cursorX = 0; let cursorY = 0; // }}} // Cursor Control {{{ { const cursor = document.querySelector("#cursor"); let firstCursorMove = true; document.onmousemove = (event) => { if (firstCursorMove) { firstCursorMove = false; cursor.style.opacity = 1; event } cursorX = event.clientX; cursorY = event.clientY; cursor.style.left = cursorX + "px"; cursor.style.top = cursorY + "px"; }; // document.onmousedown = () => { // if (!firstCursorMove) // { // expandingDot(); // } // } document.querySelectorAll("button").forEach(button => { button.addEventListener("mouseenter", () => { cursor.style.width = "5rem"; }); button.addEventListener("mouseleave", () => { cursor.style.width = ""; }); }) } // }}} // Background {{{ { // const canvas = document.querySelector("#background-canvas"); // const context = canvas.getContext("2d"); // // Depending on distance from top left decrease dot size // // When scrolling dots move towards top left and change size // // When link clicked black dot at link which expands // // Splash effect on click // canvas.width = window.innerWidth; // canvas.height = window.innerHeight; function expandingDot() { let expandingCircle = document.createElement("div"); document.body.appendChild(expandingCircle); expandingCircle.style.cssText = `position: absolute; left: ${cursorX}px; top: ${cursorY}px; transform: translate(-50%, -50%) scale(0); border-radius: 50%; background-color: black; transition: transform 1s ease-in-out; will-change: transform;`; setTimeout(() => { if (window.innerHeight > window.innerWidth) { expandingCircle.style.width = "250vh"; expandingCircle.style.height = "250vh"; } else { expandingCircle.style.width = "250vw"; expandingCircle.style.height = "250vw"; } expandingCircle.style.transform = "translate(-50%, -50%) scale(1)"; }, 0); } } function randomNumber(min, max) { return Math.floor(Math.random() * (max - min + 1) + min); } // }}}
Cursor.svg
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg width="30" height="30" viewBox="0 0 20 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;"> <path d="M10,0C15.519,0 20,4.481 20,10C20,15.519 15.519,20 10,20C4.481,20 0,15.519 0,10C0,4.481 4.481,0 10,0ZM10,5C12.76,5 15,7.24 15,10C15,12.76 12.76,15 10,15C7.24,15 5,12.76 5,10C5,7.24 7.24,5 10,5Z" style="fill:white;"/> <circle cx="10" cy="10" r="3" style="fill:white;"/> </svg>
解决方案
要实现bar穿透白色圆形显示背景渐变的效果,推荐两种简洁的CSS方案:
方案一:混合模式实现(推荐)
通过mix-blend-mode让白色圆形与背景混合,同时让黑色bar抵消白色区域,透出背景渐变:
修改style.css中.circle和.menu-bar的样式:
#burger-menu .circle { position: absolute; width: 100%; height: 100%; background-color: white; border-radius: 50%; transform: translate(40%, -40%); /* 白色与背景混合,弱化白色覆盖 */ mix-blend-mode: screen; } #burger-menu .menu-bar { width: 100%; height: 15%; border-radius: 3rem; background-color: black; /* 黑色与下方白色混合,穿透显示背景 */ mix-blend-mode: multiply; }
原理
screen模式下,白色会与背景渐变混合,降低白色的不透明度;multiply模式下,黑色bar会与下方的白色区域混合,完全抵消白色,透出背后的背景渐变;- 该方案无需精确计算位置,适配性强,代码改动最小。
方案二:遮罩镂空实现
通过CSS mask属性在白色圆形上创建与bar对应的镂空区域,直接透出背景:
修改style.css中.circle的样式:
#burger-menu .circle { position: absolute; width: 100%; height: 100%; background-color: white; border-radius: 50%; transform: translate(40%, -40%); /* 创建三个与bar位置匹配的镂空区域 */ mask: linear-gradient(black, black) no-repeat 80% 10% / 20% 15%, linear-gradient(black, black) no-repeat 80% 58% / 20% 15%, linear-gradient(black, black) no-repeat 80% 106% / 20% 15%, linear-gradient(black, black); /* 排除镂空区域,显示背景 */ mask-composite: exclude; }
原理
mask属性通过多个线性渐变创建三个与bar尺寸、位置一致的黑色区域;mask-composite: exclude将这些区域从白色圆形中排除,形成镂空,背景渐变自然透出;- 该方案效果精准,但需要根据bar的布局调整mask的位置和尺寸参数。
完整修改后的style.css
* { padding: 0; margin: 0; box-sizing: border-box; background-color: transparent; } html { font-size: 62.5%; } body { display: flex; align-items: center; justify-content: center; width: 100vw; height: 100vh; overflow: hidden; /* cursor: none; */ background: linear-gradient( 135deg, rgba(95, 21, 242, 1) 0%, rgba(28, 127, 238, 1) 25%, rgba(47, 201, 226, 1) 50%, rgba(63, 218, 216, 1) 75%, rgba(79, 220, 74, 1) 100% ); } #cursor { position: absolute; transform: translate(-50%, -50%); mix-blend-mode: difference; background-color: transparent; pointer-events: none; width: 3rem; height: auto; transition: opacity ease-in-out 0.3s, width ease-in-out 0.1s; z-index: 1; } .hero { font-size: 15rem; font-family: 'Anonymous Pro'; font-weight: bold; color: white; background-color: transparent; } #burger-menu { position: absolute; top: 0; right: 0; width: 12vw; height: 12vw; background-color: transparent; } #burger-menu .circle { position: absolute; width: 100%; height: 100%; background-color: white; border-radius: 50%; transform: translate(40%, -40%); mix-blend-mode: screen; } #burger-menu .menu { display: flex; align-items: center; justify-content: space-between; flex-direction: column; position: absolute; top: 10%; right: 10%; width: 20%; height: 16%; } #burger-menu .menu-bar { width: 100%; height: 15%; border-radius: 3rem; background-color: black; mix-blend-mode: multiply; }
内容的提问来源于stack exchange,提问作者Brumus14
相关产品推荐
相关产品推荐

