Jak mogę wykonać skalę SVG za pomocą kontenera nadrzędnego?


235

Chcę mieć skalę zawartości wbudowanego elementu svg, gdy rozmiar nie jest rodzimy. Oczywiście mógłbym go mieć jako osobny plik i skalować w ten sposób.

index.html: <img src="foo.svg" style="width: 100%;" />

foo.svg: <svg width="123" height="456"></svg>

Chcę jednak dodać dodatkowe style do SVG poprzez CSS, więc połączenie zewnętrznego nie jest opcją. Jak zrobić wbudowaną skalę SVG?


2
wypróbuj precenty w szerokościach i wysokościach SVG.
ncm

@ncm Jak by to było zrobione z JS?
Mawg mówi o przywróceniu Moniki

Odpowiedzi:


457

Aby określić współrzędne w obrazie SVG niezależnie od przeskalowanego rozmiaru obrazu, użyj viewBoxatrybutu na elemencie SVG, aby zdefiniować pole ograniczające obrazu w układzie współrzędnych obrazu, a także użyj atrybutów widthi, heightaby zdefiniować szerokość lub wysokość odnoszą się do strony zawierającej.

Na przykład, jeśli masz następujące elementy:

<svg>
    <polygon fill=red stroke-width=0 
             points="0,10 20,10 10,0" />
</svg>

Będzie renderowany jako trójkąt 10 na 20 pikseli:

Trójkąt 10x20

Teraz, jeśli ustawisz tylko szerokość i wysokość, to zmieni rozmiar elementu SVG, ale nie skaluje trójkąta:

<svg width=100 height=50>
    <polygon fill=red stroke-width=0 
             points="0,10 20,10 10,0" />
</svg>

Trójkąt 10x20

Jeśli ustawisz pole widoku, spowoduje to przekształcenie obrazu w taki sposób, że dane pole (w układzie współrzędnych obrazu) zostanie przeskalowane w górę, aby pasowało do podanej szerokości i wysokości (w układzie współrzędnych strony). Na przykład, aby powiększyć trójkąt do rozmiaru 100 na 50 pikseli:

<svg width=100 height=50 viewBox="0 0 20 10">
    <polygon fill=red stroke-width=0 
             points="0,10 20,10 10,0" />
</svg>

Trójkąt 100 x 50

Jeśli chcesz przeskalować go do szerokości rzutni HTML:

<svg width="100%" viewBox="0 0 20 10">
    <polygon fill=red stroke-width=0 
             points="0,10 20,10 10,0" />
</svg>

Trójkąt 300 x 150

Należy pamiętać, że domyślnie współczynnik kształtu jest zachowany. Jeśli więc określisz, że element powinien mieć szerokość 100%, ale wysokość 50 pikseli, w rzeczywistości będzie skalowany tylko do wysokości 50 pikseli (chyba że masz bardzo wąskie okno):

<svg width="100%" height="50px" viewBox="0 0 20 10">
    <polygon fill=red stroke-width=0 
             points="0,10 20,10 10,0" />
</svg>

Trójkąt 100 x 50

Jeśli chcesz, aby rozciągał się w poziomie, wyłącz zachowanie proporcji obrazu za pomocą preserveAspectRatio=none:

<svg width="100%" height="50px" viewBox="0 0 20 10" preserveAspectRatio="none">
    <polygon fill=red stroke-width=0 
             points="0,10 20,10 10,0" />
</svg>

Trójkąt 300 x 50

(zauważ, że chociaż w moich przykładach używam składni, która działa na potrzeby osadzania HTML, aby uwzględnić przykłady jako obraz w StackOverflow, zamiast tego osadzam w innym SVG, więc muszę użyć prawidłowej składni XML)


1
Jak zrobić nie tylko viewBox preserveAspectRatio, ale także okno główne? Chcę szerokość: 100%; wysokość: auto dla tego.
bjb568,

1
@Dude: Myślę, że przykład z width="100%"i bez określonej wysokości robi to, co chcesz. Dodałem zdjęcia do zademonstrowania. Ma 100% szerokości i proporcjonalnie zwiększa wysokość. Jeśli nie tego szukasz, czy możesz spróbować wyjaśnić, co miałeś na myśli?
Brian Campbell

1
O. Właściwie nie ma problemu. To tylko błąd webkita. W Safari i Chrome „prawdziwa” wysokość wynosi domyślnie 100%, a nie auto. Jak miałbym to obejść?
bjb568,

4
@Dude, tak, rozumiem. Działa OK w przeglądarce Firefox, ale nie ma Chrome ani Safari. Zgodnie ze specyfikacją SVG Firefox wydaje się poprawny; podczas gdy wartość domyślną widthoraz heightdla elementu SVG jest w 100%, nie jest definicją CSS 100% (100% bloku zawierającego), lecz zamiast 100% wziernika, które zostały określone w oparciu o stosunek wewnętrzną kształtu ( który jest obliczany od viewBoxmomentu podania). Nie znalazłem jeszcze rozwiązania tego problemu, który działa w Chrome / Safari.
Brian Campbell

1
To działa dla mnie. Najpierw tworzę atrybut viewBox na elemencie SVG i ustawiam wartość na „0 0 [oryginalna szerokość svg] [oryginalna wysokość svg]”. Następnie zmieniam atrybut szerokości elementu SVG na „auto” i atrybut wysokości na „100%”. Pojemnik musi mieć również określoną wysokość. Spowoduje to skalowanie wektora do 100% wysokości pojemnika, umożliwiając swobodne przesunięcie szerokości. Na koniec ustaw maksymalną szerokość CSS SVG na 100%, aby zapobiec przekroczeniu kontenera.
Ryan Griggs

28

Po około 48 godzinach badań skończyłem tak, aby uzyskać proporcjonalne skalowanie:

UWAGA: Ta próbka jest napisana za pomocą React. Jeśli nie używasz, że zmiany case wielbłąd rzeczy z powrotem do kresek (tj zmian backgroundColordo background-colori zmienić styl Objectz powrotem do String).

<div
  style={{
    backgroundColor: 'lightpink',
    resize: 'horizontal',
    overflow: 'hidden',
    width: '1000px',
    height: 'auto',
  }}
>
  <svg
    width="100%"
    viewBox="113 128 972 600"
    preserveAspectRatio="xMidYMid meet"
  >
    <g> ... </g>
  </svg>
</div>

Oto, co dzieje się w powyższym przykładowym kodzie:

WIDOK

MDN: https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/viewBox

min-x, min-y, szerokość i wysokość

tj .: viewbox = "0 0 1000 1000"

Viewbox jest ważnym atrybutem, ponieważ w zasadzie informuje SVG, jaki rozmiar narysować i gdzie. Jeśli użyłeś CSS do zrobienia SVG o wymiarach 1000 x 1000 pikseli, ale Twój viewbox miał wymiary 2000 x 2000, zobaczysz lewą górną ćwiartkę SVG.

Pierwsze dwie liczby, min-x i min-y, określają, czy SVG powinien być przesunięty w polu widzenia.

Mój SVG musi się zmieniać w górę / w dół lub w lewo / w prawo

Zbadaj to: viewbox = "50 50 450 450"

Pierwsze dwie liczby przesuną twój plik SVG w lewo o 50 pikseli i w górę o 50 pikseli, a dwie pozostałe liczby to rozmiar pola widzenia: 450 x 450 pikseli. Jeśli Twój plik SVG ma wymiary 500 x 500, ale ma na nim dodatkowe dopełnienie, możesz manipulować tymi liczbami, aby przenosić je w „polu widzenia”.

Twoim celem w tym momencie jest zmiana jednej z tych liczb i zobaczenie, co się stanie.

Możesz również całkowicie pominąć pole widzenia, ale wtedy twój przebieg będzie się różnić w zależności od każdego innego ustawienia, jakie masz w tym czasie. Z mojego doświadczenia wynika, że ​​napotkasz problemy z zachowaniem współczynnika kształtu, ponieważ viewbox pomaga zdefiniować współczynnik kształtu.

ZACHOWAJ PROPORCJE

MDN: https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/preserveAspectRatio

Z moich badań wynika, że ​​istnieje wiele różnych ustawień współczynnika kształtu, ale domyślnie nazywa się to xMidYMid meet. Nakładam to na moje, aby wyraźnie sobie przypomnieć. xMidYMid meetsprawia, że ​​skaluje się proporcjonalnie w oparciu o punkt środkowy X i Y. Oznacza to, że pozostaje wyśrodkowany w polu podglądu.

SZEROKOŚĆ

MDN: https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/width

Spójrz na mój przykładowy kod powyżej. Zauważ, jak ustawiam tylko szerokość, bez wysokości. Ustawiłem go na 100%, aby wypełniał pojemnik, w którym się znajduje. To prawdopodobnie najbardziej przyczynia się do odpowiedzi na pytanie przepełnienia stosu.

Możesz go zmienić na dowolną wartość piksela, ale zalecam użycie 100%, tak jak zrobiłem, aby powiększyć go do maksymalnego rozmiaru, a następnie kontrolować za pomocą CSS za pośrednictwem kontenera nadrzędnego. Polecam to, ponieważ uzyskasz „odpowiednią” kontrolę. Możesz używać zapytań o media i kontrolować rozmiar bez szalonego JavaScript.

SKALOWANIE Z CSS

Ponownie spójrz na mój przykładowy kod powyżej. Zwróć uwagę, jak mam te właściwości:

resize: 'horizontal', // you can safely omit this
overflow: 'hidden',   // if you use resize, use this to fix weird scrollbar appearance
width: '1000px',
height: 'auto',

Jest to dodatkowe, ale pokazuje, jak zezwolić użytkownikowi na zmianę rozmiaru SVG przy zachowaniu odpowiedniego współczynnika proporcji. Ponieważ SVG zachowuje swój własny współczynnik kształtu, wystarczy zmienić rozmiar kontenera nadrzędnego, a jego rozmiar zmieni się zgodnie z potrzebami.

Wysokość zostawiamy w spokoju i / lub ustawiamy ją na auto, i kontrolujemy zmianę rozmiaru za pomocą szerokości. Wybrałem szerokość, ponieważ często jest bardziej znacząca ze względu na responsywne projekty.

Oto obraz używanych ustawień:

wprowadź opis zdjęcia tutaj

Jeśli czytasz wszystkie rozwiązania zawarte w tym pytaniu i nadal jesteś zdezorientowany lub nie rozumiesz, czego potrzebujesz, sprawdź ten link tutaj. Uważam to za bardzo pomocne:

https://css-tricks.com/scale-svg/

Jest to ogromny artykuł, ale rozkłada się praktycznie każdy możliwy sposób manipulowania SVG, z CSS lub bez. Zalecam przeczytanie go podczas swobodnego picia kawy lub wyboru wybranych płynów.


Wydaje się, że to nie działa w przypadku żadnego SVG - jeśli nie masz kontroli nad źródłem SVG, ta metoda zawiedzie, gdy SVG ma stałą szerokość.
user48956,

@ user48956 Zawsze możesz nim manipulować za pomocą JavaScript.
Andrew

Tak - zawsze możesz wtrącić się do wnętrza różnych formatów plików za pomocą programu - ale masz nadzieję, że będzie metoda, która działa dla wszystkich rodzajów zasobów (np. PNG) i nie wymaga programowania JavaScript.
user48956,

21

Będziesz chciał wykonać transformację jako taką:

z JavaScript:

document.getElementById(yourtarget).setAttribute("transform", "scale(2.0)");

Z CSS:

#yourtarget {
  transform:scale(2.0);
  -webkit-transform:scale(2.0);
}

Zawiń swoją stronę SVG w tag Group jako taki i ukierunkuj ją, aby manipulować całą stroną:

<svg>
  <g id="yourtarget">
    your svg page
  </g>
</svg>

Uwaga : Skala 1.0 wynosi 100%


7
Dobrze. Nie chcę w tym JS. Czy istnieje sposób, aby przekształcić go tak, aby pasował do rodzica?
bjb568,

@bj setAttribute to to samo, co <tag attribute = "value">
john ktejik

17

Bałagan i okazało się, że ten CSS zawiera plik SVG w przeglądarce Chrome do momentu, gdy kontener jest większy niż obraz:

div.inserted-svg-logo svg { max-width:100%; }

Wydaje się również działać w FF + IE 11.


To rozwiązało problem dla mnie. Jednak widziałem tylko przepełnienie w iOS. Dzięki!
Evan Mattson,

5
Użycie obu max-width: 100%i max-height: 100%sprawi, że svg zawsze będzie skalować się do kontenera bez przepełnienia lub utraty współczynnika kształtu.
Gavin

2
@Gavin max-height: 100%nie działa dla mnie, rozwiązany przy użyciu vhzamiast%
Pavel

2

zmiana pliku SVG nie była dla mnie sprawiedliwym rozwiązaniem, więc zamiast tego użyłem względnych jednostek CSS .

vh, vw, %Są bardzo wygodne. Użyłem CSS, jak height: 2.4vh;ustawić dynamiczny rozmiar moich obrazów SVG.



Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.