最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Is a see-through child div possible? - Stack Overflow

programmeradmin7浏览0评论

The image is the grandparent div, the black translucent overlay is the parent div, and the cropped section is the child div. User will see the grandparent image and the parent overlay, then he can crop through it using the child cropper div. I tried and failed with opacity and rgba background.

These crazy approaches do seem to work for me -

  1. Set the grandparent image in the background of the child div as well and then change the x/y of the background-position.
  2. Combine child and parent into one single div, and use rgba border as the overlay (my friend's suggestion).
  3. Found this on stackoverflow, which uses box-shadow instead of borders and seems like a similar approach to #2.

My minor gripe with #2 and #3 is that I'll need to add another div for the dashed borders so the user clearly knows what he's cropping. But my bigger gripe with all of them is that none of these looks like the right approach.

Is there a proper / better / 2018-ish / "its so obvious, you idiot" way to do this?

Update: Here's the basic markup (I am okay with a different markup too if that helps in solving this)

#grandparentImage {
  background: url(.jpg) no-repeat;
  background-size: cover;
  position: relative;
  height: 500px;
}

#parentOverlay {
  background: rgba(0,0,0,0.5);
  height: 100%;
  position: relative;
}

#childCropper {
  border: 1px dashed #ccc;
  left: 50px;
  height: 100px;
  width: 100px;
  position: absolute;
  top: 50px;
}
<div id="grandparentImage">
  <div id="parentOverlay">
    <div id="childCropper"></div>
  </div>
</div>

The image is the grandparent div, the black translucent overlay is the parent div, and the cropped section is the child div. User will see the grandparent image and the parent overlay, then he can crop through it using the child cropper div. I tried and failed with opacity and rgba background.

These crazy approaches do seem to work for me -

  1. Set the grandparent image in the background of the child div as well and then change the x/y of the background-position.
  2. Combine child and parent into one single div, and use rgba border as the overlay (my friend's suggestion).
  3. Found this on stackoverflow, which uses box-shadow instead of borders and seems like a similar approach to #2.

My minor gripe with #2 and #3 is that I'll need to add another div for the dashed borders so the user clearly knows what he's cropping. But my bigger gripe with all of them is that none of these looks like the right approach.

Is there a proper / better / 2018-ish / "its so obvious, you idiot" way to do this?

Update: Here's the basic markup (I am okay with a different markup too if that helps in solving this)

#grandparentImage {
  background: url(https://9to5mac./wp-content/uploads/sites/6/2018/07/Desert-2.jpg) no-repeat;
  background-size: cover;
  position: relative;
  height: 500px;
}

#parentOverlay {
  background: rgba(0,0,0,0.5);
  height: 100%;
  position: relative;
}

#childCropper {
  border: 1px dashed #ccc;
  left: 50px;
  height: 100px;
  width: 100px;
  position: absolute;
  top: 50px;
}
<div id="grandparentImage">
  <div id="parentOverlay">
    <div id="childCropper"></div>
  </div>
</div>

Edit: It is not a duplicate of the marked question, since that question deals with how to grab the cropped image, this one deals with how to show the user what he's cropping. More about UI than data.

Share Improve this question edited Oct 2, 2018 at 2:49 Boann 50k16 gold badges124 silver badges152 bronze badges asked Oct 1, 2018 at 12:01 rmnrmn 1,1697 silver badges19 bronze badges 10
  • Can you provide some basic markup so we can use it to test? – ibrahim mahrir Commented Oct 1, 2018 at 12:05
  • 1 You could use two divs, one as the background (with low opacity) one on the front with background position to show only the part that is selected – Rafael Herscovici Commented Oct 1, 2018 at 12:18
  • 1 Your 1st approach with using of two images is well-known solution for this task and is used in most of crop libraries. Another one solution is to use canvas, but there is much more work here – Igor Alemasow Commented Oct 1, 2018 at 12:23
  • 2 You could either try clip-path: inset() or clip-path: polygon for more advanced shapes. – Domenik Reitzner Commented Oct 1, 2018 at 12:30
  • 1 Possible duplicate of Crop an image displayed in a Canvas – Rafael Herscovici Commented Oct 1, 2018 at 12:41
 |  Show 5 more ments

5 Answers 5

Reset to default 8

You can set box-shadow with 100vmax spread radius on the #childCropper. In this way it will always cover the screen:

#grandparentImage {
  background: url(https://9to5mac./wp-content/uploads/sites/6/2018/07/Desert-2.jpg) no-repeat;
  background-size: cover;
  position: relative;
  height: 500px;
}

#childCropper {
  position: absolute;  
  top: 50px;
  left: 50px;
  height: 200px;
  width: 200px;
  border: 1px dashed #ccc;
  box-shadow: 0 0 0 100vmax rgba(0,0,0,0.5);
}

body {
  margin: 0;
}
<div id="grandparentImage">
  <div id="childCropper"></div>
</div>

This seems like a perfect job for pseudo-elements. So this solution is an upgrade of #2 suggestion in the question, but instead of using the element itself, it uses :after:

#grandparentImage {
  background: url(https://upload.wikimedia/wikipedia/mons/thumb/e/e5/%D0%94%D0%B7%D0%B5%D0%BC%D0%B1%D1%80%D0%BE%D0%BD%D1%8F._%D0%9F%D0%B5%D1%80%D0%B2%D1%8B%D0%B5_%D0%BB%D1%83%D1%87%D0%B8_%D1%81%D0%BE%D0%BB%D0%BD%D1%86%D0%B0.jpg/800px-%D0%94%D0%B7%D0%B5%D0%BC%D0%B1%D1%80%D0%BE%D0%BD%D1%8F._%D0%9F%D0%B5%D1%80%D0%B2%D1%8B%D0%B5_%D0%BB%D1%83%D1%87%D0%B8_%D1%81%D0%BE%D0%BB%D0%BD%D1%86%D0%B0.jpg) no-repeat;
  background-size: cover;
  position: relative;
  height: 500px;
  overflow: hidden;
  z-index: 1;
}

#childCropper {
  border: 2px dashed #ccc;
  position: absolute;
  top: 50px;
  left: 50px;
  height: 200px;
  width: 200px;
}

#childCropper:after {
  content: "";
  width: 100%;
  height: 100%;
  border: 1000px solid rgba(0, 0, 0, 0.5);
  position: absolute;
  top: -1000px;
  left: -1000px;
  z-index: -1;
}
<div id="grandparentImage">
  <div id="childCropper"></div>
</div>

Note: There will be no need for the #parentOverlay element anymore. Also this solution requires the grand-parent element to have an overflow: hidden property and a z-index (why?).

I'm guessing this is what you're looking for:

overlay-mask {
  background-color: rgba(0,0,0,.65);
  clip-path: polygon(0% 0%, 75% 0%, 75% 25%, 25% 25%, 25% 75%, 75% 75%, 75% 0%, 100% 0%, 100% 100%, 0 100%);
  z-index: 1;
  pointer-events: none;
  /* rest is optional, you could use 
   * `position:absolute` to place it in a parent with `relative` 
   */
  position: fixed;
  top: 0; bottom: 0; left: 0; right: 0;
}

body {
  margin: 0;
  background: url("https://loremflickr./800/600") no-repeat center center /cover;
  min-height: 100vh;
}
<overlay-mask></overlay-mask>

It's a simple shape following the polygon of the dark area. Points position can be expressed in percentage, using calc() or even providing a custom <svg> by id (and use an external tool, like Adobe Illustrator to generate it.

Current browser coverage: 87.99%.

You can have any content under the mask. And, instead of using position:fixed, you could use position:absolute and place it in the desired container with position:relative, to apply to that container.


Another method is to use <svg>s <path>. Animating them is pretty straight forward using either smil animations or plain CSS keyframes.

Example:

#overlay-mask {
  z-index: 1;
  pointer-events: none;
  /* rest is optional, you could use 
   * `position:absolute` to place it in a parent with `relative` 
   */
  position: fixed;
  top: 0; bottom: 0; left: 0; right: 0;
  color: rgba(0,0,0,.65);
  width: calc(100% + 4px);
  height: calc(100% + 4px);
  left: -2px;
  top: -2px;
}

body {
  margin: 0;
  background: url("https://loremflickr./800/600") no-repeat center center /cover;
  min-height: 200vh;
}
h2 {color: white;}
<script src="https://ajax.googleapis./ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg id="overlay-mask" version="1.1" xmlns="http://www.w3/2000/svg" xmlns:xlink="http://www.w3/1999/xlink"
     preserveAspectRatio="none"
     viewBox="0 0 600 600" width="600" height="600">
    <defs>
        <path d="M0 600L0 0L600 0L600 600L0 600ZM100 200L200 200L200 100L100 100L100 200Z" id="cutPath">
        <animate attributeType="XML" attributeName="d" 
        values="M0 600L0 0L600 0L600 600L0 600ZM100 200L200 200L200 100L100 100L100 200Z; M0 600L0 0L600 0L600 600L0 600ZM200 300L300 300L300 200L200 200L200 200Z;M0 600L0 0L600 0L600 600L0 600ZM100 300L300 300L300 100L100 100L100 200Z;M0 600L0 0L600 0L600 600L0 600ZM100 200L200 200L200 100L100 100L100 100Z"
        keyTimes="0; 0.33; 0.66; 1"
        dur="3s" repeatCount="indefinite"
        />
        </path>
    </defs>
    <use xlink:href="#cutPath" opacity="1" fill="currentColor" fill-opacity="1"></use>
    <use xlink:href="#cutPath" opacity="1" fill="none" stroke="white" stroke-width="2"
    stroke-dasharray="1,1"
    ></use>
</svg>

<h2>Scroll down...</h2>

Overlaying divs (Proof of Concept)

.parent,
.child {
  background-image: url(https://scontent-lht6-1.cdninstagram./vp/0f18c710d8dc3ebd48819b3f9f44b5cc/5C28EE7E/t51.2885-15/e35/29094825_1798384780455300_8914767740305145856_n.jpg?se=7&ig_cache_key=MTc0MDQ5MzIwMjE5OTYyODM5MQ%3D%3D.2);
  background-size: contain;
}

.parent {
  height: 1072px;
  width: 1072px;
  opacity: 0.3
}

.child {
  position: absolute;
  top: 150px;
  left: 20px;
  height: 200px;
  width:500px;
  background-position: -20px -150px; 
  background-size: 1072px 1072px
}
<div class="parent"></div>
<div class="child"></div>

Here is another approach that uses only one element where you can rely on gradient and multiple background to create the cropped overlay and also the dotted border:

#grandparentImage {
  --g:linear-gradient(rgba(0,0,0,0.5),rgba(0,0,0,0.5));
  --t:repeating-linear-gradient(to right ,#ccc 0,#ccc 2px,transparent 2px, transparent 4px);
  --b:repeating-linear-gradient(to bottom,#ccc 0,#ccc 2px,transparent 2px, transparent 4px);
  background-image: 
    /*the border*/ 
    var(--t),var(--t),var(--b),var(--b),
    /*the overlay*/
    var(--g),var(--g),var(--g),var(--g),
    /*the image*/
    url(https://picsum.photos/1000/800?image=1069);
  background-size: 
    /*the border*/ 
    40% 2px,40% 2px,2px 40%,2px 40%,
    /*the overlay*/
    100% 30%,100% 30%,20% 40%, 40% 40%,
    /*the image*/
    cover;
  background-position:
    /*the border*/ 
    33.33% 30%,left 33.33% bottom 30%,20% 50%,60% 50%,
    /*the overlay*/
    top,bottom,left center,right center,
    /*the image*/
    center;
  background-repeat:no-repeat;
  position: relative;
  height: 100vh;
}

body {
 margin:0;
}
<div id="grandparentImage">

</div>

The overlay will be formed by 4 gradients as a rectangular shapes and each border will be a repeating gradient to alternate white/transparent.

The hard part is to understand the different values and how the caclulation of background-size/background-position is done. Here is a good reading for this: background-position not working in percentage for linear-gradient


We can also and the dots of your screenshot:

#grandparentImage {
  --g:linear-gradient(rgba(0,0,0,0.5),rgba(0,0,0,0.5));
  --t:repeating-linear-gradient(to right ,#ccc 0,#ccc 2px,transparent 2px, transparent 4px);
  --b:repeating-linear-gradient(to bottom,#ccc 0,#ccc 2px,transparent 2px, transparent 4px);
  --d:radial-gradient(#ccc 60%,transparent 62%);
  background-image: 
    /*the dots*/
    var(--d),var(--d),var(--d),var(--d),var(--d),var(--d),var(--d),var(--d),
    /*the border*/ 
    var(--t),var(--t),var(--b),var(--b),
    /*the overlay*/
    var(--g),var(--g),var(--g),var(--g),
    /*the image*/
    url(https://picsum.photos/1000/800?image=1069);
  background-size: 
    /*the dots*/
    10px 10px,10px 10px,10px 10px,10px 10px,10px 10px,10px 10px,10px 10px,10px 10px,
    /*the border*/ 
    40% 2px,40% 2px,2px 40%,2px 40%,
    /*the overlay*/
    100% 30%,100% 30%,20% 40%, 40% 40%,
    /*the image*/
    cover;
  background-position:
    /*the dots*/
    20% 30%,20% 70%,20% 50%,60% 30%,60% 50%,60% 70%,40% 30%,40% 70%, 
    /*the border*/ 
    33.33% 30%,left 33.33% bottom 30%,20% 50%,60% 50%,
    /*the overlay*/
    top,bottom,left center,right center,
    /*the image*/
    center;
  background-repeat:no-repeat;
  position: relative;
  height: 100vh;
}

body {
 margin:0;
}
<div id="grandparentImage">

</div>

发布评论

评论列表(0)

  1. 暂无评论