5

Для обрезки изображения используется clipPath

//HTML
<span class="clip-svg-inline2">
   <img src="templates/img/case-4.jpg" alt="">
</span>

//CSS
.clip-svg-inline2 {
  -webkit-clip-path: url("#clip-polygon2");
  clip-path: url("#clip-polygon2");
}
//SVG
<svg>
        <defs>
            <clipPath id="clip-polygon2" clipPathUnits="objectBoundingBox">
                <polygon points=".16 0, .40 .57, .40 1, .72 1, .72 .57, 1 0, .72 0, .57 .28, .48 0" />
            </clipPath>
        </defs>
    </svg>

https://jsfiddle.net/oxjatd5q/

Все работает. Но вопрос - возможно ли вместо polygon использовать свою форму, подключить код из собственного SVG или каким либо еще образом обрезать изображение именно по нарисованной фигуре.

Дело в том, что все фигуры clipPath построены на прямых и ломанных, а как нарисовать там округлое со всех сторон изображение? Картинка в примере с экраном старого телевизора не случайна, хотелось бы понять, как нарисовать подобный контур, где с каждой стороны дуги и округлые края.

Alexandr_TT
  • 110,146
  • 23
  • 114
  • 384
Amsterdam
  • 546
  • Ну сделай ту фигуру в самом svg и сделай ее background-ОМ элемента. background-image: url(путь svg файла); – Air Jan 14 '19 at 17:02
  • @Amsterdam так вам надо вырезать картинку по форме экрана TV? – Alexandr_TT Jan 14 '19 at 17:16
  • @Air бэкграунд изображения перекроется img, вложенным в блок. Задача обрезать именно вложенные изображения по контуру фигуры. – Amsterdam Jan 14 '19 at 17:18
  • Ты не понял. Картинка тоже должна быть в svg – Air Jan 14 '19 at 17:19
  • @Alexandr_TT да, нужно обрезать вложенное в блок изображение по форме экрана (но это просто пример формы, которую не получается создать при помощи фигур типа polygon и пр.), т.к. она со всем сторон состоит из дуг, которые там не задаются – Amsterdam Jan 14 '19 at 17:20
  • @Air да, не совсем понял возможность реализации, поэтому интересно было бы увидеть код – Amsterdam Jan 14 '19 at 17:21
  • @Amsterdam понял – Alexandr_TT Jan 14 '19 at 17:21
  • @Amsterdam, думаю, Александр тебе поможет... – Air Jan 14 '19 at 17:22
  • @Amsterdam, не потому что я не хочу, просто Александр в SVG крут... У него лучше получиться – Air Jan 14 '19 at 17:25
  • @Amsterdam загляните сюда, через час, полтора, подробно напишу как это делается – Alexandr_TT Jan 14 '19 at 17:25
  • 1
    @Alexandr_TT большое спасибо! Загляну обязательно, так или иначе, хотя уже и ночь на дворе) но реализовать необходимо. Полдня уже потрачено, но решить задачу никак не получается. Звездочки, символы, трапеции, все это получается, но с формой телевизора - просто затык.. – Amsterdam Jan 14 '19 at 17:28

3 Answers3

8

Чтобы получить точный контур, по которому будет вырезаться изображение необходимо сделать следующие шаги:

  • Загрузить картинку в векторный редактор с помощью файла svg и тегов <image>

<svg version="1.1" xmlns="http://www.w3.org/2000/svg" 
    xmlns:xlink="http://www.w3.org/1999/xlink"
       width="960" height="630" viewBox="0 0 960 630" preserveAspectRatio="xMinYMin meet" >

<image xlink:href="https://i.stack.imgur.com/pKxce.jpg" width="100%" height="100%" clip-path="url(#clip1)" /> </svg>

  • В векторном редакторе

    1. С помощью инструмента рисовать кривые Безье (цифра 1 на рисунке) нанести на контур узловые точки

введите сюда описание изображения

  1. Выделить узловые точки (цифра 2) для появления рычагов управления, с помощью которых будем корректировать форму кривой
  2. Преобразовать узловые точки в автоматически сглаженные.
  3. Сохраняем файл в векторном редакторе и забираем из него формулу патча, которая будет использоваться как clip-path, который точно повторяет экран TV

SVG clipPath

.container{
width:100%;
height:100%;
 }
  svg image {
 clip-path:url(#clip1);
}
<div class="container" >
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" 
    xmlns:xlink="http://www.w3.org/1999/xlink"
        viewBox="0 0 960 630" preserveAspectRatio="xMinYMin meet"  
    <defs>
     <clipPath id="clip1" >
   <path fill="black" d="m231.6 181.5c44.4-10.1 135.5-7.3 135.5-7.3 0 0 104-3.7 172.2 9.3 19.1 3.7 26.2 24.7 28 41.4 7 63.8 5.6 110 6 109.4 0 0 0.1 56.6-8 103.4-1.7 10.1-9.3 21.9-19.4 24-48.9 10.3-156.2 12-156.2 12 0 0-97.7-0.5-150.8-16-12.2-3.6-24.2-14.4-27.4-26.7-10.3-39.5-14.7-118.1-14.7-118.1 0 0-2.3-71.8 5.3-104.8 3-12.9 16.5-23.8 29.4-26.7z"/>
   </clipPath>
    </defs>

<image xlink:href="https://i.stack.imgur.com/pKxce.jpg" width="100%" height="100%" /> </svg>
</div>

Вырезаем другую картинку

.container{
width:100%;
height:100%;
 } 
 svg image {
 clip-path:url(#clip1);
 }
<div class="container" >
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" 
    xmlns:xlink="http://www.w3.org/1999/xlink"
        viewBox="0 0 960 630" preserveAspectRatio="xMinYMin meet" >  
    <defs>
     <clipPath id="clip1" >
   <path fill="black" d="m231.6 181.5c44.4-10.1 135.5-7.3 135.5-7.3 0 0 104-3.7 172.2 9.3 19.1 3.7 26.2 24.7 28 41.4 7 63.8 5.6 110 6 109.4 0 0 0.1 56.6-8 103.4-1.7 10.1-9.3 21.9-19.4 24-48.9 10.3-156.2 12-156.2 12 0 0-97.7-0.5-150.8-16-12.2-3.6-24.2-14.4-27.4-26.7-10.3-39.5-14.7-118.1-14.7-118.1 0 0-2.3-71.8 5.3-104.8 3-12.9 16.5-23.8 29.4-26.7z"/>
   </clipPath>
    </defs>

<image xlink:href="https://i.stack.imgur.com/VGmV9.jpg" width="100%" height="100%" /> </svg> </div>

SVG Mask

С масками можно получить более интересные варианты

Для справки можно почитать статью - Практические примеры применения масок svg

Вырезаем как clipPath, но оставляем полупрозрачным окружающий фон

.container{
width:100%;
height:100%;
 }
<div class="container" >
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" 
    xmlns:xlink="http://www.w3.org/1999/xlink"
        viewBox="0 0 960 630" preserveAspectRatio="xMinYMin meet" >  
    <defs>
     <mask id="msk1" >
   <rect width="100%" height="100%" fill="red" />
   <path fill="white" d="m231.6 181.5c44.4-10.1 135.5-7.3 135.5-7.3 0 0 104-3.7 172.2 9.3 19.1 3.7 26.2 24.7 28 41.4 7 63.8 5.6 110 6 109.4 0 0 0.1 56.6-8 103.4-1.7 10.1-9.3 21.9-19.4 24-48.9 10.3-156.2 12-156.2 12 0 0-97.7-0.5-150.8-16-12.2-3.6-24.2-14.4-27.4-26.7-10.3-39.5-14.7-118.1-14.7-118.1 0 0-2.3-71.8 5.3-104.8 3-12.9 16.5-23.8 29.4-26.7z"/>
   </mask>
    </defs>

<image xlink:href="https://i.stack.imgur.com/VGmV9.jpg" width="100%" height="100%" mask="url(#msk1)" /> </svg> </div>

Другой вариант

<!-- begin snippet: js hide: false console: true babel: false -->

В этом варианте вырезается экран и показывается фон, который лежит ниже и одновременно показывается сам TV.

.container{
width:100%;
height:100%;
 }
<div class="container" >
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" 
    xmlns:xlink="http://www.w3.org/1999/xlink"
        viewBox="0 0 960 630" preserveAspectRatio="xMinYMin meet"  >  
    <defs>
     <mask id="msk1" >
   <rect width="100%" height="100%" fill="black" />
   <path fill="white" d="m231.6 181.5c44.4-10.1 135.5-7.3 135.5-7.3 0 0 104-3.7 172.2 9.3 19.1 3.7 26.2 24.7 28 41.4 7 63.8 5.6 110 6 109.4 0 0 0.1 56.6-8 103.4-1.7 10.1-9.3 21.9-19.4 24-48.9 10.3-156.2 12-156.2 12 0 0-97.7-0.5-150.8-16-12.2-3.6-24.2-14.4-27.4-26.7-10.3-39.5-14.7-118.1-14.7-118.1 0 0-2.3-71.8 5.3-104.8 3-12.9 16.5-23.8 29.4-26.7z"/>
   </mask>
    </defs>
       &lt;image xlink:href="https://i.stack.imgur.com/pKxce.jpg" width="100%" height="100%"  /&gt; 
&lt;image xlink:href="https://i.stack.imgur.com/VGmV9.jpg" width="100%" height="100%" mask="url(#msk1)" /&gt;


</svg> </div>

Пример с анимацией изображения TV

Добавляются две строчки анимации,- горизонтального и вертикального перемещения фоновой картинки

<image xlink:href="https://i.stack.imgur.com/VGmV9.jpg" width="100%" height="100%" mask="url(#msk1)" >
          <animate attributeName="x" dur="10s" values="0;135;0" repeatcount="indefinite" />
           <animate attributeName="y" dur="10s" values="0;20;90;90;20;20;90;90;70;50;20;0" repeatcount="indefinite" />
           </image>    

.container{
width:100%;
height:100%;
 }
<div class="container" >
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" 
    xmlns:xlink="http://www.w3.org/1999/xlink"
        viewBox="0 0 960 630" preserveAspectRatio="xMinYMin meet"  >  
    <defs>
     <mask id="msk1" >
   <rect width="100%" height="100%" fill="black" />
   <path fill="white" d="m231.6 181.5c44.4-10.1 135.5-7.3 135.5-7.3 0 0 104-3.7 172.2 9.3 19.1 3.7 26.2 24.7 28 41.4 7 63.8 5.6 110 6 109.4 0 0 0.1 56.6-8 103.4-1.7 10.1-9.3 21.9-19.4 24-48.9 10.3-156.2 12-156.2 12 0 0-97.7-0.5-150.8-16-12.2-3.6-24.2-14.4-27.4-26.7-10.3-39.5-14.7-118.1-14.7-118.1 0 0-2.3-71.8 5.3-104.8 3-12.9 16.5-23.8 29.4-26.7z"/>
   </mask>
    </defs>
       &lt;image xlink:href="https://i.stack.imgur.com/pKxce.jpg" x="0" width="100%" height="100%"  /&gt;

&lt;image xlink:href="https://i.stack.imgur.com/VGmV9.jpg" width="100%" height="100%" mask="url(#msk1)" &gt;
   &lt;animate attributeName="x" dur="20s" values="0;135;0" repeatcount="indefinite" /&gt;
 &lt;animate attributeName="y" dur="20s" values="0;20;90;90;20;20;90;90;70;50;20;0" repeatcount="indefinite" /&gt;
       &lt;/image&gt; 


</svg> </div>

Alexandr_TT
  • 110,146
  • 23
  • 114
  • 384
  • спасибо за шикарно развернутый ответ! Но видите ли в чем дело - сами изображения находятся внутри слайдера, через тег img, поэтому и нужно было использовать вариант с присвоением класса элементу и передачи маски.

    Получается, можно создать в path нужную форму, методом, описанным вами, и загрузить способом, как показано на примере Qwertiy ?

    Правда, сейчас попробовал вставить ваш path с телевизором в тот пример, но почему то, ничего не отображается..

    – Amsterdam Jan 14 '19 at 19:20
  • 1
    суть понял, получается! Осталось подогнать маску под изображения в слайдере, и готово. Спасибо огромное вам за такой содержательный ответ! Вы крайне выручили! – Amsterdam Jan 14 '19 at 19:54
  • 1
    Пример с зомбоящиком мне очень понравился! – Bharatha Jan 15 '19 at 12:15
4
  1. В clip-path можно поместить любой path.
  2. В path достаточно методов для рисования, в том числе кривые безье и дуги.

html, body, main {
  margin: 0;
  height: 100%;
}

svg { width: 10em; float: right; position: relative; z-index: 1; }

main { background: linear-gradient(to bottom, green, blue); clip-path: url(#heart-clip); }

<svg viewBox="0 0 1 1" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
  <path id="heart" fill="orange" stroke="red" stroke-width=".01" d="M.1,0.3A.2,.2 0,0,1 .5,.3A.2,.20 0,0,1 .9,.3Q.9,.6 .5,.90Q.1,.6 .1,.3z" />

  <clipPath id="heart-clip" clipPathUnits="objectBoundingBox">
    <use xlink:href="#heart" />
  </clipPath>
</svg>

<main></main>

PS: Данный пример не будет работать в EDGE и IE.

Qwertiy
  • 123,725
4

Пример автора вопроса

Чтобы заработало, нужно было убрать clipPathUnits="objectBoundingBox" так как при этом параметре путь вычисляется в процентах или в долях от единицы

Подставил патч, полученный в первом ответе

.clip-svg-inline2 {
  display: block;
      -webkit-clip-path: url("#clip-polygon2");
      clip-path: url("#clip-polygon2");
    }
<span class="clip-svg-inline2">
       <img src="https://i-a.d-cd.net/1cda2es-960.jpg" alt="">
    </span>
&lt;svg&gt;
        &lt;defs&gt;
            &lt;clipPath id="clip-polygon2" &gt;
                &lt;path fill="black" d="m231.6 181.5c44.4-10.1 135.5-7.3 135.5-7.3 0 0 104-3.7 172.2 9.3 19.1 3.7 26.2 24.7 28 41.4 7 63.8 5.6 110 6 109.4 0 0 0.1 56.6-8 103.4-1.7 10.1-9.3 21.9-19.4 24-48.9 10.3-156.2 12-156.2 12 0 0-97.7-0.5-150.8-16-12.2-3.6-24.2-14.4-27.4-26.7-10.3-39.5-14.7-118.1-14.7-118.1 0 0-2.3-71.8 5.3-104.8 3-12.9 16.5-23.8 29.4-26.7z"/&gt;
            &lt;/clipPath&gt;
        &lt;/defs&gt;
    &lt;/svg&gt; </code></pre>

PS: Данный пример не будет работать в EDGE && IE

Qwertiy
  • 123,725
Alexandr_TT
  • 110,146
  • 23
  • 114
  • 384
  • понял, благодарю! Оказывается, всего одно значение мешало настроить вывод) – Amsterdam Jan 14 '19 at 20:04
  • @Amsterdam Я тоже доволен, что помог :) теорию изучайте, что означает каждый параметр. Это же быстро сделать, например https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/clipPathUnits и статью мою по маскам почитайте, на которую дал ссылку, там всё доходчиво изложено, но это понимание добыто кровью и потом, так сказать :))) Зато какие переспективы открываются, если осознанно использовать – Alexandr_TT Jan 14 '19 at 20:12
  • 1
    бесспорно. svg вещь очень мощная, позволяет реализовывать в верстке бурные фантазии дизайнеров) Сейчас встал как раз такой случай, потребовалось искать решение. Благо есть svg и добрые люди, которые помогут в непростой ситуации. Спасибо вам еще раз! Изучение этой темы конечно же продолжу. Очень полезная вещь) – Amsterdam Jan 14 '19 at 20:18
  • @Alexandr_TT, но ведь тогда он будет не responsive? – Qwertiy Jan 14 '19 at 21:19
  • @Alexandr_TT можно небольшой вопрос, касательно уже непосредтсвенно моего случая? Картинка обрезается сейчас вот таким образом: http://prntscr.com/m7b0j1 Правильно ли я понимаю, что это изза того, что "экран" обрамлен белой рамкой вокруг? – Amsterdam Jan 15 '19 at 05:01
  • @Amsterdam белый фон это то, что не попало в clipPath/ Пробуйте его подвинуть влево и вверх <clipPath id="clip-polygon2" > <path transform="translate(-120 200)" fill="black" – Alexandr_TT Jan 15 '19 at 06:56
  • @Alexandr_TT так совсем исчезло) Александр, а фигуру вы рисовали в Inkscape? В Иллюстраторе, как понимаю, можно сделать по аналогии, с помощью инструмента "Кривизна". Или удобнее использовать другой редактор? – Amsterdam Jan 15 '19 at 12:20
  • @Amsterdam рисовал в Inkscape, попробуйте подбирать значения translate, посмотрите внимательно, может ошибка в синтаксисе. Не получится, задайте новый вопрос, но подробно, с родными картинками и вашим кодом – Alexandr_TT Jan 15 '19 at 12:23
  • @Alexandr_TT в целом, все получается! Но, выходит, она обрезает конкретно заданную область. То есть, какого размера был svg, такую область по ширине и высоте обрежет. А возможно ли сделать, что бы обрезаемая фигурой область, растягивалась пропорционально ширине и высоте родительского блока, если тот будет менять свои размеры (например при адаптации страницы, или Hover эффекте, когда при наведении блок увеличивается по ширине и т.п) – Amsterdam Jan 16 '19 at 06:24
  • @Amsterdam Привет, задайте отдельный вопрос, где всё это и напишите, будет быстрее и легче. Во-первых я увижу ваш код реализации и пойму возможно это или нет. Во-вторых, у вас повышаются шансы получить ответ, здесь много отвечающих специалистов. – Alexandr_TT Jan 16 '19 at 06:56
  • @Alexandr_TT готово: https://ru.stackoverflow.com/questions/932679/Масштабируемый-clippath – Amsterdam Jan 16 '19 at 07:50
  • @Amsterdam увидел – Alexandr_TT Jan 16 '19 at 07:51