Responsive clip-path

119
11 августа 2019, 13:00

В следующем примере блок main (синезелёный градиент) обрезается при помощи clip-path и принимает форму сердечка. Однако видно, что он обрезается в масштабе 1:1, а хотелось бы, чтобы форма обрезки растягивалась по размеру блока (по аналогии с тем, как у background-size работает cover, contain или 100% 100%).

https://jsfiddle.net/a5goLyds/

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 100 100" 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" 
    d="M 10,30 
       A 20,20 0,0,1 50,30 
       A 20,20 0,0,1 90,30 
       Q 90,60 50,90 
       Q 10,60 10,30 z" 
  /> 
 
  <clipPath id="heart-clip"> 
    <use xlink:href="#heart" /> 
  </clipPath> 
</svg> 
 
<main></main>

Answer 1

К сожалению я не нашёл clip-path генераторов, которые позволяли бы рисовать кривыми линиями.

Есть генераторы, которые рисуют прямыми линиями по узловым точкам:

  1. https://codepen.io/jh3y/pen/XqVQqa
  2. http://bennettfeely.com/clippy/

Для многоугольника получаю вот такие значения

clip-path: polygon(50% 0%, 80% 10%, 100% 35%, 100% 70%, 80% 90%, 50% 100%, 20% 90%, 0% 70%, 0% 35%, 20% 10%);  

Преобразую для svg clip-path в доли от единицы:

<polygon points="0.5,0 0.8,0.1 1,0.35 1,0.7 0.8,0.9 0.5,1 0.20,0.9  0,0.7 0,0.35 0.2,0.1" />  

Чтобы получить масштабируемый clip-path, например при наведении курсора, нужно менять размер изображения в сторону увеличения, соответственно увеличится и clip-path, обрезая это изображение.

svg {} 
 
main { 
  width: 15%; 
  height: 15%; 
  background: linear-gradient(to bottom, green, blue); 
  clip-path: url(#heart-clip); 
  transition: 1s; 
} 
 
main:hover { 
  width: 100%; 
  height: 100%; 
}
<main> 
  <svg viewBox="0 0 1 1" xmlns:svg="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">  
  <defs> 
   <clipPath id="heart-clip" clipPathUnits="objectBoundingBox"> 
     <polygon   
     points="0.5,0 0.8,0.1 1,0.35 1,0.7  
     0.8,0.9 0.5,1 0.20,0.9  0,0.7 0,0.35 0.2,0.1" /> 
   </clipPath> 
  </defs> 
  </svg> 
</main>

Answer 2

Ничего не меняя в авторском примере - ввожу туда:

<use xlink:href="#heart" transform="scale(5), translate(-10 -10)"/>  

Итог:

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 100 100" 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" 
    d="M 10,30 
       A 20,20 0,0,1 50,30 
       A 20,20 0,0,1 90,30 
       Q 90,60 50,90 
       Q 10,60 10,30 z" 
  /> 
 
  <clipPath id="heart-clip"> 
    <use xlink:href="#heart" transform="scale(6), translate(-10 -10)"/> 
  </clipPath> 
</svg> 
 
<main></main>

В результате можно добиться любой пропорции и положения патча, регулируя лишь
transform="scale(what), translate(x y)"

Однако это ещё не всё.

Там, где было <clipPath id="heart-clip">, добавим clipPathUnits="objectBoundingBox", но при этом не забудем подкорректировать scale(), чтобы результат от "d" всегда был меньше единицы, как у Александра в полигоне.
- И вот оно, долгожданное счастье!

  • Responsive clip-path!!!

В песочнице будет легче менять размеры рабочей области, чтобы убедиться в искомой "респонсивности" элемента.
Но пробуем описать его и здесь:

html, body { 
  margin: 0; 
  background: repeating-linear-gradient(45deg, #666, #222, #666, #ea8, #666, #222, #666, #8ce, #666 4%) fixed; 
} 
 
svg { 
  width: 10rem; 
  float: right; 
  position: relative; 
  z-index: 1; 
} 
 
main { 
  height: 100vw; 
  clip-path: url(#heart-clip); 
  background: linear-gradient(to bottom, blue, red, green, transparent 70%); 
}
<svg viewBox="0 0 100 100"  
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" 
    d="M 10,30 
       A 20,20 0,0,1 50,30 
       A 20,20 0,0,1 90,30 
       Q 90,60 50,90 
       Q 10,60 10,30 z" /> 
 
  <clipPath id="heart-clip" clipPathUnits="objectBoundingBox"> 
    <use xlink:href="#heart" transform="scale(.007,.007), translate(-6 -6)"/> 
  </clipPath> 
</svg> 
 
<main></main>

Answer 3

Я бы реализовал так, а градиент уже реализовал бы в самом SVG

html, 
body { 
  width: 100%; 
  height: 100%; 
  background: #242424; 
} 
 
main { 
  width: 100%; 
  height: 100%; 
  background-image: url('data:image/svg+xml, <svg xmlns="http://www.w3.org/2000/svg" viewBox=" 0 0 100 100" width="100%" height="100%"><path id="heart" fill="orange" stroke="red" d="M 10,30 A 20,20 0,0,1 50,30  A 20,20 0,0,1 90,30 Q 90,60 50,90 Q 10,60 10,30 z"></path>);</svg>'); 
  background-repeat: no-repeat; 
  background-size: 100% 100%; 
}
<main></main>

READ ALSO
flexbox, текст не переноситься во вложенном flexbox в ie11

flexbox, текст не переноситься во вложенном flexbox в ie11

В IE11 из-за вложенного флексбокса текст не переходит на следующую строку, а растягивается на весь контент, если же поставить дляitem width:100%, блоки...

80
Эффект вождения пальцем по воде

Эффект вождения пальцем по воде

Не знал, как точно сформировать вопрос, поэтому сразу прошу прощения

120
Масштабируемый clipPath

Масштабируемый clipPath

Суть в том, что svg фигура в clipPath отрисовывается как есть, по тем самым размерам, с которыми создана

91
использовать другой маркер

использовать другой маркер

Использую либу highchartsВстал вопрос - как вместо маркеров использовать диаграмму

108