в радиусе CSS circle (), похоже, рассчитан неправильно - PullRequest
3 голосов
/ 17 января 2020

Меня некоторое время мучает всякий раз, когда я пытаюсь использовать функцию CSS circle () для некоторого отсечения, как в:

.red {
  	width: 200px;
        height: 300px;
        background: red;
        border: 2px solid black;
        clip-path: circle(69%);  /*barely cuts off the corners of the .red div */
}

/*  the full circle will enclose the entire box at around 71% or (sqrt(2)/2 * 100%)
 per Mozilla documentation and not at 100% as one might expect */
<div class='red'></div>

радиус никогда не рассчитывается так, как я ожидал. Рассматривая справку Mozilla MDN (https://developer.mozilla.org/en-US/docs/Web/CSS/basic-shape), они вычисляют ее следующим образом:



enter image description here



, что мне просто не кажется правильным. Я предположил бы, что они вычислили бы радиус окружности, которая охватывает прямоугольник элементов (div, img, et c) следующим образом:



enter image description here



но это, похоже, не так. Может кто-нибудь пролить некоторый свет на это. Это какая-то ошибка или я просто чего-то не понимаю?

1 Ответ

5 голосов
/ 17 января 2020

Это определено так, они никогда не предназначались для расчета радиуса, который вы показываете. Это также в спецификации .

Чтобы лучше понять, давайте рассмотрим квадрат. Вы можете иметь идеальный круг, если считаете 50% значением

.red {
  width: 200px;
  height: 200px;
  background: red;
  clip-path: circle(50%);
  border:2px solid;
  box-sizing:border-box;
}
<div class='red'></div>

Идея заключается в следующем:

enter image description here

R - это 'c', который вы вычисляете (зеленые линии), а r - используемая ссылка (линия зрачка). Вы можете легко увидеть, что r = R/sqrt(2) и R = sqrt(w² + h²). Объединение обоих даст нам:

r = sqrt(w² + h²)/sqrt(2)

Какую формулу вы видите на странице MDN.

Использование 50% этого значения внутри квадрата даст нам логический круг:

 r/2 = sqrt(w² + h²)/(2*sqrt(2)) = sqrt(2*w²)/(2*sqrt(2)) = w/2 (or h/2)

Чтобы покрыть весь квадрат, нам нужно значение, равное R/2, равное r/sqrt(2) = r/1.41 а поскольку r равно 100%, у вас будет 71%, которое вы обнаружили

.red {
  width: 200px;
  height: 200px;
  background: red;
  clip-path: circle(calc(100% / 1.44)); /* a little bogger  than 1.4 to better see*/
  border:2px solid;
  box-sizing:border-box;
}
<div class='red'></div>

Те же логики c применяются к неквадратной форме, где ширина и высота различны, но эталон остается тем же:

r = sqrt(w² + h²)/sqrt(2)

Исходя из вышеизложенного, мы можем сделать вывод, что 71% - это значение magi c, которое будет давать одинаковый результат независимо от формы, поскольку он зависит от радиуса окружности, охватывающей элементы прямоугольника 50% (или любое другое значение) даст другие результаты:

.red {
  width: 200px;
  height: 200px;
  background: red;
  clip-path: circle(69%); 
  border:2px solid;
  box-sizing:border-box;
}
<div class='red'></div>
<div class='red' style="width:300px;"></div>
<div class='red' style="width:100px;"></div>
<div class='red' style="width:50px;"></div>

Использование 50%

.red {
  width: 200px;
  height: 200px;
  background: red;
  clip-path: circle(50%); 
  border:2px solid;
  box-sizing:border-box;
}
<div class='red'></div>
<div class='red' style="width:300px;"></div>
<div class='red' style="width:100px;"></div>
<div class='red' style="width:50px;"></div>

Мы также можем думать, что любое значение, большее, чем 71%, бесполезно, так как оно всегда будет давать круг больше, чем наш элемент. Это правда, но мы не должны забывать, что у нас также есть позиция.

Пример вывода с использованием 100%, 200% и даже 300%!

.red {
  width: 200px;
  height: 200px;
  background: red;
  border:2px solid;
  box-sizing:border-box;
}
<div class='red' style="clip-path: circle(100% at  0    50%)"></div>

<div class='red' style="clip-path: circle(200% at -100% 50%)"></div>

<div class='red' style="clip-path: circle(300% at -200% 50%)"></div>

Я рассмотрю другое свойство, чтобы лучше убрать путаницу, которая radial-gradient.

.box {
  width:200px;
  height:200px;
  border:1px solid;
  background:radial-gradient(circle 50%, red ,blue);
}
<div class="box">

</div>

Приведенный ниже код предназначен для определения круга с радиусом, равным 50%, но он недействителен, поскольку мы не знаем ссылку:

Примечание: проценты здесь не допускаются; они могут использоваться только для указания размера эллиптического градиента, а не круглого. Это ограничение существует, потому что существует несколько разумных ответов относительно того, какой размер процент должен быть относительно . Будущий уровень этого модуля может предоставить возможность измерения кругов с процентами, возможно, с более четким контролем того, какое измерение используется. ref

Мы мы имеем дело с прямоугольными angular формами, поэтому мы можем использовать высоту, ширину и радиус, который вы рассчитываете, и т. д. c, и т. c. Многие варианты, поэтому они просто решили сделать его недействительным, но для clip-path они приняли решение и определили ссылку для использования percetange.

Кстати, вы можете лучше контролировать свой круг с учетом таких значений, как closest-side / farthest-side.

Ниже приведен круг, касающийся ближайших сторон (так же, как contain с фоном)

.red {
  width: 200px;
  height: 200px;
  background: red;
  clip-path:circle(closest-side); 
  border:2px solid;
  box-sizing:border-box;
}
<div class='red'></div>
<div class='red' style="width:300px;"></div>
<div class='red' style="width:100px;"></div>
<div class='red' style="width:50px;"></div>

Нижеследующее всегда дает нам круги, соприкасающиеся с самыми дальними сторонами (так же, как cover с фоном)

.red {
  width: 200px;
  height: 200px;
  background: red;
  clip-path:circle(farthest-side); 
  border:2px solid;
  box-sizing:border-box;
}
<div class='red'></div>
<div class='red' style="width:300px;"></div>
<div class='red' style="width:100px;"></div>
<div class='red' style="width:50px;"></div>

В сочетании с положением они могут дать интересные результаты:

.red {
  width: 200px;
  height: 200px;
  background: red;
  border:2px solid;
  box-sizing:border-box;
  transition:1s all;
}
<div class='red' style="clip-path:circle(farthest-side at left); "></div>
<div class='red' style="clip-path:circle(closest-side at 10% 10%); "></div>
<div class='red' style="clip-path:circle(farthest-side at top left); "></div>
<div class='red' style="clip-path:circle(closest-side at 40% 50%); "></div>
...