Как создать криволинейную форму clipPath

121
08 августа 2019, 15:30

Для обрезки изображения используется 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 построены на прямых и ломанных, а как нарисовать там округлое со всех сторон изображение? Картинка в примере с экраном старого телевизора не случайна, хотелось бы понять, как нарисовать подобный контур, где с каждой стороны дуги и округлые края.

Answer 1

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

  • Загрузить картинку в векторный редактор с помощью файла 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> 
 
           <image xlink:href="https://i.stack.imgur.com/pKxce.jpg" width="100%" height="100%"  />  
	   <image xlink:href="https://i.stack.imgur.com/VGmV9.jpg" width="100%" height="100%" mask="url(#msk1)" /> 
 
	   
</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> 
 
           <image xlink:href="https://i.stack.imgur.com/pKxce.jpg" x="0" width="100%" height="100%"  /> 
           		 
	   <image xlink:href="https://i.stack.imgur.com/VGmV9.jpg" width="100%" height="100%" mask="url(#msk1)" > 
	      <animate attributeName="x" dur="20s" values="0;135;0" repeatcount="indefinite" /> 
		   <animate attributeName="y" dur="20s" values="0;20;90;90;20;20;90;90;70;50;20;0" repeatcount="indefinite" /> 
           </image>	 
 
	   
</svg>	 
</div>

Answer 2
  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.

Answer 3

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

Чтобы заработало, нужно было убрать 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> 
     
    <svg> 
            <defs> 
                <clipPath id="clip-polygon2" > 
                    <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> 
        </svg> 

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

READ ALSO
Поймать ввод текста в форме

Поймать ввод текста в форме

Разрабатываю поиск с использованием технологии AjaxКак поймать ввод текста вернее каждый введеный символ в форме с идентификатором search_text?

127