Преобразование clipPath в :focus/:hover для нескольких экземпляров одного и того же значка

У меня есть значок SVG с некоторыми замаскированными фигурами, состоящими из:

  • book-1: замаскировано clipPath mask-1
  • book-2: замаскировано clipPath mask-2
  • book-3: не замаскирован, преобразование не требуется

В :focus / :hover я хочу mask-1 (но не book-1) и book-2 (но не mask-2) трансформироваться. Достаточно прямо…

<a href = "whatevs" class = "icon">
    <svg xmlns = "http://www.w3.org/2000/svg" viewBox = "0 0 44 44">
        <defs>
            <style>
                #book-1 {clip-path:url(#mask-1);} 
                #book-2 {clip-path:url(#mask-2);}
            </style>

            <clipPath id = "mask-1">
                <path class = "nudge" fill = "none" … />
            </clipPath>
            <clipPath id = "mask-2">
                <path fill = "none" … />
            </clipPath>
        </defs>

        <g id = "book-1">
            <path fill = "#fff" … />
        </g>
        <g id = "book-2">
            <path fill = "#fff" class = "nudge" … />
        </g>
        <path fill = "#fff" … /> <!-- book-3 -->
    </svg>
</a>

/* CSS */

.icon .nudge {
    transition: transform 0.2s ease-in;
}

.icon:focus .nudge, 
.icon:hover .nudge {
    transform: translate(-2px, 2px);
}

Но самое интересное начинается, когда на странице есть несколько экземпляров одного и того же значка.


У меня есть 3 ручки на CodePen, каждая с 2 экземплярами связанного значка, где:

  1. MRYwBqтерпит неудачу с:
    • подробный код, указывающий полный SVG каждый раз, когда он появляется
    • имена классов для book-1 и book-2
    • уникальные имена идентификаторов для каждого экземпляра только масок: mask-1 и mask-2
  2. qwEZrGработает с:
    • подробный код, указывающий полный SVG каждый раз, когда он появляется
    • уникальные идентификаторы для каждого экземпляра книг и масок: book-1, mask-1, book-2 и mask-2
  3. gybrvLтерпит неудачу с:
    • <symbol> экземпляр значка повторяется через <use> на странице

Мысли

  1. Это просто странно. Я хотел бы понять, почему это терпит неудачу так, как это происходит.
  2. Хорошо, что это работает, но я бы предпочел не повторять идентификаторы с помощью JavaScript после того, как они были отправлены на страницу без дифференциации.
  3. Это то, что я хотел бы заставить работать, но я не знаю, возможно ли это.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Введение в CSS
Введение в CSS
CSS является неотъемлемой частью трех основных составляющих front-end веб-разработки.
Как выровнять Div по центру?
Как выровнять Div по центру?
Чтобы выровнять элемент <div>по горизонтали и вертикали с помощью CSS, можно использовать комбинацию свойств и значений CSS. Вот несколько методов,...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
CSS: FlexBox
CSS: FlexBox
Ранее разработчики использовали макеты с помощью Position и Float. После появления flexbox сценарий полностью изменился.
0
0
67
1

Ответы 1

Поскольку для clip-path требуется идентификатор дочернего элемента svg def, в случае размещения на странице нескольких значков будет учитываться только одно из этих <clipPath> определений. Вот почему преобразование элементов <clipPath> недопустимо, так как это повлияет на все элементы, ссылающиеся на него. Как следствие, нам нужно решение, которое не перемещает и не изменяет эти элементы на основе :hover из :focus.

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

  1. Назначить путь клипа родительскому
  2. Переместите родителя в том направлении, в котором должна двигаться траектория клипа.
  3. Переместить всех детей в противоположном направлении

Пример этого трюка на основе предоставленного вами кода можно найти во фрагменте ниже:

a .nudge, a .unnudge {
  transition: transform 0.2s ease-in;
}

a:focus, 
a:hover {
    background-color: black;
}
    
a:focus .nudge, 
a:hover .nudge {
    transform: translate(-2px, 2px);
}

a:focus .unnudge, 
a:hover .unnudge {
    transform: translate(2px, -2px);
}


* {
  box-sizing: border-box;
}

a {
  display: block;
  background-color: red;
  padding: 0.5rem;
  border-radius: 50%;
  transition: background-color 0.2s ease-in;
  width: 60px;
  height: 60px;
}

body {
  font-family: sans-serif;
  line-height: 1.5;
  max-width: 36em;
  color: #333;
}

code {
  background: #e5e5e5;
  font-size: 1.125em;
  border-radius: 2px;
}
<p>Instance 1: 
  <a href = "#">
    <svg class = "icon" xmlns = "http://www.w3.org/2000/svg" viewBox = "0 0 44 44" width = "44" height = "44">
      <defs>
          <style>
              .book-1{clip-path:url(#mask-1-1);}
              .book-2{clip-path:url(#mask-2-1);}
          </style>
          <clipPath id = "mask-1-1">
              <path fill = "none" d = "M13.823,33.1V18.293a4.738,4.738,0,0,1,1.4-3.371S24.6,5.531,25.085,5.048L20.019-.019H8.143V33.1Z"/>
          </clipPath>
          <clipPath id = "mask-2-1">
              <path fill = "none" d = "M31.814,10.117,21.12,20.822a4.733,4.733,0,0,0-1.4,3.371V39H12V7H28.7Z"/>
          </clipPath>
      </defs>
      <g class = "nudge book-1" >
          <path fill = "#fff" class = "unnudge" d = "M22.736,5.72a1.193,1.193,0,0,0-1.686,0l-7.516,7.516a1.191,1.191,0,0,1-1.685-1.685l7.516-7.516a1.192,1.192,0,0,0-1.686-1.686L10.163,9.865h0a3.565,3.565,0,0,0-1.047,2.529h0V26.625h0a3.576,3.576,0,0,0,6.1,2.528h0l7.516-7.516a1.188,1.188,0,0,0,.349-.843V6.563A1.188,1.188,0,0,0,22.736,5.72Z"/>
      </g>
      <g class = "book-2">
          <path fill = "#fff" class = "nudge" d = "M21.723,22.193a4.733,4.733,0,0,1,1.4-3.371l5.865-5.871v-.488a1.192,1.192,0,0,0-2.035-.843l-7.516,7.516a1.192,1.192,0,0,1-1.686-1.686l7.516-7.516a1.191,1.191,0,1,0-1.685-1.685l-7.516,7.516a3.561,3.561,0,0,0-1.048,2.528h0V32.524h0a3.577,3.577,0,0,0,6.105,2.529h0l.6-.6Z"/>
      </g>
      <path fill = "#fff" d = "M34.535,17.52a1.19,1.19,0,0,0-1.685,0l-7.516,7.516a1.192,1.192,0,0,1-1.686-1.686l7.516-7.516a1.192,1.192,0,1,0-1.686-1.685l-7.516,7.516h0a3.564,3.564,0,0,0-1.047,2.528h0V38.424h0a3.576,3.576,0,0,0,6.1,2.529h0l7.516-7.516a1.188,1.188,0,0,0,.349-.843V18.363A1.188,1.188,0,0,0,34.535,17.52Z"/>
  </svg>
  </a>
</p>
<p>Instance 2, exact copy of instance 1: 
  <a href = "#">
    <svg class = "icon" xmlns = "http://www.w3.org/2000/svg" viewBox = "0 0 44 44" width = "44" height = "44">
      <defs>
          <style>
              .book-1{clip-path:url(#mask-1-1);}
              .book-2{clip-path:url(#mask-2-1);}
          </style>
          <clipPath id = "mask-1-1">
              <path fill = "none" d = "M13.823,33.1V18.293a4.738,4.738,0,0,1,1.4-3.371S24.6,5.531,25.085,5.048L20.019-.019H8.143V33.1Z"/>
          </clipPath>
          <clipPath id = "mask-2-1">
              <path fill = "none" d = "M31.814,10.117,21.12,20.822a4.733,4.733,0,0,0-1.4,3.371V39H12V7H28.7Z"/>
          </clipPath>
      </defs>
      <g class = "nudge book-1" >
          <path fill = "#fff" class = "unnudge" d = "M22.736,5.72a1.193,1.193,0,0,0-1.686,0l-7.516,7.516a1.191,1.191,0,0,1-1.685-1.685l7.516-7.516a1.192,1.192,0,0,0-1.686-1.686L10.163,9.865h0a3.565,3.565,0,0,0-1.047,2.529h0V26.625h0a3.576,3.576,0,0,0,6.1,2.528h0l7.516-7.516a1.188,1.188,0,0,0,.349-.843V6.563A1.188,1.188,0,0,0,22.736,5.72Z"/>
      </g>
      <g class = "book-2">
          <path fill = "#fff" class = "nudge" d = "M21.723,22.193a4.733,4.733,0,0,1,1.4-3.371l5.865-5.871v-.488a1.192,1.192,0,0,0-2.035-.843l-7.516,7.516a1.192,1.192,0,0,1-1.686-1.686l7.516-7.516a1.191,1.191,0,1,0-1.685-1.685l-7.516,7.516a3.561,3.561,0,0,0-1.048,2.528h0V32.524h0a3.577,3.577,0,0,0,6.105,2.529h0l.6-.6Z"/>
      </g>
      <path fill = "#fff" d = "M34.535,17.52a1.19,1.19,0,0,0-1.685,0l-7.516,7.516a1.192,1.192,0,0,1-1.686-1.686l7.516-7.516a1.192,1.192,0,1,0-1.686-1.685l-7.516,7.516h0a3.564,3.564,0,0,0-1.047,2.528h0V38.424h0a3.576,3.576,0,0,0,6.1,2.529h0l7.516-7.516a1.188,1.188,0,0,0,.349-.843V18.363A1.188,1.188,0,0,0,34.535,17.52Z"/>
  </svg>
  </a>
</p>

Обратите внимание, что это решение не идеально, и трюк с наличием двух противоположных движений, которые должны сводиться к отсутствию движения, может привести к небольшому рывку .book-1 в некоторых браузерах (например, Firefox).

Спасибо большое Петр. Хорошие идеи.

Jonathan Schofield 02.04.2019 00:58

Другие вопросы по теме