Стилизация и анимация текста SVG

280
25 марта 2018, 19:35

Хотелось бы рассмотреть ряд примеров стилизации текста и как использовать pattern & mask в связке с какими-то эффектами.

1. "Гусеничный" stroke (linearGradient & animate):

2. Текст, отбрасывающий от себя тень из
диагональных линий (pattern & mask):

3. Заполнение текста водой (SVG(pattern & mask) & CSS(@keyframes)):

P.S. В данном вопросе присутствуют примеры, взятые из открытого доступа(2 и 3). Вопрос создан с целью привлечь к SVG и показать его возможности.

Answer 1

Добавление и стилизация svg текста в растровую картинку

Допустим нам необходимо добавить текст к существующей растровой картинке в стиле диалога, комикса.
При этом необходимо, чтобы изображение и текст были адаптивны,- сохраняли взаимное расположение при изменении размера.

Пошаговая инструкция:

  • Добавляем растровую картинку в SVG

<image xlink:href="https://i.stack.imgur.com/6HVU6.jpg" width="400" height="300"/>

  • Рисуем в векторном редакторе контур, где будет расположен текст

    <path d="M350 280a400 400 0 0 0 4 -150a100 60 0 1 0 -14 4a400 400 0 0 1 10 146z"/>

  • Добавляем текст внутрь контура. К сожалению в svg нет автоматического переноса текста, как в HTML, но есть возможность ручного переноса текста с помощью атрибута <tspan>

  • При необходимости делаем более тонкую регулировку размера, позиции контейнера и текста

    <g transform="scale(1.1) translate(-40 0)" >

  svg { 
  width:40%; 
  height:40%; 
   } 
   text { 
   font-family: Lobster; 
  font-size:24px; 
  text-anchor:middle; 
  fill:#474447; 
  }  
  path { 
  fill:#fff; 
  stroke:#474447; 
  stroke-width:2; 
 }
 <link href='https://fonts.googleapis.com/css?family=Lobster|Raleway' rel='stylesheet' type='text/css'> 
    <link href="google-font.css" rel="stylesheet" type="text/css">  
     
 <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 400 300" preserveAspectRatio="xMinYMin meet"> 
 
 <image xlink:href="https://i.stack.imgur.com/6HVU6.jpg" width="400" height="300"/> 
 <g transform="scale(1.1) translate(-40 0)" > 
 <path     stroke-miterlimit="50" d="M350 280a400 400 0 0 0 4 -150a100 60 0 1 0 -14 4a400 400 0 0 1 10 146z"/> 
 <text> 
  <tspan x="302" y="60" >Вы вызываете</tspan> 
  <tspan x="302" y="85" >больше проблем,</tspan> 
  <tspan x="302" y="110">чем пользы.</tspan> 
 </text>  
 </g> 
</svg>

Картинка и текст адаптивны.
Работает во всех современных браузерах + IE11, Edge

Answer 2

Постепенно будем рассматривать и создавать подобные примеры.

Первый пример
  1. Помещаем наш текст в <symbol></symbol>.

Элемент <symbol> используется для определения объектов графического шаблона, которые могут быть созданы элементом <use>

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="400" height="400"> 
  <symbol id="text"> 
    <text font-size="5em" text-anchor="middle" x="160" y="55">Some text</text> 
  </symbol> 
  <use xlink:href="#text"/> 
</svg>

  1. Делаем произвольный gradient с помощью <linearGradient></linearGradient>.Думаю здесь всё понятно, его можно подключать к различным элементам холста. В данном примере мы "залили" фон текста gradient'ом, но это не всё, что он может. Мы можем применить gradient для stroke и не только.

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="400" height="400"> 
  <symbol id="text"> 
    <text font-size="5em" text-anchor="middle" x="160" y="55">Some text</text> 
  </symbol> 
  <linearGradient id="grad"> 
    <stop offset="0%" stop-color="red"/> 
    <stop offset="50%" stop-color="black"/> 
    <stop offset="100%" stop-color="blue"/> 
  </linearGradient> 
  <use xlink:href="#text" fill="url(#grad)"/> 
</svg>

  1. "Нарисуем" контур для текста. Также попробуем изменять атрибут stroke-dashoffset с помощью <animate/>.

Атрибут stroke-dashoffset определяет смещение stroke относительно начального положения

Атрибут stroke-dasharray имеет от 2х и больше значений. Первое значение определяет длину линии, а второе - пробел между линиями

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="400" height="100"> 
  <symbol id="text"> 
    <text text-anchor="middle" x="160" y="55">Some text</text> 
  </symbol> 
  <linearGradient id="grad"> 
    <stop offset="0%" stop-color="red"/> 
    <stop offset="60%" stop-color="black"/> 
    <stop offset="100%" stop-color="blue"/> 
  </linearGradient> 
  <use xlink:href="#text" stroke-dashoffset="0" stroke-dasharray="10 15" fill="none" stroke-width="3" stroke="url(#grad)" font-size="5em"> 
    <animate attributeName="stroke-dashoffset" values="250;0" dur="7s" repeatCount="indefinite"/> 
  </use> 
</svg>

  1. Можно приступать к самому "гусеничному" эффекту. Мы должны наложить текст на текст и изменить атрибуты stroke-dashoffset & stroke-dasharray.

    Первый пример готов:

@import url(https://fonts.googleapis.com/css?family=Open+Sans:800); 
* { 
  margin: 0; 
  padding: 0; 
} 
 
body { 
  background-color: #000000; 
  display: flex; 
  justify-content: center; 
  align-items: center; 
  font-family: Open Sans; 
  text-transform: uppercase; 
  letter-spacing: 5px; 
}
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/2000/svg" version="1.1"> 
  <symbol id="stroke-dash"> 
    <text text-anchor="middle" x="50%" y="50%">Stroke</text> 
  </symbol> 
  <linearGradient id="linear" x1="0%" y1="0%" x2="100%" y2="0%"> 
    <stop offset="0%" stop-color="#05a"/> 
    <stop offset="100%" stop-color="#0a5"/> 
  </linearGradient> 
  <use xlink:href="#stroke-dash" stroke="url(#linear)" stroke-dasharray="10 1" stroke-width="3" stroke-dashoffset="0" font-size="4em"> 
    <animate attributeName="stroke-dashoffset" values="250;0" dur="15s" repeatCount="indefinite"/> 
  </use> 
  <use xlink:href="#stroke-dash" stroke="url(#linear)" stroke-dasharray="10 15" stroke-width="3" stroke-dashoffset="0" font-size="4em"> 
    <animate attributeName="stroke-dashoffset" values="250;0" dur="15s" repeatCount="indefinite"/> 
  </use> 
</svg>

Второй пример

P.S. В данном примере мы ознакомимся с pattern & mask.

  1. Попробуем использовать pattern на любом квадрате, заполнив его кругами:

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

<link href='https://fonts.googleapis.com/css?family=Cabin+Condensed:700' rel='stylesheet' type='text/css'> 
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1"> 
  <defs> 
    <pattern id="pattern" width="10" height="10" patternUnits="userSpaceOnUse"> 
      <circle id="circle" cx="5" cy="5" r="5" fill="#000"/> 
    </pattern> 
  </defs> 
  <rect x="0" y="0" width="250" height="250" fill="url(#pattern)"/> 
</svg>

  1. Теперь опробуем pattern & mask.

mask в нашем контексте является поверхностным слоем, который скрывает часть контента.

.stripes { 
  width: 100px; 
  height: 50px; 
  mask: url("#mask"); 
} 
 
.red { 
  fill: red; 
} 
 
.blue { 
  fill: blue; 
}
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/2000/svg" version="1.1" height="150" width="150"> 
  <defs> 
    <pattern id="strokeEffect" width="1" height="3" patternUnits="userSpaceOnUse" patternTransform="rotate(45)"> 
      <rect x="0" y="0" width="1" height="1" fill="#fff"/> 
    </pattern> 
    <mask id="mask"> 
      <rect height="100%" width="100%" style="fill: url(#strokeEffect)"/> 
    </mask> 
  </defs> 
  <rect class="stripes red" y="0"/> 
  <rect class="stripes" y="50"/> 
  <rect class="stripes blue" y="100"/> 
</svg>

  1. Воссоздадим второй пример, используя вышеперечисленное.

    Второй пример готов:

body { 
  background-color: #2e2e2e; 
}
<link href='https://fonts.googleapis.com/css?family=Cabin+Condensed:700' rel='stylesheet' type='text/css'> 
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="620" height="500"> 
  <defs> 
    <pattern id="strokeEffect" width="1" height="3" patternUnits="userSpaceOnUse" patternTransform="rotate(45)"> 
      <rect x="0" y="0" width="1" height=".8" fill="#ffffff"/> 
    </pattern> 
    <text id="text" x="250" y="100" font-size="5em" text-anchor="middle" letter-spacing="15" font-family="'Cabin Condensed'">Some text</text> 
    <mask id="mask"> 
      <rect x="0" y="0" width="100%" height="100%" fill="#fff"/> 
      <use x="-6" y="-6" stroke="#000" stroke-width="5" xlink:href="#text" opacity="1" fill="#000"/> 
    </mask> 
  </defs> 
  <use x="6" y="6" xlink:href="#text" opacity="1" fill="url(#strokeEffect)" mask="url(#mask)"/>  
  <use x="0" y="0" xlink:href="#text" fill="#fff"/> 
</svg>

Третий пример
  1. Первым делом рассмотрим код:

body { 
  background: #141414; 
  text-align: center; 
} 
 
.water-fill { 
  -webkit-animation: wave 0.7s infinite linear, fill-up 10s infinite ease-out alternate; 
  animation: wave 0.7s infinite linear, fill-up 10s infinite ease-out alternate; 
} 
 
@-webkit-keyframes wave { 
  0% { 
    x: -400px; 
  } 
  100% { 
    x: 0; 
  } 
} 
 
@keyframes wave { 
  0% { 
    x: -400px; 
  } 
  100% { 
    x: 0; 
  } 
} 
 
@-webkit-keyframes fill-up { 
  0% { 
    height: 0; 
    y: 130px; 
  } 
  100% { 
    height: 160px; 
    y: -30px; 
  } 
} 
 
@keyframes fill-up { 
  0% { 
    height: 0; 
    y: 130px; 
  } 
  100% { 
    height: 160px; 
    y: -30px; 
  } 
}
<link href='https://fonts.googleapis.com/css?family=Cabin+Condensed:700' rel='stylesheet' type='text/css'> 
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="575px" height="120px" viewBox="0 0 575 120" xml:space="preserve"> 
  <defs> 
    <pattern id="water" width=".25" height="1.1" patternContentUnits="objectBoundingBox"> 
      <path fill="white" d="M0.25,1H0c0,0,0-0.659,0-0.916c0.083-0.303,0.158,0.334,0.25,0C0.25,0.327,0.25,1,0.25,1z"/> 
    </pattern> 
    <text id="text" transform="matrix(1 0 0 1 -8 117)" font-family="'Cabin Condensed'" font-size="161">LOADING</text> 
    <mask id="text_mask"> 
      <use xlink:href="#text" fill="white"/> 
    </mask> 
  </defs> 
<rect class="water-fill" mask="url(#text_mask)" fill="url(#water)" width="1600" height="120"/> 
</svg>

  1. Делаем выводы:)

    2.1. Происходит смещение pattern по оси X.
    2.2. Эффект волны происходит за счёт ширины rect, которая равна 1600 и отрицательному смещению по оси X от -400 до 0. Мы можем поэкспериментировать, то есть изменить значения и посмотреть что выйдет:

    P.S. Результат не впечатляет, думаю вы разобрались почему так происходит. Если нет, значит вот краткий ответ: Мы делаем шире rect, в то время как pattern"подстраивается" под эту ширину, после этого мы смещаем rect по оси X. 2.3. Далее мы вставляем его в mask, voilà, эффект волны для текста готов:)

.water-fill { 
  animation: wave 0.7s infinite linear, fill-up 10s ease-out alternate; 
} 
 
@keyframes wave { 
  0% { 
      /*New*/ 
    x: -200px; 
  } 
  100% { 
    x: 0; 
  } 
} 
 
@keyframes fill-up { 
  0% { 
    y: 120px; 
    height: 0; 
  } 
  100% { 
    y: 0; 
    height: 120px; 
  } 
}
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> 
  <defs> 
    <pattern id="water" width="0.25" height="1" patternContentUnits="objectBoundingBox"> 
      <path fill="dodgerblue" d="M0.25,1H0c0,0,0-0.659,0-0.916c0.083-0.303,0.158,0.334,0.25,0C0.25,0.327,0.25,1,0.25,1z"/> 
    </pattern> 
  </defs>	 
  <!--New (width)--> 
  <rect class="water-fill" fill="url(#water)" width="400" height="120"/> 
</svg>

READ ALSO
Почему-то не показываются маленькие и большие иконки на сайте

Почему-то не показываются маленькие и большие иконки на сайте

Почему-то не показываются маленькие иконки на сайте

168
Изменение стилей блока с помощью javascript

Изменение стилей блока с помощью javascript

Есть два блока, надо сделать функцию на javascript, чтобы по нажатию на кнопку 1 блок принял стиль display: block;, а второй display:none;

176
Фиксированная позиция при прокрутке

Фиксированная позиция при прокрутке

В шапке веб-страницы расположены якоря как менюШапка при прокрутке веб-страницы вниз получает фиксированную позицию

223