<div class="features">
<svg class="features__svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" height="33">
<defs>
<pattern id="pattern" width="82" height="33" patternUnits="userSpaceOnUse">
<line y1="22.5" x2="82" y2="22.5" fill="none" stroke="#738fc8" />
<line y1="16.5" x2="82" y2="16.5" fill="none" stroke="#738fc8" />
<line y1="10.5" x2="82" y2="10.5" fill="none" stroke="#738fc8" />
<polyline points="28 30.5 13.34 30.5 5.34 22.5" fill="none" stroke="#738fc8" />
<polyline points="48 2.5 34.94 2.5 26.94 10.5" fill="none" stroke="#738fc8" />
<circle cx="28" cy="30.5" r="2" fill="#738fc8" />
<circle cx="48" cy="2.5" r="2" fill="#738fc8" />
</pattern>
</defs>
<rect width="100%" height="100%" fill="url(#pattern)" />
</svg>
<div class="features__main"></div>
<ul class="features__list">
<li class="features__item">Lorem ipsum dolor sit amet consectetur adipisicing elit</li>
<li class="features__item">Odit reprehenderit nostrum culpa distinctio sapiente</li>
<li class="features__item">Possimus quis odit, atque ea mollitia id dolores minima cumque quaerat</li>
<li class="features__item">Molestiae nisi rem sit minima perferendis nemo</li>
<li class="features__item">Veritatis molestiae libero recusandae labore earum deleniti </li>
<li class="features__item">arum fugiat placeat quidem! Ratione quas fuga</li>
<li class="features__item">Lorem ipsum dolor sit amet consectetur adipisicing elit</li>
<li class="features__item">Odit reprehenderit nostrum culpa distinctio sapiente</li>
</ul>
</div>
* {
box-sizing: border-box;
}
.features {
position: relative;
z-index: 0;
}
.features__svg {
transform-origin: 0 50%;
position: absolute;
pointer-events: none;
width: 0;
transition: width 350ms;
z-index: -1;
}
.features__main {
position: absolute;
top: 50%;
left: 50%;
width: 25%;
transform: translate(-50%, -50%);
background-color: #cc07;
}
.features__main::before {
content: '';
display: block;
width: 100%;
padding-bottom: 100%;
}
.features__list {
display: flex;
flex-wrap: wrap;
list-style: none;
margin: 0;
padding: 0;
cursor: default;
}
.features__item {
width: 25%;
background-color: #ccc7;
padding: 15px;
margin-top: 15px;
margin-bottom: 15px;
}
.features__item:first-child,
.features__item:last-child {
margin-left: 37.5%;
margin-right: 37.5%;
}
.features__item:nth-child(2),
.features__item:nth-child(6) {
margin-left: 50px;
margin-right: calc(25% - 50px);
}
.features__item:nth-child(3),
.features__item:nth-child(7) {
margin-right: 50px;
margin-left: calc(25% - 50px);
}
.features__item:nth-child(4) {
margin-left: 0;
margin-right: 25%;
}
.features__item:nth-child(5) {
margin-left: 25%;
margin-right: 0;
}
const featuresEl = document.querySelector('.features');
const featuresSvgEl = featuresEl.querySelector('.features__svg');
const centerEl = featuresEl.querySelector('.features__main');
const svgHeight = 33;
let currentOverEl = null;
function getDistAngle(r1, r2) {
const dx = (r1.x + r1.width * 0.5) - (r2.x + r2.width * 0.5);
const dy = (r1.y + r1.height * 0.5) - (r2.y + r2.height * 0.5);
const dist = Math.hypot(dx, dy);
const angle = 180 * Math.atan2(dy, dx) / Math.PI;
return { dist, angle };
}
featuresEl.addEventListener('mouseover', (event) => {
const target = event.target;
const item = target.closest('.features__item');
if (!item || item === currentOverEl) return;
currentOverEl = item;
showItemJoin();
});
featuresEl.addEventListener('mouseout', (event) => {
const target = event.target;
const item = target.closest('.features__item');
if (!item) return;
currentOverEl = null;
hideItemJoin();
});
function showItemJoin() {
const parrentRect = featuresEl.getBoundingClientRect();
const itemRect = currentOverEl.getBoundingClientRect();
const centerRect = centerEl.getBoundingClientRect();
const { dist, angle } = getDistAngle(itemRect, centerRect);
const offsetX = itemRect.x + itemRect.width * 0.5 - parrentRect.x;
const offsetY = itemRect.y + itemRect.height * 0.5 - parrentRect.y - svgHeight * 0.5;
featuresSvgEl.style.width = `${dist}px`;
featuresSvgEl.style.transform = `translate(${offsetX}px, ${offsetY}px) rotate(${angle - 180}deg)`;
}
function hideItemJoin() {
featuresSvgEl.style.width = `0px`;
}
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.