Como posso fazer uma escala svg com seu contêiner pai?

236

Eu quero ter uma escala de conteúdo do elemento svg embutido quando o tamanho não for nativo. É claro que eu poderia tê-lo como um arquivo separado e escalá-lo assim.

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

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

No entanto, quero adicionar estilos adicionais ao SVG através do CSS, portanto, vincular um externo não é uma opção. Como faço para fazer uma escala SVG embutida?

bjb568
fonte
2
tente precedentes em larguras e alturas svg.
Ncm 21/10
@ncm Como isso seria feito com o JS?
Mawg diz que restabelece Monica

Respostas:

458

Para especificar as coordenadas na imagem SVG independentemente do tamanho em escala da imagem, use o viewBoxatributo no elemento SVG para definir qual é a caixa delimitadora da imagem no sistema de coordenadas da imagem e use os atributos widthe heightpara definir o que a largura ou a altura estão em relação à página que contém.

Por exemplo, se você tiver o seguinte:

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

Ele será renderizado como um triângulo de 10 por 20 pixels:

Triângulo 10x20

Agora, se você definir apenas a largura e a altura, isso mudará o tamanho do elemento SVG, mas não dimensionará o triângulo:

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

Triângulo 10x20

Se você definir a caixa de exibição, isso fará com que ela transforme a imagem, de forma que a caixa especificada (no sistema de coordenadas da imagem) seja dimensionada para caber na largura e altura especificadas (no sistema de coordenadas da página). Por exemplo, para aumentar o triângulo para 100px por 50px:

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

Triângulo de 100 x 50

Se você quiser escalá-lo até a largura da janela de exibição HTML:

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

Triângulo de 300 x 150

Observe que, por padrão, a proporção é preservada. Portanto, se você especificar que o elemento deve ter uma largura de 100%, mas uma altura de 50px, ele será escalado apenas até a altura de 50px (a menos que você tenha uma janela muito estreita):

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

Triângulo de 100 x 50

Se você realmente deseja esticar horizontalmente, desative a preservação da proporção com 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>

Triângulo de 300 x 50

(observe que, enquanto nos meus exemplos eu uso uma sintaxe que funciona para incorporação em HTML, para incluir os exemplos como uma imagem no StackOverflow, em vez disso, estou incorporando em outro SVG, por isso preciso usar sintaxe XML válida)

Brian Campbell
fonte
1
Como você cria não apenas a viewBox preserveAspectRatio, mas também a caixa principal? Eu quero largura: 100%; height: auto para isso.
bjb568
1
@ Cara: Eu acho que o exemplo com width="100%"e sem altura especificada faz o que você quer. Eu adicionei imagens para demonstrar. Tem 100% de largura e aumenta a altura proporcionalmente. Se não é isso que você procura, tente esclarecer o que quis dizer?
Brian Campbell
1
Oh. Na verdade, não há problema. É apenas um bug do webkit. No Safari e Chrome, a altura "real" é 100% por padrão, não automática. Como eu contornaria isso então?
bjb568
4
@ Cara Ah, sim, entendo. Funciona bem no Firefox, mas não no Chrome ou Safari. De acordo com a especificação SVG , o Firefox parece estar correto; embora o valor padrão de widthe heightpara um elemento SVG seja 100%, essa não é a definição CSS de 100% (100% do bloco que contém), mas sim 100% da viewport especificada com base na proporção intrínseca ( que é calculado a partir de viewBoxquando isso é dado). Ainda não encontrei uma solução para esse problema que funcione no Chrome / Safari.
Brian Campbell
1
Isso funciona para mim. Primeiro, criei um atributo viewBox no elemento SVG e defino o valor como "0 0 [largura original do svg] [altura original do svg]". Em seguida, altero o atributo de largura do elemento SVG para "auto" e o atributo de altura para "100%". O contêiner também deve ter uma altura definida. Isso dimensiona o vetor para 100% da altura do contêiner, permitindo que a largura flutue. Por fim, defina a largura máxima do CSS do SVG como 100% para evitar o overshooting do contêiner.
Ryan Griggs
28

Após 48 horas de pesquisa, acabei fazendo isso para obter escala proporcional:

NOTA: Este exemplo é escrito com React. Se você não estiver usando isso, mude o material da caixa de camelo de volta para hífens (ou seja: mude backgroundColorpara background-colore mude o estilo de Objectvolta para a 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>

Aqui está o que está acontecendo no código de exemplo acima:

VIEWBOX

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

min-x, min-y, largura e altura

ou seja: viewbox = "0 0 1000 1000"

O Viewbox é um atributo importante, porque basicamente informa ao SVG qual o tamanho para desenhar e onde. Se você usasse CSS para criar o SVG 1000x1000 px, mas sua caixa de visualização fosse 2000x2000, veria o quarto superior esquerdo do seu SVG.

Os dois primeiros números, min-x e min-y, determinam se o SVG deve ser deslocado dentro da caixa de exibição.

Meu SVG precisa deslocar para cima / baixo ou esquerda / direita

Examine isto: viewbox = "50 50 450 450"

Os dois primeiros números deslocam o SVG para 50px para cima e para 50px, e os dois primeiros números são do tamanho da caixa de exibição: 450x450 px. Se o seu SVG é de 500 x 500, mas possui algum preenchimento extra, você pode manipular esses números para movê-lo dentro da "caixa de visualização".

Seu objetivo neste momento é alterar um desses números e ver o que acontece.

Você também pode omitir completamente a caixa de visualização, mas sua milhagem variará dependendo de todas as outras configurações que você tiver no momento. Na minha experiência, você encontrará problemas com a preservação da proporção, porque a caixa de visualização ajuda a definir a proporção.

PRESERVE ASPECT RATIO

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

Com base em minha pesquisa, existem muitas configurações diferentes de proporção, mas a padrão é chamada xMidYMid meet. Coloquei no meu para me lembrar explicitamente. xMidYMid meeta escala proporcional com base nos pontos médios X e Y. Isso significa que permanece centralizado na caixa de exibição.

LARGURA

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

Veja o meu código de exemplo acima. Observe como eu defino apenas largura, sem altura. Eu o defino como 100% para que preencha o contêiner em que está. É provavelmente o que mais contribui para responder a essa pergunta do Stack Overflow.

Você pode alterá-lo para o valor de pixel desejado, mas recomendo usar 100% como fiz para aumentar o tamanho máximo e controlá-lo com CSS por meio do contêiner pai. Eu recomendo isso, porque você obterá o controle "adequado". Você pode usar consultas de mídia e controlar o tamanho sem JavaScript louco.

ESCALAR COM CSS

Veja meu código de exemplo acima novamente. Observe como eu tenho essas propriedades:

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

Isso é adicional, mas mostra como permitir que o usuário redimensione o SVG enquanto mantém a proporção adequada. Como o SVG mantém sua própria proporção, você só precisa redimensionar a largura no contêiner pai e redimensionar conforme desejado.

Deixamos a altura em paz e / ou a definimos como automática e controlamos o redimensionamento com largura. Eu escolhi a largura porque geralmente é mais significativa devido a designs responsivos.

Aqui está uma imagem dessas configurações sendo usadas:

insira a descrição da imagem aqui

Se você leu todas as soluções nesta pergunta e ainda está confuso ou não vê o que precisa, confira este link aqui. Eu achei muito útil:

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

É um artigo massivo, mas divide praticamente todas as formas possíveis de manipular um SVG, com ou sem CSS. Eu recomendo a leitura enquanto você toma um café casualmente ou escolhe líquidos selecionados.

agm1984
fonte
Isso não parece funcionar para nenhum SVG - Se você não tiver controle da fonte SVG, esse método falhará quando o SVG tiver uma largura fixa.
user48956
@ user48956 Você sempre pode manipulá-lo após o fato com JavaScript.
Andrew
Sim - você sempre pode cutucar as entranhas de vários formatos de arquivo com uma programação - mas espera que exista um método que funcione para todos os tipos de ativos (por exemplo, PNGs) e não exija programação JavaScript.
User48956
21

Você desejará fazer uma transformação como tal:

com JavaScript:

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

Com CSS:

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

Embrulhe sua página SVG em uma tag de grupo e direcione-a para manipular a página inteira:

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

Nota : a escala 1.0 é 100%

Gary Hayes
fonte
7
Está bem. Eu não quero JS nisso. Existe uma maneira de transformá-lo para caber pai?
bjb568
@bj setAttribute é a mesma coisa que <tag attribute = "value"> #
315 john ktejik
17

Brincar e encontrar esse CSS parece conter o SVG no navegador Chrome até o ponto em que o contêiner é maior que a imagem:

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

Também parece estar funcionando no FF + IE 11.

Kerry7777
fonte
Isso resolveu o problema para mim. Eu só estava vendo o estouro no iOS. Obrigado!
Evan Mattson
5
Usar os dois max-width: 100%e max-height: 100%fará com que o svg sempre seja dimensionado para o contêiner sem nunca exceder ou perder sua proporção.
Gavin
2
@ Gavin max-height: 100%não funciona para mim, resolvido usando em vhvez de%
Pavel
2

alterar o arquivo SVG não era uma solução justa para mim; então, usei unidades CSS relativas .

vh, vw, %São muito úteis. Eu usei um CSS como height: 2.4vh;para definir um tamanho dinâmico para minhas imagens SVG.

canbax
fonte
1

Outra maneira simples é

transform: scale(1.5);
Kasim ŞEN
fonte
0

Ajustar o atributo currentScale funciona no IE (testei com o IE 11), mas não no Chrome.

Fabian Madurai
fonte