Как сделать снимок экрана/изображение внутри изображения кадра, не пропуская последний кадр?

С помощью divs или canvas цель состоит в том, чтобы полностью заполнить фрейм устройства изображением/скриншотом, но без прохождения кадра.

Снимок экрана 1 иллюстрирует изображение, плотно прилегающее к рамке. Снимок экрана 2 иллюстрирует пролив изображения за кадром.

Первая проблема заключается в том, что изображение/скриншот могут отличаться по соотношению сторон, т.е. Могут использоваться изображения разного размера. Например, одно изображение может быть 1242x2688, а другое изображение может быть 1440x2960. Независимо от соотношения сторон, снимок экрана должен заполнять рамку, но не проходить через ее края.

Вторая проблема заключается в том, что они часто масштабируются в CSS с помощью transform: scale(x) до ~ 25%, а поведение браузеров при округлении создает разрывы в пикселях в этом масштабе. Эти промежутки, однако, исчезают, когда масштаб восстанавливается до 100%.

Мы попробовали два варианта. У обоих есть недостатки.

Оба делают изображение/скриншот дочерним элементом div рамки.

Вариант 1: значения заполнения

Мы использовали значения "padding", чтобы отрегулировать ширину, высоту и положение дочернего элемента div (т.е. Снимка экрана), чтобы он помещался внутри родительского элемента, рамки. Тем не менее, изображения с различными пропорциями могут выходить за рамки кадра или не заполнять кадр.

Вариант 2: обтравочный контур

Мы использовали обтравочные контуры для представления области внутри фрейма, но иногда пропуски были видны в зависимости от значения масштаба CSS. Мы не можем допустить пробелов.

Проблема с пропуском проиллюстрирована в коде и Codepen ниже.

Есть ли другой вариант?

Codepen (иллюстрирует пробелы): https://codepen.io/anon/pen/yWXvJE

.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;"><div class="backgroundColorBox" style="width: 163px; height: 335px; top: 17px; left: 4px; -webkit-mask-image: url(&quot;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&quot;); background-size: cover;"></div><div class="backgroundGraphicBox" style="width: 163px; height: 335px; top: 17px; left: 4px; -webkit-mask-image: url(&quot;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&quot;); background-size: cover;"></div><div class="foregroundBox" style="width: 163px;height: 335px;top: 17px;left: 4px;-webkit-mask-image: url(&quot;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&quot;);background-size: cover;background-image: url(https://uce9d8d4a8a6c69a057e9a584674.dl.dropboxusercontent.com/cd/0/inline/AhH2Z_q_te_Yu3IKd2cdiB0XMhJEzRdO4KP686rb3VdE1hxeIamOskpIoAhrxKegUAxERpAIyX3g0VABD7EU5S4JWe9X_Q1zdaS2hsoD_SpI4w/file#);"></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>

Ответы

Ответ 1

Другие ответы

Прежде чем я представлю свой собственный подход к источникам, я сначала обсудю ответ Рона Ройстона и покажу возможные проблемы/препятствия.

Рон Ройстон ответ

Вы уже указали на проблему с этим подходом:

это не работает, потому что, если рамка имеет закругленные углы, подобные этой, снимок экрана может все еще просматриваться в зависимости от размера фона

Возможное решение предоставлено kthornbloom:

Так что добавьте border-radius к элементу изображения, если ему нужны закругленные углы, верно?

Правильно! Но это работает только для некоторых изображений. Видите, вы не можете применить border-radius только к background-image. Вместо этого вы должны сделать это для самого контейнера.

Ну, в чем проблема? Просто добавьте достаточно маленький border-radius чтобы он не обрезал изображение, уменьшите background-image, и вы готовы к работе, верно?
На самом деле, нет! Вы должны решить, что делать с размером фонового изображения. Вы можете уменьшить его, но тогда вы не сможете использовать cover или что-то подобное в качестве background-size. Если у вас нет изображения, которое идеально вписывается в границы изображения смартфона, вы столкнетесь с проблемами. Кроме того, border-radius устареет, если вы уменьшите фоновое изображение, так как оно больше не касается границ.

  .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(&quot;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&quot;); 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>

Ответ 2

Вы можете создать div за рамкой, немного уменьшить его, чтобы граница была внутри границы телефона. Затем закруглите углы div и дайте ему переполниться: скрыто; Затем поместите изображение внутрь, задайте ему высоту и ширину 100% и поместите объект: cover; Вот один из моих сайтов с похожим эффектом, чтобы вы могли иметь ссылку. ссылка (телефоны видны на средних и больших экранах)

Ответ 3

Я думаю, что самый простой способ - применить изображение как background-image CSS, а затем использовать background-size contain или cover.

Масштабирование фоновых изображений

Свойство background-size CSS позволяет регулировать ширину и высоту фоновых изображений, переопределяя поведение по умолчанию, при котором фоновые изображения располагаются в полном размере. Вы можете масштабировать изображение вверх или вниз по желанию.

Ответ 4

Самое простое решение

Использование телефона с черным экраном и обтравочной маской. Там не будет видимых пробелов, и вы получите очень чистый код. Вы можете использовать background-size: cover или 100% 100% чтобы "покрыть" или "растянуть" изображение.

Итак, чтобы быть ясным... слои будут выглядеть так:

  • Слой 1 имеет фоновое изображение, показывающее телефон. У телефона есть сплошная черная область, где должен быть скриншот (экран). Этот слой показан на изображении ниже с синей рамкой.
  • Слой 2 имеет фоновое изображение, показывающее скриншот. Этот снимок экрана обрезается обтравочной маской в точную форму экрана (SVG), как это. Этот слой показан на изображении ниже с красной рамкой.

Слой 1 - телефон с черным экраном

enter image description here

Здесь вы видите телефон/изображение с черным экраном и прозрачным фоном.

Слой 2 - Скриншот изображения с обтравочной маской

enter image description here

Обратите внимание, что прозрачность вызвана обтравочной маской и/или радиусом границы. Сам скриншот не прозрачный (просто прямоугольный JPG). Также обратите внимание, что вы должны обрезать пустое пространство в SVG, чтобы упростить размещение этого слоя.

Код

Используйте этот простой HTML:

<div class='layer 1'>
  <div class='layer2'></div>
</div>

<svg width="0" height="0">
  <defs>
    <clipPath id="myClip">
      ... [add the complex clip path definition here]
    </clipPath>
  </defs>
</svg>

И немного CSS:

.layer1 {
  position: relative;  
  width: 500px; 
  padding-bottom: 150%;
  background: url(phone.png) center center / contain no-repeat;
  /*border: 1px solid blue;*/
}
.layer2 {
  position: absolute;
  width: 470px;
  top: 40px;
  left: 15px;
  padding-bottom: 150%;
  background: url(screenshot.jpg) center center / 100% 100% no-repeat;
  border-radius: 30px;
  clip-path: url(#myClip);
  /*border: 1px solid red;*/
}

Измените 100% 100% чтобы cover и или отрегулируйте процент. Когда вы измените его на покрытие, вы должны убедиться, что вы обрезали все пустое пространство этого слоя, чтобы у вас остался прямоугольник в красной линии. Обратите внимание, что любые повороты или преобразования должны быть добавлены к внешнему элементу (слой 1).

Поддержка браузера

Люди, похоже, беспокоятся об устаревших нестандартных браузерах. Я понял, но я использовал встроенный SVG, который в настоящее время поддерживается во всех основных браузерах. Только IE11, Edge18, Opera Mini, Blackberry и IE Mobile не поддерживают это. Если браузер не поддерживает clip-path со встроенным SVG, вы получите тот же результат, НО БЕЗ ЗАРЕЗКИ. Мне кажется разумным, так как эта проблема уменьшается с каждым днем.