Круг SVG должен адаптироваться к CSS высоте сетки без наложения - PullRequest
8 голосов
/ 09 января 2020

В следующем примере круг адаптируется к ширине сетки и сохраняет свое соотношение сторон. По мере уменьшения ширины контейнера сужаются окружности ...

Когда высота меньше ширины, однако (второе поле), круг не сжимается, перекрывается за пределами сетки. Есть ли способ получить его? адаптироваться к высоте, сохраняя соотношение сторон?

.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>

Результат должен выглядеть следующим образом: enter image description here

Ответы [ 2 ]

8 голосов
/ 16 января 2020

Поработав некоторое время с этой проблемой, я понял, что с макетом сетки это не проблема.

Поскольку вы никогда не определяете height / max-height или width / max-width для вашего SVG, вычисляется width:auto и height:auto

Примечание: Я поднимаю max-height / max-width , поскольку они будут иметь приоритет над значениями ширина / высота .


Теперь, почему ваш макет landscape работает и ваш портрет макет не работает? Поскольку ширина «имеет приоритет» над вашей высотой.

И поэтому в макете блока автоматическая высота основывается на общей высоте потомков, а автоматическая ширина - на ширине содержащего блока. .

Источник - почему width: auto ведет себя иначе, чем высота: auto?

Это означает, что ваш SVG берет width из своего контейнера и height от его потомков.

В вашем примере SVG не имеет потомков, но имеет родителя с определенной max-width . Но что это значит для SVG высота ?

SVG рассчитывает свою высоту по соотношению intrisi c:

Если 'viewBox' в элементе 'svg' указан правильно:

  1. пусть viewbox будет окном просмотра, определенным атрибутом 'viewBox' в элементе 'svg'
  2. return viewbox.width / viewbox.height

Источник

И ваше отношение c составляет 1/1 = 1

Таким образом, вы заставляете свой height=width


Решение (я)

Решением является установка width или margin в ваш SVG зависит от пропорции вашего родительского деления.

В приведенном вами примере у вас есть пропорция 2: 1, поэтому ваш SVG должен иметь width:50% или margin: 0 25%.

Это означает, что если вы хотите установить другую пропорцию, вы должны отрегулировать ее соответствующим образом (см. Портрет-1-3 в приведенном ниже коде).

Установления правила CSS для каждой пропорции можно избежать ed, если height не является ограничением, поскольку вы можете определить width для вашего SVG и контейнера, позволяя элементам корректировать height, чтобы сохранить соотношение сторон.

Я также добавил последний пример, если кто-то не заботится о сохранении соотношения сторон, но должен содержать SVG в наборе height и width контейнера.

.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>

Обратите внимание, я не очень опытный в работе с SVG, и этот ответ является результатом исследований и большого количества экспериментов! Я был бы рад получить любые корректировки и / или исправления к моему ответу.

0 голосов
/ 21 января 2020

Добавьте к контейнеру c высоту и ширину вместе с max-height и max-width.

vw & vh можно использовать, чтобы сделать этот макет более гибким.

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

Таким образом, можно установить max-width: 100%; max-height: 100%; для svg, и оно не будет перекрываться.


-EDIT-

Поскольку окно просмотра SVG уже отрисованный с правильным соотношением сторон, можно переместить фон svg внутри самого svg, чтобы получить ожидаемый результат: тег cicle сделает свое дело.

Можно ли имитировать радиус границы с другой круговой тег внутри маски

Все остальные элементы svg должны быть помещены в маскированную группу. ie: <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>
...