How to render screenshot/image inside a frame image without bleeding past frame? How to render screenshot/image inside a frame image without bleeding past frame? javascript javascript

How to render screenshot/image inside a frame image without bleeding past frame?


Other answers

Before I provide my own approach with sources I will first discuss the answer from Ron Royston and show the possible problems / bumps.

Ron Royston's answer

You already pointed out the problem with this approach:

this doesn't work because if the frame has rounded corners like this one, the screenshot can still peek through depending on the background-size

A possible solution is provided by kthornbloom:

So add border-radius to the image element if it needs rounded corners, right?

Right! But this only works for some images. See, you can't apply a border-radius only to the background-image. Instead, you have to do it to the container itself.

Well, what is the problem in that? Just add a small enough border-radius so it doesn't cut the image, scale the background-image down and you are ready to go, right?
Not really! You have to decide what to do with your background-image's size. You can scale it down but then you can't use cover or something similar as the background-size. Unless you have an image that fits perfectly in the border of the smartphone image you will run into trouble. Also, the border-radius is obsolete if you scale your background-image down as it doesn't touch the borders anymore.

  .colorClassProxy {  display: none}.itemBox,.itemBox>* {  position: absolute;  box-sizing: border-box;}.itemBox {  background-image: url('https://images.unsplash.com/photo-1500382017468-9049fed747ef?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&w=1000&q=80');  border-radius: 15px;  background-size: 95% 95%;  background-repeat: no-repeat;  background-position: center;}.backgroundColorBox,.backgroundGraphicBox,.foregroundBox,.frameBox {  width: 100%;  height: 100%;  background-size: contain;  background-color: transparent;  background-position: center;  background-repeat: no-repeat;  pointer-events: none;
<div class="itemBox graphic" id="NZW2Hmn4nVgb" style="width: 173px; height: 364px; top: 86px; left: 111px;">  <div class="backgroundColorBox" style="width: 163px; height: 335px; top: 17px; left: 4px; -webkit-mask-image: url("data:image/svg+xml;charset=utf8,%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20viewBox=%2241.7%20142.4%201445.2%202965.9%22%20preserveAspectRatio=%22none%22%3E%3Cpath%20d=%22M1359.3,3105.3h-1190c-68.8,0-124.6-53.2-124.6-118.9V264.3c0-65.7,55.8-118.9,124.6-118.9h1190%20%20c68.8,0,124.6,53.3,124.6,118.9l0,2722.1C1484,3052.1,1428.2,3105.4,1359.3,3105.3L1359.3,3105.3z%22%20style=%22fill:%20white;%20stroke:%20white;%20stroke-width:%206;%22/%3E%3C/svg%3E"); background-size: cover;"></div>  <div class="frameBox" data-natural-width="1528.64" data-natural-height="3224.29" style="background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNTI4LjY0IiBoZWlnaHQ9IjMyMjQuMjkiIHZpZXdCb3g9IjAgMCAxNTI4LjY0IDMyMjQuMjkiIGRhdGEtaHAtY29sb3ItcHJlcGFyZWQ9InRydWUiIHN0eWxlPSItLWhwLWNvbG9yLTluYXo1Z0JWLTE6cmdiKDI1NSwgMjU1LCAyNTUpOyAtLWhwLWNvbG9yLTluYXo1Z0JWLTI6dXJsKFwjY29sb3ItOW5hejVnQlYtMik7Ij48cmFkaWFsR3JhZGllbnQgaWQ9ImNvbG9yLTluYXo1Z0JWLTIiIGRhdGEtY3NzPSJyYWRpYWwtZ3JhZGllbnQocmdiKDY3LCA2NywgNjcpLCByZ2IoMCwgMCwgMCkpIiBjeD0iNTAlIiBjeT0iNTAlIiByPSI3MC43MSUiPjxzdG9wIHN0b3AtY29sb3I9InJnYig2Nyw2Nyw2NykiIG9mZnNldD0iMCUiLz48c3RvcCBzdG9wLWNvbG9yPSJyZ2IoMCwwLDApIiBvZmZzZXQ9IjEwMCUiLz48L3JhZGlhbEdyYWRpZW50Pjx0aXRsZT5Bc3NldCAyPC90aXRsZT48cGF0aCBkPSJNODU3Ljc4LDcyLjY4SDY3MC44NmMtNy42NCwwLTEzLjg1LDUuOTEtMTMuODUsMTMuMjFzNi4yMSwxMy4yMSwxMy44NSwxMy4yMUg4NTcuNzhjNy42NiwwLDEzLjg1LTUuOTEsMTMuODUtMTMuMjFTODY1LjQ0LDcyLjY4LDg1Ny43OCw3Mi42OFoiIGZpbGw9IiNlOGVlZWYiIGZpbGwtcnVsZT0iZXZlbm9kZCIgc3R5bGU9ImZpbGw6IHZhcigtLWhwLWNvbG9yLTluYXo1Z0JWLTEpOyIvPjxwYXRoIGQ9Ik0xNTE0Ljc5LDc4Ni4yNlYxNjUuMTdDMTUxNC43OSw3My45NSwxNDM3LjI5LDAsMTM0MS43MiwwSDE4Ni45MkM5MS4zMywwLDEzLjg1LDczLjk1LDEzLjg1LDE2NS4xN1Y0NzUuNzFDNi4xOSw0NzUuNzEsMCw0ODEuNjIsMCw0ODguOTJWODU4LjkzYzAsNy4zLDYuMTksMTMuMjEsMTMuODUsMTMuMjF2MTMyLjE1QzYuMTksMTAwNC4yOSwwLDEwMTAuMiwwLDEwMTcuNXYxOTguMjFjMCw3LjMxLDYuMTksMTMuMjIsMTMuODUsMTMuMjJWMzA1OS4xYzAsOTEuMjMsNzcuNDgsMTY1LjE5LDE3My4wNywxNjUuMTloMTE1NC44Yzk1LjU3LDAsMTczLjA3LTczLjk2LDE3My4wNy0xNjUuMTlWMTAxNy41YzcuNjQsMCwxMy44NS01LjkxLDEzLjg1LTEzLjIxVjc5OS40N0MxNTI4LjY0LDc5Mi4xNywxNTIyLjQzLDc4Ni4yNiwxNTE0Ljc5LDc4Ni4yNlpNNjcwLjg2LDcyLjY4SDg1Ny43OGM3LjY2LDAsMTMuODUsNS45MSwxMy44NSwxMy4yMVM4NjUuNDQsOTkuMSw4NTcuNzgsOTkuMUg2NzAuODZjLTcuNjQsMC0xMy44NS01LjkxLTEzLjg1LTEzLjIxUzY2My4yMiw3Mi42OCw2NzAuODYsNzIuNjhabTY4OC40OCwzMDMyLjY3SDE2OS4zMmMtNjguODQsMC0xMjQuNjEtNTMuMjQtMTI0LjYxLTExOC45M1YyNjQuMjljMC02NS42OSw1NS43Ny0xMTguOTQsMTI0LjYxLTExOC45NEgxMzU5LjM0YzY4LjgxLDAsMTI0LjYxLDUzLjI1LDEyNC42MSwxMTguOTRsLjAxLDI3MjIuMTNDMTQ4My45NiwzMDUyLjExLDE0MjguMTYsMzEwNS4zNSwxMzU5LjM0LDMxMDUuMzVaIiBmaWxsPSIjZmZmIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIHN0eWxlPSJmaWxsOiB2YXIoLS1ocC1jb2xvci05bmF6NWdCVi0yKTsiLz48L3N2Zz4=);"    data-inner-natural-left="41.7" data-inner-natural-top="142.4" data-inner-natural-width="1445.2" data-inner-natural-height="2965.9"><iframe class="colorClassProxy"></iframe></div></div>

Doesn't look good does it?
However, this approach does work in some cases. If the outline of the smartphone does not have any buttons on the side (like this one does) this approach will work. But I can't think of a smartphone that doesn't have buttons on the side.

Никита Гулис's answer (working)

Due to the missing markup this answer is very hard to read. However, it is mostly right and the best way to go most of the times. Actually, you have almost done it yourself with the clipping path. But first let's do the steps.

  1. Create an image and place it inside of the container.
  2. Scale it down to the right size.
  3. Position it the right way.
  4. Remove the clipping paths as it is unnecessary.

/*====Added this part====*/.display-image {  width: 165px;  height: 340px;  display: block;  background-image: url('https://images.unsplash.com/photo-1500382017468-9049fed747ef?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&w=1000&q=80"');  background-size: cover;  margin-top: 15px;  margin-left: 5px;  border-radius: 10px;}/*=======================*/.colorClassProxy {  display: none}.itemBox,.itemBox>* {  position: absolute;  box-sizing: border-box;}.backgroundColorBox,.backgroundGraphicBox,.foregroundBox,.frameBox {  width: 100%;  height: 100%;  background-size: contain;  background-color: transparent;  background-position: center;  background-repeat: no-repeat;  pointer-events: none;
<div class="itemBox graphic" id="NZW2Hmn4nVgb" style="width: 173px; height: 364px; top: 86px; left: 111px;">  <!--====Added this line====-->  <div class="display-image" alt=""></div>  <!--=======================-->    <!--====Removed the clipping path====-->  <div class="frameBox" data-natural-width="1528.64" data-natural-height="3224.29" style="background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNTI4LjY0IiBoZWlnaHQ9IjMyMjQuMjkiIHZpZXdCb3g9IjAgMCAxNTI4LjY0IDMyMjQuMjkiIGRhdGEtaHAtY29sb3ItcHJlcGFyZWQ9InRydWUiIHN0eWxlPSItLWhwLWNvbG9yLTluYXo1Z0JWLTE6cmdiKDI1NSwgMjU1LCAyNTUpOyAtLWhwLWNvbG9yLTluYXo1Z0JWLTI6dXJsKFwjY29sb3ItOW5hejVnQlYtMik7Ij48cmFkaWFsR3JhZGllbnQgaWQ9ImNvbG9yLTluYXo1Z0JWLTIiIGRhdGEtY3NzPSJyYWRpYWwtZ3JhZGllbnQocmdiKDY3LCA2NywgNjcpLCByZ2IoMCwgMCwgMCkpIiBjeD0iNTAlIiBjeT0iNTAlIiByPSI3MC43MSUiPjxzdG9wIHN0b3AtY29sb3I9InJnYig2Nyw2Nyw2NykiIG9mZnNldD0iMCUiLz48c3RvcCBzdG9wLWNvbG9yPSJyZ2IoMCwwLDApIiBvZmZzZXQ9IjEwMCUiLz48L3JhZGlhbEdyYWRpZW50Pjx0aXRsZT5Bc3NldCAyPC90aXRsZT48cGF0aCBkPSJNODU3Ljc4LDcyLjY4SDY3MC44NmMtNy42NCwwLTEzLjg1LDUuOTEtMTMuODUsMTMuMjFzNi4yMSwxMy4yMSwxMy44NSwxMy4yMUg4NTcuNzhjNy42NiwwLDEzLjg1LTUuOTEsMTMuODUtMTMuMjFTODY1LjQ0LDcyLjY4LDg1Ny43OCw3Mi42OFoiIGZpbGw9IiNlOGVlZWYiIGZpbGwtcnVsZT0iZXZlbm9kZCIgc3R5bGU9ImZpbGw6IHZhcigtLWhwLWNvbG9yLTluYXo1Z0JWLTEpOyIvPjxwYXRoIGQ9Ik0xNTE0Ljc5LDc4Ni4yNlYxNjUuMTdDMTUxNC43OSw3My45NSwxNDM3LjI5LDAsMTM0MS43MiwwSDE4Ni45MkM5MS4zMywwLDEzLjg1LDczLjk1LDEzLjg1LDE2NS4xN1Y0NzUuNzFDNi4xOSw0NzUuNzEsMCw0ODEuNjIsMCw0ODguOTJWODU4LjkzYzAsNy4zLDYuMTksMTMuMjEsMTMuODUsMTMuMjF2MTMyLjE1QzYuMTksMTAwNC4yOSwwLDEwMTAuMiwwLDEwMTcuNXYxOTguMjFjMCw3LjMxLDYuMTksMTMuMjIsMTMuODUsMTMuMjJWMzA1OS4xYzAsOTEuMjMsNzcuNDgsMTY1LjE5LDE3My4wNywxNjUuMTloMTE1NC44Yzk1LjU3LDAsMTczLjA3LTczLjk2LDE3My4wNy0xNjUuMTlWMTAxNy41YzcuNjQsMCwxMy44NS01LjkxLDEzLjg1LTEzLjIxVjc5OS40N0MxNTI4LjY0LDc5Mi4xNywxNTIyLjQzLDc4Ni4yNiwxNTE0Ljc5LDc4Ni4yNlpNNjcwLjg2LDcyLjY4SDg1Ny43OGM3LjY2LDAsMTMuODUsNS45MSwxMy44NSwxMy4yMVM4NjUuNDQsOTkuMSw4NTcuNzgsOTkuMUg2NzAuODZjLTcuNjQsMC0xMy44NS01LjkxLTEzLjg1LTEzLjIxUzY2My4yMiw3Mi42OCw2NzAuODYsNzIuNjhabTY4OC40OCwzMDMyLjY3SDE2OS4zMmMtNjguODQsMC0xMjQuNjEtNTMuMjQtMTI0LjYxLTExOC45M1YyNjQuMjljMC02NS42OSw1NS43Ny0xMTguOTQsMTI0LjYxLTExOC45NEgxMzU5LjM0YzY4LjgxLDAsMTI0LjYxLDUzLjI1LDEyNC42MSwxMTguOTRsLjAxLDI3MjIuMTNDMTQ4My45NiwzMDUyLjExLDE0MjguMTYsMzEwNS4zNSwxMzU5LjM0LDMxMDUuMzVaIiBmaWxsPSIjZmZmIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIHN0eWxlPSJmaWxsOiB2YXIoLS1ocC1jb2xvci05bmF6NWdCVi0yKTsiLz48L3N2Zz4=);"    data-inner-natural-left="41.7" data-inner-natural-top="142.4" data-inner-natural-width="1445.2" data-inner-natural-height="2965.9"><iframe class="colorClassProxy"></iframe></div></div>

Short note: The reference he provided does not actually represent what he wrote.

I took a look at the reason why you opened the bounty:

Looking for an answer drawing from credible and/or official sources.

You can see it on every website that uses an image as the smartphone.

  • It has been discussed on stack overflow once right here.
  • I created a test app with an "website to app" converter. On this website you can test the app out and they used the same approach. The only difference is that they can't have an image as the display. Instead, they use a canvas. Sadly I can't implement it in my answer so I have to post the link instead.
  • The same can be seen on this site.

The examples I provided are all rather big companies and if you search for more exmaples you will find more of them. In my opinion these examples make this approach credible.

Edit

Based on the comments I will complete the answer.
This depends on how much you can edit your picture. I assume that you own the pictures or are allowed to use them. Here is one approach:

First of all I thought I can just position it and scale the image. Turns out that the smartphone in the image is slightly turned. So one approach would be to use CSS for this. You will have to work with skew() (CSS), but this is very, very, very hard to nail. Also, if you just put it on the image you will run into the same problem as you had before with your clipping paths. So this does not seem to be the solution.

Another approach is the following:
It should be no problem for you to just convert it to a PNG (Portable Network Graphic) and cut out the white display to make it transparent.

  1. Give the image you want in the display a lower z-index.
  2. Position it and scale it.

However, this is only approximatly. You can of course just skew and transform the image until no one would notice. But this doesn't seem to be the "clearest" way does it?

* {  box-sizing: border-box;  margin: 0;  padding: 0;}.display-image {  width: 184px;  height: 322px;  display: block;  background-image: url('https://images.unsplash.com/photo-1500382017468-9049fed747ef?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&w=1000&q=80"');  background-size: cover;  top: 165px;  left: 219px;  position: absolute;  transform: rotate(0.2deg);  z-index: -1;}.itemBox {  position: relative;  box-sizing: border-box;}.frameBox {  z-index: 1;}
<div class="itemBox graphic" id="NZW2Hmn4nVgb" style="width: 173px; height: 364px; top: 86px; left: 111px;">  <!--====Added this line====-->  <div class="display-image" alt=""></div>  <!--=======================-->  <!--====Removed the clipping path====-->  <div class="frameBox"><img alt="" src="https://i.imgur.com/jbHkPuf.png"></div></div>

The only clean way I can think of is using canvas. As you can see here it is possible to distord images with it to your liking. You will have to draw the whole "smartphone inside hand" picture in the canvas and then draw the image that should be on the display on the needed coordinates. But you have to decide if it is worth the time because it is fairly time consuming and complex and a lot of code. I decided it isn't and that's why there is no working exmaple. Also, you can't just use things like background-size: cover so you will have to cut the image to the smartphones size if you don't want to write a huge junk of JS. In my opinion the approach before this is the best approach.

Of course I could have overlooked something so feel free to correct me or edit my answer.


You can create a div behind the frame, scale it just a little bit down so the border would be inside of the border of the phone.Then round the corners of the div and give it overflow: hidden;Then place an image inside, give it height and width of 100% and object-fit:cover;Heres one of my websites with similar effect so you can have a reference.reference (phones are visible on medium to big screens)


I think the easiest way is to apply the image as a CSS background-image then use background-size's contain or cover.

Scaling background images

The background-size CSS property makes it possible to adjust the width and height of background images, thus overriding the default behavior which tiles background images at their full size. You can scale the image upward or downward as desired.