iOS/macOS Mail в темном режиме инвертирует цвета маски SVG, что приводит к изменению поведения маскирования

У меня есть изображение SVG, которое использует маскирование, чтобы вырезать отверстие в другой форме. Я упростил сложные формы, связанные с этим репрезентативным примером:

      <?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="256" height="256" viewBox="0 0 256 256" xml:space="preserve">
  <defs>
    <mask id="mask">
      <rect x="0" y="0" width="256" height="256" fill="#ffffff" />
      <circle cx="128" cy="128" r="32" fill="#000000" />
    </mask>
  </defs>
  <circle mask="url(#mask)" cx="128" cy="128" r="64" fill="#ff0000" />
</svg>

Это работает, как и ожидалось, т. е. рисует следующую форму пончика практически в любом контексте:

Однако, если я встраиваю SVG в электронное письмо и просматриваю его в macOS Mail (16.0, входит в состав Monterey 12.3.1) или iOS Mail при включенном темном режиме, я получаю эту своеобразную версию:

Похоже, что эти два приложения пытаются угадать интерпретацию SVG в темном режиме и ошибочно изменили маску на очень темно-серый (#232323, если бы мне пришлось угадывать, какой цвет фона самого приложения в темном режиме) и#000000на , тем самым в основном, но не полностью инвертируя поведение маскирования.

Это похоже на ошибку в Mail. Есть ли способ сказать Mail, чтобы он не связывался с цветами, определенными в маске? Я пробовал пару обходных путей, но их было недостаточно:

  • с использованиемprefers-color-schemeчтобы определить цвета маски, чтобы я мог «предварительно инвертировать» ее для темного режима, который работает здесь, но ломает изображение в любом другом контексте
  • скрывает окраску маски настолько, что не пытается ее инвертировать (например, с помощьюlinear-gradient(#ffffff,#ffffff)вместо того, чтобы просто#ffffff), который просто ломает изображения везде

2 ответа

Работая над предложением ccprog, я заставил этот SVG работать, как и ожидалось:

      <?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="256" height="256" viewBox="0 0 256 256" xml:space="preserve">
  <defs>
    <mask id="mask" mask-type="alpha">
      <path
        d="
          M 0 0
          L 256 0
          L 256 256
          L 0 256
          L 0 0
          M 128 96
          a 32 32 180 1 1 0 64
          a 32 32 180 1 1 0 -64
          z
        "
        fill-rule="evenodd"
      />
    </mask>
  </defs>
  <circle mask="url(#mask)" cx="128" cy="128" r="64" fill="#ff0000" />
</svg>

Помимо перехода наmask-type(чтобы мы маскировали то, что iOS/macOS Mail не попытается инвертировать), маску пришлось переопределить. В частности, он должен был заполнить все, что не входит в круг, используяfill-rule="evenodd"чтобы он заполнил нужные области. Я не мог просто переключить существующие фигуры на использование непрозрачности, потому чтоcircleхотелось бы иметь непрозрачность 0 (чтобы указать, что круг должен быть вырезан) иrectбудет проходить за ним с непрозрачностью 1, что сделает маску недействующей.

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

Вы также можете упростить свой SVG, используя составной путь.

«Вырезанная» область определяется вспомогательным путем с противоположным направлением пути.

В твоем случае:

      // outer circle - clockwise
M 128 64
a 64 64 0 0 1 0 128
a 64 64 0 0 1 0 -128
z

// innercircle - counter clockwise
M 128 96
a 32 32 180 1 0 0 64
a 32 32 180 1 0 0 -64
z  

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

Таким образом, вам не нужно никаких дополнительныхfill-rule- даже менее способные приложения, такие как средства просмотра изображений, могут безупречно отображать эти svg.
Эта концепция (отсечение путем чередования направлений траектории) фактически существует с самых первых технологий рисования Безье (например, постскриптум).

Вы можете создавать составные контуры в любом векторном редакторе (например, Adobe Illustrator, inkscape и т. д.), применяя операции с контурами, такие как вычитание/извлечение.

Дополнительная литература: порядок намотки правила заполнения

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