До недавнего времени верстка элементов по кругу была головной болью: либо мы использовали абсолютное позиционирование «на глаз», либо подключали громоздкие JS-скрипты для расчета top и left. С появлением нативной поддержки тригонометрических функций в CSS (Chrome 111+, Firefox 108+, Safari 15.4+), всё изменилось.
Как это работает?
В основе лежит простая школьная математика. Чтобы расположить элемент на окружности, нам нужно знать угол (--angle) и радиус (--offset).
Формула проста:
- Мы определяем центр контейнера как точку (0,0).
- Считаем координату
Xкакcos(угол) * радиус. - Считаем координату
Yкакsin(угол) * радиус.
.petal {
--_angle: calc(360deg * var(--_child) / var(--_total));
--_x: calc(cos(var(--_angle)) * var(--_offset));
--_y: calc(sin(var(--_angle)) * var(--_offset));
transform: translate(-50%, -50%) translate(var(--_x), var(--_y));
}
Пример 1: Ромашка
Показать HTML код
<div class="daisy-container">
<div class="petal" style="--_child: 0"></div>
<div class="petal" style="--_child: 1"></div>
<div class="petal" style="--_child: 2"></div>
<div class="petal" style="--_child: 3"></div>
<div class="petal" style="--_child: 4"></div>
<div class="petal" style="--_child: 5"></div>
<div class="petal" style="--_child: 6"></div>
<div class="petal" style="--_child: 7"></div>
</div> Показать CSS код
.daisy-container {
--_offset: 8rem;
--_size: 3rem;
--_total: 8;
position: relative;
width: 4rem;
aspect-ratio: 1;
background: var(--color-primary);
border-radius: 50%;
margin-block: calc(var(--_offset) + 2rem);
margin-inline: auto;
}
.petal {
--_angle: calc(360deg * var(--_child) / var(--_total));
--_x: calc(cos(var(--_angle)) * var(--_offset));
--_y: calc(sin(var(--_angle)) * var(--_offset));
position: absolute;
top: 50%;
left: 50%;
width: var(--_size);
aspect-ratio: 1;
background: var(--color-primary-active);
border-radius: 50%;
transform: translate(-50%, -50%) translate(var(--_x), var(--_y));
} Пример 2: Наши преимущества (6)
преимущества
Показать HTML код
<div class="features-wrapper">
<div class="features-circle">
<div class="feature-hub">Наши<br />преимущества</div>
<div class="feature" style="--_child: 0"><span>🚀</span> Скорость</div>
<div class="feature" style="--_child: 1"><span>🛡️</span> Защита</div>
<div class="feature" style="--_child: 2"><span>💎</span> Качество</div>
<div class="feature" style="--_child: 3"><span>⚙️</span> Гибкость</div>
<div class="feature" style="--_child: 4"><span>🎧</span> Поддержка</div>
<div class="feature" style="--_child: 5"><span>📈</span> Рост</div>
</div>
</div> Показать CSS код
.features-wrapper {
--_offset: 10rem;
--_size: 8rem;
--_total: 6;
display: flex;
justify-content: center;
align-items: center;
padding-block: calc(var(--_offset) + 3rem);
}
.features-circle {
position: relative;
width: 0;
height: 0;
}
.feature-hub {
position: absolute;
width: 8rem;
aspect-ratio: 1;
background: #1e293b;
color: white;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
text-align: center;
font-size: 0.875rem;
transform: translate(-50%, -50%);
z-index: 2;
}
.feature {
--_angle: calc(360deg * var(--_child) / var(--_total));
/* -90deg - чтобы первый элемент был сверху, а не справа */
/* --_angle: calc(360deg * var(--_child) / var(--_total) - 90deg); */
--_x: calc(cos(var(--_angle)) * var(--_offset));
--_y: calc(sin(var(--_angle)) * var(--_offset));
position: absolute;
display: flex;
flex-direction: column;
width: var(--_size);
padding: 1rem;
background: white;
border: 1px solid var(--color-base-borders);
border-radius: 1rem;
text-align: center;
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
transform: translate(-50%, -50%) translate(var(--_x), var(--_y));
} Пример 3: Наши преимущества (5)
преимущества
Показать HTML код
<div class="features-wrapper-2">
<div class="features-circle-2">
<div class="feature-hub-2">Наши<br />преимущества</div>
<div class="feature-2" style="--_child: 0"><span>🚀</span> Скорость</div>
<div class="feature-2" style="--_child: 1"><span>🛡️</span> Защита</div>
<div class="feature-2" style="--_child: 2"><span>💎</span> Качество</div>
<div class="feature-2" style="--_child: 3"><span>⚙️</span> Гибкость</div>
<div class="feature-2" style="--_child: 4"><span>🎧</span> Поддержка</div>
</div>
</div> Показать CSS код
.features-wrapper-2 {
--_offset: 10rem;
--_size: 8rem;
--_total: 5;
display: flex;
justify-content: center;
align-items: center;
padding-block: calc(var(--_offset) + 3rem);
}
.features-circle-2 {
position: relative;
width: 0;
height: 0;
}
.feature-hub-2 {
position: absolute;
width: 8rem;
aspect-ratio: 1;
background: #1e293b;
color: white;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
text-align: center;
font-size: 0.875rem;
transform: translate(-50%, -50%);
z-index: 2;
}
.feature-2 {
/* --_angle: calc(360deg * var(--_child) / var(--_total)); */
/* -90deg - чтобы первый элемент был сверху, а не справа */
--_angle: calc(360deg * var(--_child) / var(--_total) - 90deg);
--_x: calc(cos(var(--_angle)) * var(--_offset));
--_y: calc(sin(var(--_angle)) * var(--_offset));
position: absolute;
display: flex;
flex-direction: column;
width: var(--_size);
padding: 1rem;
background: white;
border: 1px solid var(--color-base-borders);
border-radius: 1rem;
text-align: center;
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
transform: translate(-50%, -50%) translate(var(--_x), var(--_y));
} Итоги: Математика на службе интерфейсов
Использование тригонометрии в CSS — это не просто эффектный трюк, а переход к более декларативному и чистому коду. Мы уходим от магических чисел и ручной подгонки пикселей к логике, которую понимает браузер.
Кроме того, использование sin и cos позволит вам получить персональное достижение: первое коммерческое применение этих малопригодных навыков из школы!