O círculo SVG deve se adaptar à altura da grade CSS sem sobrepor


8

No exemplo a seguir, o círculo se adapta à largura da grade e mantém sua proporção. À medida que a largura do recipiente diminui, os círculos diminuem com ele ...

Porém, quando a altura é menor que a largura (segunda caixa), o círculo não diminui as sobreposições fora da grade. Existe uma maneira de adaptá-lo à altura, mantendo a proporção?

.container {
	display: grid;
	background-color: greenyellow;
	margin: 5px;
	min-height: 10px;
	min-width: 10px;
}

.portrait {
		max-height: 100px;
		max-width: 200px;
}

.landscape {
		max-height: 200px;
		max-width: 100px;
}

.aspect-ratio {
	grid-column: 1;
	grid-row: 1;
	background-color: deeppink;
	border-radius: 50%;
 align-self: center;
	justify-self: center;
}
<div class="container landscape">
  <svg class="aspect-ratio" viewBox="0 0 1 1"></svg>
</div>

<div class="container portrait">
  <svg class="aspect-ratio" viewBox="0 0 1 1"></svg>
</div>

O resultado deve ficar assim: insira a descrição da imagem aqui


Você tem a possibilidade de editar o código svg?
thetont 21/01

Respostas:


8

Depois de mexer algum tempo com esse problema, percebi que isso não é um problema com o layout da grade.

Como você nunca define altura / altura máxima ou largura / largura máxima para o seu SVG, o que está sendo calculado é width:autoeheight:auto

Nota: Eu trago max-height / max-width, pois eles teriam prioridade sobre os valores de largura / altura .


Agora, por que o layout da paisagem funciona e o retrato não funciona? Porque a largura está "priorizando" sua altura.

E é por isso que, no layout do bloco, uma altura automática é baseada na altura total dos descendentes e uma largura automática é baseada na largura do bloco que o contém.

Fonte - Por que width: auto se comporta de maneira diferente de height: auto?

Isso significa que seu SVG está retirando o widthcontêiner e os heightdescendentes.

No seu exemplo, seu SVG não tem descendentes, mas tem um pai com uma largura máxima definida . Mas o que isso significa para a altura do SVG ?

O SVG está calculando sua altura através da razão intrísica:

Se a 'viewBox' no elemento 'svg' estiver especificada corretamente:

  1. deixe viewbox ser a viewbox definida pelo atributo 'viewBox' no elemento 'svg'
  2. retornar viewbox.width / viewbox.height

Fonte

E sua proporção intrísica é 1/1 = 1

Então você está forçando sua height=width


As soluções)

A solução está configurando a widthou a marginpara o seu SVG, dependendo da proporção da sua div principal.

No exemplo que você deu, você tem uma proporção de 2: 1, então seu SVG deve ter width:50%ou margin: 0 25%.

Isso significa que, se você deseja definir uma proporção diferente, deve ajustar em conformidade (veja retrato-1-3 no código abaixo).

A definição de uma regra CSS para cada proporção pode ser evitada se heightnão houver uma restrição, pois você pode definir a widthpara o SVG e o contêiner, permitindo que os elementos ajustem heightpara manter a proporção.

Também adicionei o exemplo final, se alguém não se preocupa em manter a proporção, mas precisa conter o SVG em um conjunto heighte em um widthcontêiner.

.container {
  display: grid;
  background-color: greenyellow;
  margin: 5px;
  min-height: 10px;
  min-width: 10px;
}

.portrait {
  max-height: 100px;
  max-width: 200px;
}


/* Add 25% margin left and right to center the image  OR set the image width to 50% */

.portrait>.aspect-ratio {
  margin: 0 25%;
  /*
    or 
    
    width:50%;
  */
}

.landscape {
  max-height: 200px;
  max-width: 100px;
}

.aspect-ratio {
  grid-column: 1;
  grid-row: 1;
  background-color: deeppink;
  border-radius: 50%;
  align-self: center;
  justify-self: center;
}


/* Set fixed max-height and max-width rule (33% proportion)  */

.portrait-1-3 {
  max-height: 100px;
  max-width: 300px;
}


/* Align image with the new proportion */

.portrait-1-3>.aspect-ratio {
  margin: 0 33.33%;
  /*
    or 
    
    width:33.3%;
  */
}


/* Removed max-height and let the container adjust the height according to the max-width rule and the proportion set  */

.portrait-any-height {
  max-width: 400px;
}


/* Height will be adjusted through the width/margin defined here, so 10% width will correspond to 40px of height (10%*400px)*(aspect ratio=1)*/

.portrait-any-height>.aspect-ratio {
   width:10%;
}


/* Set fixed max-height and max-width rule (proportion doesn't matter)  */

.portrait-squeezed {
  max-height: 100px;
  max-width: 300px;
}


/* Make sure SVG complies with the the given max with and height (squeezing your svg)  */

.portrait-squeezed>.aspect-ratio {
  max-height: inherit;
  max-width: inherit;
}
<div class="container landscape">
  <svg class="aspect-ratio" viewBox="0 0 1 1"></svg>
</div>

<div class="container portrait">
  <svg class="aspect-ratio" viewBox="0 0 1 1"></svg>
</div>

<div class="container portrait-1-3">
  <svg class="aspect-ratio" viewBox="0 0 1 1"></svg>
</div>

<div class="container portrait-any-height">
  <svg class="aspect-ratio" viewBox="0 0 1 1"></svg>
</div>

<div class="container portrait-squeezed">
  <svg class="aspect-ratio" viewBox="0 0 1 1"></svg>
</div>

Note que eu não sou muito proficiente trabalhando com SVGs e essa resposta é resultado de pesquisas e muita experimentação! Ficaria feliz em receber quaisquer ajustes e / ou correções na minha resposta.


Obrigado pela explicação detalhada ... Devo notar que sua pesquisa infelizmente retornou os mesmos resultados que os meus. Parece não haver solução para meus requisitos: 1. A taxa de proporção SVG é fixa. 2. a proporção de aspecto do contêiner é variável / desconhecida 3. o tamanho do contêiner é limitado por altura e largura, dependendo do ambiente (por exemplo, tamanho da janela do navegador) A solução proposta, configurando a largura do SVG para uma determinada porcentagem do contêiner, funcionaria se o contêiner tinha proporção fixa, mas não.
Th3S4mur41

Desistir da altura máxima também não funciona, isso significaria apenas mover a questão do estouro para o pai
Th3S4mur41

Com esses três requisitos, parece que não há uma solução, ou seja, usando apenas CSS. Está usando Javascript para calcular a largura apropriada de SVG fora de questão?
H. Figueiredo

É isso que minha solução atual está fazendo, que eu gostaria de evitar;)
Th3S4mur41

Espero que a proporção ajude a resolver isso, mas não tenho certeza disso. drafts.csswg.org/css-sizing-4/#aspect-ratio
Th3S4mur41

0

Adicione ao recipiente altura e largura específicas ao lado de altura e largura máx.

as unidades vw e vh podem ser usadas para tornar esse layout mais flexível.

  max-height: 100px;
  max-width: 200px;
  width: 100vw;
  height: 100vh;

Dessa forma, é possível definir max-width: 100%; max-height: 100%;o svg e ele não se sobrepõe.


-EDITAR-

Como a caixa de exibição svg já é renderizada com a proporção correta, é seguro mover o fundo svg dentro do próprio svg para obter o resultado esperado: uma tag cicle fará o truque.

É possível imitar o raio da borda com outra marca de círculo dentro de uma máscara

Todos os outros elementos do svg devem ser colocados dentro de um grupo mascarado. ou seja:<g mask="url(#mask)">

.container {
  display: grid;
  background-color: greenyellow;
  margin: 5px;
  min-height: 10px;
  min-width: 10px;
}

.portrait {
  max-height: 100px;
  max-width: 200px;
  width: 100vw;
  height: 100vh;
}

.landscape {
  max-height: 200px;
  max-width: 100px;
  width: 100vw;
  height: 100vh;
}

.aspect-ratio {
  grid-column: 1;
  grid-row: 1;
  align-self: center;
  justify-self: center;
  max-width: 100%;
  max-height: 100%;
}

.aspect-ratio .bkg{
  fill: deeppink;
}
<div class="container landscape">
  <svg class="aspect-ratio" viewBox="0 0 1 1">
    <mask id="mask">
      <circle cx=".5" cy=".5" r=".5" fill="#fff"/>
    </mask>
    <circle cx=".5" cy=".5" r=".5" class="bkg"/>
    <g  mask="url(#mask)">

    </g>
  </svg>
</div>

<div class="container portrait">
  <svg class="aspect-ratio"viewBox="0 0 1 1">
    <mask id="mask">
      <circle cx=".5" cy=".5" r=".5" fill="#fff"/>
    </mask>
    <circle cx=".5" cy=".5" r=".5" class="bkg"/>
    <g  mask="url(#mask)">

    </g>
  </svg>
</div>


1
A pergunta especificada "Existe uma maneira de adaptá-la à altura, mantendo a proporção", que o seu exemplo não. É uma maneira de forçar o SVG para dentro do contêiner, mas não produzirá o resultado pretendido. É o mesmo que o último exemplo da minha resposta em que o svg é compactado para caber no contêiner
H. Figueiredo

A explicação pode ser um pouco confusa, mas com a solução sugerida, a altura do svg se adapta à altura do contêiner.
thetont 21/01

Mas não mantém a proporção SVG ! Você viu o resultado desejado que o OP postou?
H. Figueiredo

Oh, uau ... Acabei de verificar com o Chrome e agora entendo o que você está dizendo. Eu o codifiquei no Firefox e, com esse navegador, funciona como pretendido, não esperava que o resultado fosse tão diferente. My bad
thetont

Na verdade, esse é um comportamento bastante interessante, acho que o Firefox e o Chrome calculam de maneira diferente para 100%? Enfim, todos cometemos erros, caso contrário, o SO não existiria: D
H. Figueiredo
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.