CSS-live.ru

Фокус (и стили) по клику на SVG-элементе

Перевод статьи Click SVG Element to Focus (and Style) с сайта css-tricks.com, опубликовано на css-live.ru, автор — Крис Койер.

Читатель пишет:

Вы не могли бы помочь мне сделать SVG кликабельным с помощью CSS? Задача такая: есть SVG-элемент, и по клику на любую из его частей в этом месте должна появляться обводка? Во вторник у меня собеседование по телефону на работу в качестве SVG-иллюстратора и мне не хотелось бы облажаться.

Допустим, у меня есть карта США в <svg>, и выглядит это так:

<svg class="us" viewBox="0 0 500 400">

  <path d="..." class="wisconsin" />

  <polygon points="..." class="colorado" />

  <g class="michigan">
    <path d="..." class="michigan--up">
    <path d="..." class="michigan--main">
  </g>

  <!-- и т.д.-->

</svg>

Тогда каждый штат — это своего рода прямой потомок <svg>, и его селектором будет svg.us > *

Обычно при слове «кликабельный» я думаю о JavaScript. Вот так можно отслеживать клики для каждого штата. Мы также навесим класс на кликнутый штат.

var allStates = $("svg.us > *");

allStates.on("click", function() {
  
  allStates.removeClass("on");
  $(this).addClass("on");
  
});

Этот класс нужен для оформления. Вы говорили про обводку, так что сделаем её (и заодно покрасим).

.on {
  fill: pink;
  stroke: red;
  stroke-width: 2;
}

Тадам!

See the Pen Click State to Activate by Chris Coyier (@chriscoyier) on CodePen.

Но вы ПРОСИЛИ «кликабельность с помощью CSS«. А это посложнее. Обычно в CSS для этого используется :focus, но не думаю, что есть проверенный способ сделать фокусируемым сам SVG-элемент. Поговаривали (ещё давно) про атрибут focusable, но он так и не появился. Можно взять tabindex, как в HTML, и это вроде бы работает в некоторых браузерах, но рассчитывать на это нельзя. Думаю, лучший способ — это использовать якоря в SVG (серьёзно, их можно использовать и в SVG!), фокусируемые во всех браузерах. Затем применить стили :focus к якорю, которые по каскаду передаются в фигуру.

Амелия Беллами-Ройдс так и поступила в обсуждении на StackOverflow. Вот моя упрощённая версия:

<svg viewBox="0 0 95 50">
  <a xlink:href="#0">
    <circle cx="20" cy="25" r="5" data-Name="shape 1" data-tabindex="0" />
  </a>
  <a xlink:href="#0">
    <circle cx="40" cy="25" r="5" data-Name="shape 2" data-tabindex="0" />
  </a>
  <a xlink:href="#0">
    <circle cx="60" cy="25" r="5" data-Name="shape 3" data-tabindex="0" />
  </a>
  <a xlink:href="#0">
    <circle cx="80" cy="25" r="5" data-Name="shape 4" data-tabindex="0" />
  </a>
</svg>
a:focus {
  fill: pink;
  stroke: red;
  stroke-width: 1;
}

Этого достаточно:

See the Pen SVG with Focusable Elements by Chris Coyier (@chriscoyier) on CodePen.

P.S. Это тоже может быть интересно:

12 комментариев

      1. Спасибо, работает. Теперь следующая проблема.
        Надо чтобы блок/кнопка с текстом, которая появляется по клику ещё и увеличивалась (вместе с текстом).
        Сделал увеличение в стилях через transform: scale(1.5);
        Работает, но съезжает т.к. смещаются координаты. Решил сместить через transform: translate(-2%,-2%); Работает, но только по отдельности, как это сделать вместе?
        Такая запись не работает: transform: scale(1.5), translate(-5%,-1%);

        1. Запятая не нужна: transform: scale(1.5) translate(-5%,-1%);.

          Только учтите, что трансформации комбинируются, справа налево (вторая справа применяется к результату крайней правой, третья справа — к итоговому результату первых двух справа и т.д.). Так что, возможно, будет лучше поменять трансформации местами.

          Но вообще странно, что сдвигается. Может, лучше просто подогнать transform-origin, чтоб на месте оставалась правильная точка?

  1. всё равно пляшет от центра, даже так.
    transform-origin: center center;
    transform: matrix(1.2, 0, 0, 1.2, 0, 0);

    Ума не приложу как задать цетр трансформации для каждого объекта свой или хотя бы для все, но один, например по центру.

  2. Проблема решается только конкретным заданием центра через стиль для каждого элемента (в коде SVG) вот так, например style="transform-origin: 20px 25px;".
    универсального способа вывода всех увеличенных элементов в одно место через файл стилей так и не нашел.

Добавить комментарий для Максим Отменить ответ

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Получать новые комментарии по электронной почте. Вы можете подписаться без комментирования.