What formula do I use to get the circles always touch on the right place?

Viewed 70

In the example below, I created what I am trying to achieve.

I added the hover effect on the circles and then I used transform: scale(1.1); to fill in the gaps between the large circle and the ones on its side.

This one looks good when I resize the circle from 100px to 200px, but I need to make it work in any size. I used only css, but you can use JS to get the sizes and everything. I have a feeling that some trigonometry formula is needed but I have no clue how to approach it.

Thanks!

.circles {
  display: flex;
}
.circles__item {
  height: 100px;
  width: 100px;
  background: limegreen;
  border-radius: 50%;
  transform: scale(1);
  transform-origin: top center;
  transition: all 500ms ease-out;
}
.circles__item:hover {
  transform: scale(1.1);
  width: 200px;
  height: 200px;
  background-color: rebeccapurple;
}
<div class="circles">
  <div class="circles__item"></div>
  <div class="circles__item"></div>
  <div class="circles__item"></div>
  <div class="circles__item"></div>
  <div class="circles__item"></div>
</div>

2 Answers

I found the solution here and applied it on my case. I had to use JS since there was no way of finding the SQRT with css only.

let circles = document.querySelector('.circles');

let r1 = getComputedStyle(circles).getPropertyValue('--r1');
let r2 = getComputedStyle(circles).getPropertyValue('--r2');

let ab = parseFloat(r1) + parseFloat(r2);
let ad = parseFloat(r1) - parseFloat(r2);;
let bd = Math.sqrt(Math.pow(ab, 2) - Math.pow(ad, 2));
let negMargin = ab - bd;

circles.style.setProperty('--negMargin', `-${negMargin}px`);
.circles {
  --negMargin: 0;
  display: flex;
  flex-flow: row wrap;
  transform-origin: top left;
}

.circles__item {
  background: limegreen;
  border-radius: 50%;
  transform-origin: top center;
  transition: all .3s ease-in-out;
  margin: 0 0;
  height: calc(var(--r2) * 2px);
  width: calc(var(--r2) * 2px);
}

.circles__item:hover {
  height: calc(var(--r1) * 2px);
  width: calc(var(--r1) * 2px);
  margin-right: var(--negMargin);
  margin-left: var(--negMargin);
}

.circles__item:hover:last-child {
  margin-right: 0;
}

.circles__item:hover:first-child {
  margin-left: 0;
}
<div class="circles" style="--r1:180; --r2:80;">
  <div class="circles__item"></div>
  <div class="circles__item"></div>
  <div class="circles__item"></div>
  <div class="circles__item"></div>
</div>

You may give a try with CSS var() & calc() to set size and an average negative margin.

.circles {
  display: flex;
  --HW: 100px;/* can be reset on inline-style too */
  --HWhover : calc(var(--HW) * 2 );/*  * 2 doubles the size */
 
  
}
.circles__item {
  height: var(--HW);
  width:var(--HW);
  background: limegreen;
  border-radius: 50%;
  flex-shrink:0;
  transform-origin: top center;
  transition: all 500ms ease-out;
}
.circles__item:hover {
  width: var(--HWhover);
  height: var(--HWhover);
  margin: 0 calc( -0.04 * var( --HWhover) );
  background-color: rebeccapurple;
}
<div class="circles">
  <div class="circles__item"></div>
  <div class="circles__item"></div>
  <div class="circles__item"></div>
  <div class="circles__item"></div>
  <div class="circles__item"></div>
</div>
<div class="circles" style="--HW:150px;">
  <div class="circles__item"></div>
  <div class="circles__item"></div>
  <div class="circles__item"></div>
  <div class="circles__item"></div>
  <div class="circles__item"></div>
</div>
<div class="circles" style="--HW:10vw;">
  <div class="circles__item"></div>
  <div class="circles__item"></div>
  <div class="circles__item"></div>
  <div class="circles__item"></div>
  <div class="circles__item"></div>
</div>

Related