// for demo
[...document.querySelectorAll('#control input')].map(el => {
['change', 'mousemove'].map(event_name => {
el.addEventListener(event_name, ({target}) => {
document.querySelector('.block').style.setProperty('--'+target.id, target.value+'%');
document.querySelector(`label[for="${target.id}"]`).dataset.val = target.value;
});
});
});
/* for demo */
#control {color: #fff; font-family: monospace; position: fixed; left: 0; top: 0; z-index: 1;}
label {display: flex; align-items: center;}
label:not(:last-child) {margin-bottom: 20px;}
label::after {content: attr(data-val)'%'; display: inline;}
input {width: 100px; margin: 0 5px;}
body {display: flex; justify-content: center; align-items: center; min-height: 100vh; background: url(https://i.imgur.com/HYAdZOO.png) no-repeat center center / cover; margin: 0; overflow: hidden;}
/* /for demo */
.block {
--x: 0;
--y: 0;
--stroke: 10px;
--size: 60px;
display: block;
width: 200px;
height: 200px;
position: relative;
}
.block .mask {
display: block;
width: 100%;
height: 100%;
-webkit-border-radius: 10px;
border-radius: 10px;
background-color: #fff;
-webkit-mask-image:
-webkit-radial-gradient(var(--x) var(--y),
circle,
transparent -webkit-calc(var(--size) / 2 + var(--stroke)),
white -webkit-calc(var(--size) / 2 + var(--stroke) + 1px)
);
mask-image:
radial-gradient(circle at var(--x) var(--y),
transparent -moz-calc(var(--size) / 2 + var(--stroke)),
white -moz-calc(var(--size) / 2 + var(--stroke) + 1px)
);
mask-image:
radial-gradient(circle at var(--x) var(--y),
transparent calc(var(--size) / 2 + var(--stroke)),
white calc(var(--size) / 2 + var(--stroke) + 1px)
);
position: absolute;
left: 0;
top: 0;
}
.block .image {
display: block;
width: var(--size);
height: var(--size);
-webkit-border-radius: 50%;
border-radius: 50%;
background-color: red;
padding: 5px;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
position: absolute;
left: var(--x);
top: var(--y);
-webkit-transform: translate(-50%, -50%);
-moz-transform: translate(-50%, -50%);
-ms-transform: translate(-50%, -50%);
-o-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
}
<!-- for demo -->
<div id="control">
<label for="x" data-val="0">X <input id="x" type="range" min="0" max="100%" value="0"></label>
<label for="y" data-val="0">Y <input id="y" type="range" min="0" max="100%" value="0"></label>
</div>
<!-- /for demo -->
<div class="block">
<div class="mask"></div>
<div class="image">
<img src="https://i.imgur.com/LjYw4LU.gif" width="50">
</div>
</div>
Использую mask
'у, фигуру задаю такую же, как .image
, в нашем случае это круг - для этого использую radial-gradient
, размер этого круга такой же как размер .image
+ область "под вырез" (переменная --stroke
).
Позиционирую как mask
'у, так и .image
относительно .block
(переменные --x
и --y
), так же .image
смещён через transform
.
.mask
и .image
лежат на одном уровне, т.к. если вложить .image
в .mask
, то .image
будет обрезаться mask
'ой.