PerfectVector
Autor: Irene Kim9 min czytania

Jednostki SVG clipPath: dopasuj własny kształt do elementu docelowego

Wybierz jednostki SVG clipPath, znormalizuj sylwetkę i zachowaj jej proporcje. Przetestuj szerokie i wysokie elementy docelowe, zachowując otwory i geometrię źródłową.

Na tej stronie

Użyj clipPathUnits="objectBoundingBox", gdy kształt przycinający ma rozciągać się zgodnie z granicami elementu docelowego. Najpierw znormalizuj współrzędne kształtu. Użyj userSpaceOnUse, gdy potrzebujesz jawnego pozycjonowania lub równomiernego skalowania, które zachowuje proporcje kształtu.

Sama zmiana atrybutu nie przekształca ścieżki narysowanej w setkach jednostek w kształt o współrzędnych od zera do jednego. Może przesunąć niemal cały kształt przycinający poza element docelowy. W tym poradniku wykorzystujemy jedną autorską sylwetkę zakładki, aby pokazać zmianę współrzędnych, wynikające z niej zniekształcenie oraz wyśrodkowane dopasowanie, które zachowuje kwadratowy kształt otworu w formie rombu.

Przycinanie steruje widocznością. Nie przycina bazowych ścieżek do nowej, edytowalnej geometrii. Jeśli masz już czystą sylwetkę w SVG, użyj jej bezpośrednio; odrysowywanie ma znaczenie tylko wtedy, gdy musisz odzyskać tę sylwetkę z obrazu rastrowego.

Wybierz układ współrzędnych przed zmianą rozmiaru

Wartością domyślną jest userSpaceOnUse. Współrzędne przycinania należą wtedy do układu współrzędnych użytkownika elementu odwołującego się do przycinania. Przy objectBoundingBox lewy górny narożnik prostokąta ograniczającego element docelowy jest odwzorowywany na (0, 0), a prawy dolny — na (1, 1). Zobacz clipPathUnits reference.

WymaganieWybór układu współrzędnychCo musisz zrobić
Zachowaj kształt przycinający w znanych współrzędnych lokalnychuserSpaceOnUseUstaw ścieżkę względem elementu docelowego
Rozciągnij sylwetkę do każdego elementu docelowegoobjectBoundingBoxZnormalizuj ścieżkę źródłową i zaakceptuj różne skale na obu osiach
Dopasuj sylwetkę bez zniekształceńuserSpaceOnUseOblicz jednakową skalę dla obu osi oraz przesunięcie centrujące

Prostokąt ograniczający element docelowy nie musi odpowiadać viewBox zewnętrznego elementu SVG. Przycinanie grupy wykorzystuje granice tej grupy, które mogą różnić się od granic znajdującego się w niej prostokąta. Aby pierwszy test dał przewidywalny wynik, zastosuj przycinanie bezpośrednio do prostokąta o znanych wymiarach.

Porównaj szeroki element docelowy z wysokim

Zewnętrzne granice naszej zakładki to x=20, y=10, width=100, height=100. Jej romb jest drugą podścieżką w obrębie tej samej ścieżki. W teście stosujemy ją do prostokątów o wymiarach 200 × 120 i 120 × 200 w lokalnych jednostkach SVG.

Porównanie w przeglądarce kształtu przycinającego w formie zakładki na szerokich i wysokich prostokątach, pokazujące stałe współrzędne, rozciągnięte współrzędne prostokąta ograniczającego oraz równomierne dopasowanie z przezroczystymi otworami w kształcie rombu
Renderowanie w przeglądarce oryginalnego SVG zamieszczonego poniżej. Stałe współrzędne zachowują kształt o wymiarach 100 × 100; odwzorowanie na prostokąt ograniczający rozciąga go wraz z każdym elementem docelowym; równomierne dopasowanie zachowuje jego proporcje. Szachownica służy jako tło podglądu.

Kształt przycinający w środkowej kolumnie rozciąga się do granic każdego elementu docelowego, ale jego romb staje się szeroki lub wysoki. Prawa kolumna zachowuje kształt rombu i dolnego wcięcia, pozostawiając wolne miejsce wzdłuż dłuższej osi elementu docelowego. Wszystkich sześć otworów pozostaje przezroczystych.

Zapisz pełny przykład poniżej jako clippath-comparison.svg i otwórz go w przeglądarce. Kolumny odpowiadają kolejności na ilustracji. Górny rząd wykorzystuje szerokie prostokąty, a dolny — wysokie. Przesunięcia służące do rozmieszczenia przykładów nie zmieniają lokalnych wymiarów elementów docelowych.

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 720 470">
  <defs>
    <path id="silhouette" d="M20 10H120V110L70 85L20 110Z M70 30L85 45L70 60L55 45Z"/>
    <clipPath id="fixed" clipPathUnits="userSpaceOnUse">
      <use href="#silhouette" clip-rule="evenodd"/>
    </clipPath>
    <clipPath id="box" clipPathUnits="objectBoundingBox">
      <use href="#silhouette" clip-rule="evenodd"
        transform="matrix(.01 0 0 .01 -.2 -.1)"/>
    </clipPath>
    <clipPath id="wide-fit" clipPathUnits="userSpaceOnUse">
      <use href="#silhouette" clip-rule="evenodd"
        transform="matrix(1.2 0 0 1.2 16 -12)"/>
    </clipPath>
    <clipPath id="tall-fit" clipPathUnits="userSpaceOnUse">
      <use href="#silhouette" clip-rule="evenodd"
        transform="matrix(1.2 0 0 1.2 -24 28)"/>
    </clipPath>
  </defs>
  <g fill="#107c86">
    <rect x="0" y="0" width="200" height="120"
      transform="translate(20 30)" clip-path="url(#fixed)"/>
    <rect x="0" y="0" width="200" height="120"
      transform="translate(260 30)" clip-path="url(#box)"/>
    <rect x="0" y="0" width="200" height="120"
      transform="translate(500 30)" clip-path="url(#wide-fit)"/>
    <rect x="0" y="0" width="120" height="200"
      transform="translate(60 230)" clip-path="url(#fixed)"/>
    <rect x="0" y="0" width="120" height="200"
      transform="translate(300 230)" clip-path="url(#box)"/>
    <rect x="0" y="0" width="120" height="200"
      transform="translate(540 230)" clip-path="url(#tall-fit)"/>
  </g>
</svg>

Turkusowe wypełnienie należy do prostokątów. Ścieżka przycinająca nadaje im widoczny kontur. Zrzut ekranu dodaje etykiety i szachownicę wokół tego samego SVG; samodzielny plik ma przezroczyste tło.

Znormalizuj granice źródła, uwzględniając ich początek

Dla punktu (x, y) w źródle, którego granice określają (minX, minY, width, height), oblicz:

normalizedX = (x - minX) / width
normalizedY = (y - minY) / height

Tutaj są to (x - 20) / 100 i (y - 10) / 100. Macierz w definicji box wykonuje obie operacje bez przepisywania danych ścieżki:

matrix(0.01 0 0 0.01 -0.2 -0.1)

Odwzorowuje (20, 10) na (0, 0) oraz (120, 110) na (1, 1). Dzielenie przez 100 bez odjęcia współrzędnych początku pozostawiłoby kształt przesunięty wewnątrz elementu docelowego. Odwzorowanie na prostokąt ograniczający skaluje następnie znormalizowany wynik niezależnie wzdłuż szerokości i wysokości elementu docelowego.

Użyj rzeczywistych granic geometrii, którą chcesz znormalizować. viewBox może zawierać celowo pozostawioną pustą przestrzeń, więc jego wymiary nie muszą odpowiadać granicom sylwetki. Jeśli chcesz zachować tę przestrzeń, świadomie użyj prostokąta viewBox, zamiast przypadkowo mieszać oba pomiary.

W przypadku importowanej grafiki z zagnieżdżonymi transformacjami dokonuj pomiarów i normalizacji w jednym, spójnym układzie współrzędnych. Jeśli nie potrafisz z pewnością uwzględnić tych transformacji, zastosuj je do geometrii w edytorze przed skopiowaniem surowych danych ścieżki. Proces edycji SVG opisuje sprawdzanie ścieżek i grup przed przekazaniem pliku.

Zachowaj proporcje dzięki jednemu współczynnikowi skali

Dla prostokąta docelowego o lokalnym początku (0, 0), szerokości W i wysokości H użyj:

s  = min(W / width, H / height)
tx = (W - s * width) / 2 - s * minX
ty = (H - s * height) / 2 - s * minY
matrix(s 0 0 s tx ty)

Dla szerokiego elementu docelowego otrzymujemy s=1.2, tx=16 i ty=-12. Jego kształt przycinający zajmuje obszar x=40..160 i y=0..120. Dla wysokiego elementu docelowego otrzymujemy s=1.2, tx=-24 i ty=28, co umieszcza kształt przycinający w obszarze x=0..120 i y=40..160.

Są to jawnie określone macierze w userSpaceOnUse, więc przelicz je, gdy zmienią się lokalne wymiary elementu docelowego. Samo wyświetlenie całego SVG w innym rozmiarze CSS skaluje całą kompozycję razem. Zmiana znajdującego się w nim prostokąta z szerokiego na wysoki jest inną operacją.

Te obliczenia zakładają niezerową szerokość i wysokość źródła oraz brak nieuwzględnionego obrotu lub pochylenia. Jest to operacja dopasowania wewnątrz elementu: pozostawienie wolnego miejsca jest oczekiwane. Rozciąganie z użyciem jednostek prostokąta ograniczającego jest właściwe, gdy wypełnienie elementu docelowego ma większe znaczenie niż zachowanie proporcji motywu.

Zachowaj otwór w geometrii przycinania

Przykład umieszcza clip-rule="evenodd" na każdym elemencie use wewnątrz jego clipPath. Ścieżka, do której prowadzi odwołanie, zawiera zarówno zewnętrzny kształt zakładki, jak i podścieżkę rombu. Reguła określa, które obszary tego złożonego kształtu znajdują się wewnątrz obszaru przycinania.

Umieszczenie clip-rule na turkusowym prostokącie nie ustawia reguły kształtu przycinającego. Podobnie fill-rule używana do wypełnienia źródła nie zastępuje reguły przycinania. Dokumentacja MDN clip-rule reference wyjaśnia zakres jej działania wewnątrz clipPath.

Nie dodawaj osobnego białego rombu z oczekiwaniem, że odejmie on obszar od kształtu przycinającego. Sylwetki elementów potomnych w ścieżce przycinającej są łączone w widoczny obszar; ich kolory nie działają jak czarno-białe wartości maski. Aby uzyskać taki otwór, użyj ścieżki złożonej i odpowiedniej reguły określania wnętrza. Poradnik o wypełniających się otworach w SVG wyjaśnia strukturę ścieżek, na której opiera się to rozwiązanie.

Jeśli Twój projekt wymaga częściowo przezroczystych krawędzi lub widoczności opartej na luminancji, porównaj clipPath i maskę SVG na tym samym obrazie. Przycinanie przydaje się do wyznaczenia geometrycznej granicy; maska oferuje inny model widoczności. W przypadku jednokolorowej ikony wypełnianej za pomocą CSS zobacz poradnik o maskach SVG w CSS.

Sprawdź granice i wynik eksportu

Pozioma lub pionowa linia może mieć geometryczny prostokąt ograniczający o zerowej wysokości lub szerokości, nawet gdy jej obrys jest widoczny. Unikaj objectBoundingBox dla takich elementów docelowych i podczas normalizacji nie dziel przez zerowy wymiar źródła. SVG coordinate specification wyklucza szerokość obrysu z obliczeń tego prostokąta ograniczającego i ostrzega przed takimi przypadkami zdegenerowanej geometrii.

Przed przekazaniem pliku:

  1. Potwierdź, że identyfikator przycinania wskazany w odwołaniu istnieje i jest unikalny w dokumencie.
  2. Porównaj szerokie i wysokie elementy docelowe, uwzględniając najmniejszy otwór.
  3. Sprawdź zarówno granice źródła, jak i granice elementu docelowego w przewidzianych dla nich układach współrzędnych.
  4. Zapisz wyeksportowany SVG i otwórz go ponownie w aplikacji, w której będzie używany.
  5. Zachowaj oryginalną geometrię, jeśli kształt przycinający ma pozostać edytowalny.

CSS Masking specification stwierdza, że przycinanie zmienia renderowanie, a nie właściwą geometrię elementu. Ploter tnący lub aplikacja przetwarzająca geometrię może zatem wymagać rzeczywistego wyznaczenia części wspólnej ścieżek albo innej operacji w edytorze. Potwierdź wynikowe ścieżki w tej aplikacji; sam poprawny podgląd w przeglądarce nie dowodzi, że plik jest gotowy do cięcia.

W razie potrzeby odzyskaj sylwetkę z obrazu rastrowego

PerfectVector sprawdzi się, gdy własny motyw zachował się tylko jako PNG lub JPG, a do przycinania potrzebujesz edytowalnych konturów. Przekształć ten obraz w SVG, a następnie sprawdź zewnętrzną krawędź, wewnętrzne otwory i wszelkie niepożądane kształty tła, zanim wyodrębnisz sylwetkę. Wybierz kontury, które mają należeć do kształtu przycinającego; kolory źródła nie określają odrębnych poziomów przycinania.

Zachowaj istniejący oryginał grafiki wektorowej, jeśli go masz. Prostą geometryczną zakładkę można narysować bezpośrednio, tak jak w tym przykładzie. Wektoryzacja nie wybiera jednostek przycinania, nie normalizuje granic ani nie wykonuje trwałego przycięcia za pomocą operacji boolowskiej. Szersze wskazówki dotyczące wyboru źródła znajdziesz w omówieniu wektoryzacji obrazów.

Najczęściej zadawane pytania

Czy objectBoundingBox zachowuje proporcje kształtu? Nie. Odwzorowuje znormalizowany kształt przycinający niezależnie na szerokość i wysokość elementu docelowego. Użyj jednakowej skali dla obu osi w userSpaceOnUse, gdy sylwetka musi zachować proporcje.

Dlaczego zmiana clipPathUnits ukrywa mój kształt? Współrzędne ścieżki mogą nadal być wyrażone w oryginalnych jednostkach źródła. Znormalizuj je do układu współrzędnych względem elementu docelowego, uwzględniając początek źródła, albo zachowaj userSpaceOnUse i jawnie określ ich położenie.

Czy przycinanie usuwa ukryte części mojego SVG? Nie. Przycinanie zmienia to, co jest renderowane, zachowując bazową geometrię. Użyj odpowiedniej operacji edycji ścieżek, jeśli przekazywany plik wymaga trwale przyciętych konturów.

Źródła

  1. MDN — clipPathUnits — Wybór układu współrzędnych i domyślna interpretacja w przestrzeni użytkownika.
  2. MDN — clip-rule — Umiejscowienie reguły określania wnętrza w ścieżkach przycinających.
  3. W3C — SVG coordinate systems — Odwzorowanie na prostokąt ograniczający, wykluczenie obrysu i ograniczenia związane z zerowymi wymiarami.
  4. W3C — CSS Masking — Geometria przycinania, łączenie sylwetek i niezmienione ścieżki bazowe.

Jeśli Twój kształt przycinający powstaje z rastrowego motywu, przygotuj jego SVG w PerfectVector, sprawdź sylwetkę i otwory, a następnie przetestuj obie proporcje elementu docelowego, zanim wybierzesz rozciąganie lub równomierne dopasowanie.

Więcej z bloga

Zacznij od czystszego SVG,
który łatwiej edytować