0

Here's sort of what I'm going for:

enter image description here

I have a scanner component (plays back what the camera is seeing) but I need to wrap it somehow to create a semi-opaque overlay with a transparent rectangle directly in the center of the screen.

How can this be done?

McDerp
  • 77
  • 1
  • 2
  • 14

3 Answers3

1

You can try this workaround using clip-path.

You may adjust the dimensions of the highlight by editing the

style="--left: 30%; --top: 30%; --width: 40%; --height: 40%;"

part of the .frame element.

.frame {
  position: relative;
  display: inline-block;
}

.frame::after {
  content: '';
  display: block;
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.5);
  z-index: 1;
  
  clip-path: polygon(
    0% 0%, 
    0% 100%, 
    var(--left) 100%,
    var(--left) var(--top),
    calc(var(--left) + var(--width)) var(--top),
    calc(var(--left) + var(--width)) calc(var(--top) + var(--height)),
    var(--left) calc(var(--top) + var(--height)),
    var(--left) 100%,
    100% 100%,
    100% 0
  );
}
<div class="frame" style="--left: 30%; --top: 30%; --width: 40%; --height: 40%;">
  <img src="https://picsum.photos/id/16/640/320" />
</div>
Hao Wu
  • 17,573
  • 6
  • 28
  • 60
1

You can use border to produce the 'overlay' portion - that way you have a true 'transparent' block that darkens everything outside it. The trick is to have the borders extend to the edges of the element (or the screen) - you can do that by specifying the border-width in viewport units, like this:

.container {
  position: relative;
  width: 100vw;
  height: 100vh;
  overflow: hidden;
}

.container img{
  margin: auto;
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.loupe {
  width: 24rem;
  height: 18rem;
  border: 0 solid rgba(0,0,0,0.5);
  border-width: 50vh 50vw;
  position: absolute;
  top: -9rem; /* Half of height */
  bottom: 0;
  right: 0;
  left: -12rem;  /* Half of width */
  margin: auto;
}

/* Optional - apply a shadow effect under the loupe */
.loupe::after {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  box-shadow: 0 0.1rem 1.5rem rgba(0,0,0,0.25);
}
    <div class="container">
      <img src="https://images.unsplash.com/photo-1621135177072-57c9b6242e7a?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=1534&q=80"/>
      <div class="loupe">
      </div>
    </div>

If you need to fine-tune the position of the loupe, you can use transform: translate(); to adjust the position.

Ben Hull
  • 7,524
  • 3
  • 36
  • 56
1

Similar to the "border" solution, you can use an inset box-shadow, some what effectively.

.wrap {
  position: relative;
}

.wrap::before {
  position: absolute;
  height: 100%;
  width: 100%;
  overflow: hidden;
  box-shadow: inset 0 0 0 150px rgb(0 0 0 / 70%);
  content: '';
}

body {
  margin: 0;
}
<div class="wrap">
  <img src="https://www.fillmurray.com/1000/1000">
</div>
Jon P
  • 19,442
  • 8
  • 49
  • 72
  • One thing about a box shadow is that it can't collect 'clicks' like an element does. That may or may not be an issue with this application. This is a really cool approach though. – Ben Hull May 23 '21 at 23:07