Как закрепить несколько масок на одном фиксированном фоне?
Я пытаюсь создать фрагмент, в котором у меня есть несколько элементов, за которыми расположен один общий фон. Оба круга имеют разную прозрачность. Они могут перемещаться, чтобы показать различные части фона. Я застрял, и у меня заканчиваются идеи. Как к этому подойти?
Моя попытка, чтобы результат выглядел так.
Свободный перевод вопроса How to clip multiple masks to one single fixed background? от участника @Ashutosh Gupta.
Ответы (3 шт):
маска - это то, что вам нужно:
.box {
position:fixed;
inset:0;
-webkit-mask:
/* control the opacity --v position / size */
radial-gradient(farthest-side,rgba(0,0,0,0.5) 96%,#0000) 20% 50% / 300px 300px,
radial-gradient(farthest-side,rgba(0,0,0,0.2) 96%,#0000) 70% 50% / 200px 200px,
linear-gradient(#000 0 0);
-webkit-mask-repeat:no-repeat;
-webkit-mask-composite: destination-out;
mask-composite: exclude;
background:#000;
}
html {
background:url(https://picsum.photos/id/1069/800/800) top/cover
}
<div class="box"></div>
Свободный перевод ответа от участника @Temani Afif.
Решение SVG mask
В качестве маски используются две окружности. Разная прозрачность кругов обеспечивается разными цветами заполнения.
.container {
width:75vw;
height:75vh;
}
<div class="container">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 0 800 664" preserveAspectRatio="xMinYMin meet">
<defs>
<mask id="msk" >
<rect width="100%" height="100%" fill="black" />
<circle fill="rgba(255,255,255,0.4)" cx="280" cy="300" r="150" />
<circle fill="rgba(255,255,255,0.7)" cx="420" cy="300" r="120" />
</mask>
</defs>
<rect width="100%" height="100%" fill="black" />
<image mask="url(#msk)" xlink:href="https://i.stack.imgur.com/2WicJ.jpg" width="100%" height="100%" />
</svg>
</div>
Чтобы сделать фон немного видимым, добавим в маску
<rect width="100%" height="100%" fill="#A96667" />
.container {
width:75vw;
height:75vh;
}
<div class="container">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 0 800 664" preserveAspectRatio="xMinYMin meet">
<defs>
<mask id="msk" >
<rect width="100%" height="100%" fill="#A96667" />
<circle fill="rgba(255,255,255,0.4)" cx="280" cy="300" r="150" />
<circle fill="rgba(255,255,255,0.7)" cx="420" cy="300" r="120" />
</mask>
</defs>
<rect width="100%" height="100%" fill="black" />
<image mask="url(#msk)" xlink:href="https://i.stack.imgur.com/2WicJ.jpg" width="100%" height="100%" />
</svg>
</div>
Update
Все благодарности @Leonid за ценное добавление в улучшении кода fill="rgba(255,255,255,0.4)" которое позволило улучшить конечный результат (зона на пересечении масок стала выделена более светлым цветом)
Можно и с помощью canvas:
let canvas = document.getElementById('canvas');
let ctx = canvas.getContext('2d');
let image = new Image();
image.src = 'https://i.stack.imgur.com/2WicJ.jpg';
image.onload = () => { draw();};
window.addEventListener('resize', () => {draw()});
function draw(){
let iW = image.width;
let iH = image.height;
let wW = canvas.parentElement.getBoundingClientRect().width;
let wH = canvas.parentElement.getBoundingClientRect().height;
let k = Math.min(wW/iW, wH/iH);
let w = canvas.width = iW*k;
let h = canvas.height = iH*k;
ctx.clearRect(0,0,w,h);
ctx.save();
ctx.fillStyle = 'rgba(255,255,255,0.7)';
ctx.beginPath();
ctx.arc(w/2.7, h/2.7, Math.min(w,h)/3.5, 0, 2 * Math.PI);
ctx.fill();
ctx.fillStyle = 'rgba(255,255,255,0.5)';
ctx.beginPath();
ctx.arc(w*2/3, h*2/3.5, Math.min(w,h)/4, 0, 2 * Math.PI);
ctx.fill();
ctx.globalCompositeOperation = 'source-in';
ctx.drawImage(image,0,0,iW,iH,0,0,w,h);
ctx.restore();
}
body {
min-height: 98vh;
}
* {
box-sizing: border-box;
margin: 0;
}
<canvas id="canvas" style="background: black"></canvas>
Размер холста в пропорциях загруженного изображения. При изменении размера окна просмотра перестраивается.
Тема globalCompositeOperation обширна, добавил несколько рабочих вариантов. Последний "color" оставил все фигуры без изменения. Методов компоновки много, некоторые требуют обратный порядок, подложенный фон или объединение фигур для адекватного отображения эффекта.
let canvas = document.getElementById('canvas');
let ctx = canvas.getContext('2d');
let w = canvas.width = 600;
let h = canvas.height = 180;
let image = new Image();
image.src = 'https://i.stack.imgur.com/2WicJ.jpg';
image.onload = () => {draw()};
function draw(gco='source-in'){
ctx.clearRect(0,0,w,h);
ctx.save();
ctx.fillStyle = 'rgba(255,255,255,0.7)';
ctx.beginPath();
ctx.arc(280, 80, 60, 0, 2 * Math.PI);
ctx.fill();
ctx.fillStyle = 'rgba(255,255,255,0.5)';
ctx.beginPath();
ctx.arc(350, 90, 70, 0, 2 * Math.PI);
ctx.fill();
ctx.globalCompositeOperation = gco;
ctx.drawImage(image,0,(image.height - image.height*(h/w))/2,image.width,image.height*(h/w),0,0,w,h);
ctx.restore();
}
document.querySelector('select').addEventListener('change', e => {
draw(e.target.value);
})
<canvas id="canvas" style="background: black"></canvas>
<select style="position: fixed; top:0; left: 0;">
<option selected>source-in</option>
<option>source-out</option>
<option>destination-in</option>
<option>xor</option>
<option>lighter</option>
<option>difference</option>
<option>luminosity</option>
<option>color</option>
</select>

