<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="./style.css">
<title>Team Profiles rotation with pure CSS</title>
</head>
<body>
<div style="--total: 12;" class="circle-wrapper">
<div class="center-element">The Team</div>
<input type="radio" name="radio-avatar" id="radio-avatar-1">
<label id="avatar-1" for="radio-avatar-1" class="avatar" style="--i:1">
<img src="https://i.pravatar.cc/300?img=12" alt="Steven Robinson">
<svg viewBox="0 0 300 300">
<text fill="currentColor">
<textPath xlink:href="#circlePath">Steven Robinson - Web Developer</textPath>
</text>
</svg>
</label>
<input type="radio" name="radio-avatar" id="radio-avatar-2">
<label id="avatar-2" for="radio-avatar-2" class="avatar" style="--i:2">
<img src="https://i.pravatar.cc/300?img=37" alt="Mari Johnson">
<svg viewBox="0 0 300 300">
<text fill="currentColor">
<textPath xlink:href="#circlePath">Mari Johnson - UX Designer</textPath>
</text>
</svg>
</label>
<input type="radio" name="radio-avatar" id="radio-avatar-3">
<label id="avatar-3" for="radio-avatar-3" class="avatar" style="--i:3">
<img src="https://i.pravatar.cc/300?img=3" alt="Bob">
<svg viewBox="0 0 300 300">
<text fill="currentColor">
<textPath xlink:href="#circlePath">Bob - Designer</textPath>
</text>
</svg>
</label>
<input type="radio" name="radio-avatar" id="radio-avatar-4">
<label id="avatar-4" for="radio-avatar-4" class="avatar" style="--i:4">
<img src="https://i.pravatar.cc/300?img=48" alt="Susan Williams">
<svg viewBox="0 0 300 300">
<text fill="currentColor">
<textPath xlink:href="#circlePath">Susan Williams - Full Stack Developer</textPath>
</text>
</svg>
</label>
<input type="radio" name="radio-avatar" id="radio-avatar-5">
<label id="avatar-5" for="radio-avatar-5" class="avatar" style="--i:5">
<img src="https://i.pravatar.cc/300?img=52" alt="James Braun">
<svg viewBox="0 0 300 300">
<text fill="currentColor">
<textPath xlink:href="#circlePath">James Braun - Content Creator</textPath>
</text>
</svg>
</label>
<input type="radio" name="radio-avatar" id="radio-avatar-6">
<label id="avatar-6" for="radio-avatar-6" class="avatar" style="--i:6">
<img src="https://i.pravatar.cc/300?img=33" alt="Andrew Charles">
<svg viewBox="0 0 300 300">
<text fill="currentColor">
<textPath xlink:href="#circlePath">Andrew Charles - Front End Developer</textPath>
</text>
</svg>
</label>
<input type="radio" name="radio-avatar" id="radio-avatar-7">
<label id="avatar-7" for="radio-avatar-7" class="avatar" style="--i:7">
<img src="https://i.pravatar.cc/300?img=44" alt="Jane Dobson">
<svg viewBox="0 0 300 300">
<text fill="currentColor">
<textPath xlink:href="#circlePath">Jane Dobson - Social Media Manager</textPath>
</text>
</svg>
</label>
<input type="radio" name="radio-avatar" id="radio-avatar-8">
<label id="avatar-8" for="radio-avatar-8" class="avatar" style="--i:8">
<img src="https://i.pravatar.cc/300?img=13" alt="Ryan Williams">
<svg viewBox="0 0 300 300">
<text fill="currentColor">
<textPath xlink:href="#circlePath">Ryan Williams - Back End Developer</textPath>
</text>
</svg>
</label>
<input type="radio" name="radio-avatar" id="radio-avatar-9">
<label id="avatar-9" for="radio-avatar-9" class="avatar" style="--i:9">
<img src="https://i.pravatar.cc/300?img=14" alt="Ralph Heartling">
<svg viewBox="0 0 300 300">
<text fill="currentColor">
<textPath xlink:href="#circlePath">Ralph Heartling - Full Stack Developer</textPath>
</text>
</svg>
</label>
<input type="radio" name="radio-avatar" id="radio-avatar-10">
<label id="avatar-10" for="radio-avatar-10" class="avatar" style="--i:10">
<img src="https://i.pravatar.cc/300?img=15" alt="Bryan Davidson">
<svg viewBox="0 0 300 300">
<text fill="currentColor">
<textPath xlink:href="#circlePath">Bryan Davidson - Team Leader</textPath>
</text>
</svg>
</label>
<input type="radio" name="radio-avatar" id="radio-avatar-11">
<label id="avatar-11" for="radio-avatar-11" class="avatar" style="--i:11">
<img src="https://i.pravatar.cc/300?img=16" alt="Angie Jameson">
<svg viewBox="0 0 300 300">
<text fill="currentColor">
<textPath xlink:href="#circlePath">Angie Jameson - Front End Developer</textPath>
</text>
</svg>
</label>
<input type="radio" name="radio-avatar" id="radio-avatar-12">
<label id="avatar-12" for="radio-avatar-12" class="avatar" style="--i:12">
<img src="https://i.pravatar.cc/300?img=17" alt="Raymond Simpson">
<svg viewBox="0 0 300 300">
<text fill="currentColor">
<textPath xlink:href="#circlePath">Raymond Simpson - CEO and Entrepreneur</textPath>
</text>
</svg>
</label>
</div>
<!-- SVG template for dynamic text -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 300 300" width="0" height="0">
<defs>
<path id="circlePath" d="M 150, 150 m -100, 0 a 100,100 0 0,1 200,0 a 100,100 0 0,1 -200,0" />
</defs>
</svg>
<script src="script.js"></script>
</body>
</html>
*,
::before,
::after {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background-color: #000;
min-height: 100vh;
display: grid;
place-content: center;
font-family: system-ui, sans-serif;
}
/* Hide radio input elements */
input[type="radio"] {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border-width: 0;
}
/* Positioning and style for paragraph */
p {
position: absolute;
bottom: 2rem;
right: 2rem;
color: white;
font-size: 0.8rem;
}
/* Wrapper for circle elements */
.circle-wrapper {
border: 1px solid #0f3e5d;
position: relative;
border-radius: 9999px; /* Fully rounded */
display: grid;
width: 450px;
height: 450px;
grid-template-areas: "stack";
place-content: center;
}
/* Label styles inside the circle wrapper */
label {
grid-area: stack;
width: 5rem;
height: 5rem;
border-radius: 9999px; /* Fully rounded */
border: 1px solid #738088;
display: grid;
place-content: center;
background-color: rgba(255, 255, 255, 0.2);
position: relative;
color: #87ceeb;
font-size: 1.25rem;
transition-property: all;
transition-duration: 0.5s;
cursor: pointer;
box-shadow: 0 0 0 4px rgba(255, 255, 255, 0.2); /* White with 20% opacity */
}
/* Image styles */
img {
border-radius: 9999px;
width: 100%;
height: 100%;
object-fit: cover;
transition: all 1s ease-in-out;
}
/* SVG styles */
svg {
transition: all 0.5s ease-in-out;
position: absolute;
inset: 0 0 0 -25%;
margin: auto;
width: 125px;
opacity: 0;
z-index: -10;
}
/* Centered element styles */
.center-element {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
margin: auto;
width: 8rem;
height: 8rem;
background-color: #1b2c36;
border: 1px solid rgba(255, 255, 255, 0.4);
border-radius: 50%; /* Circle */
display: grid;
place-content: center;
text-transform: uppercase;
font-weight: 100;
letter-spacing: 0.05em;
color: #cbd5e0;
font-size: 1.125rem;
}
/* Before pseudo-element for center-element */
.center-element::before {
content: "";
position: absolute;
top: -1px;
right: -1px;
bottom: -1px;
left: -1px;
background-color: #0a4368;
border-radius: 50%;
z-index: -10;
transition: all 1s;
}
/* Checked radio input styles */
input:checked + label {
transform: none !important;
transition-duration: 1s;
}
/* Image transform on checked */
input:checked + label > img {
transform: scale(2);
}
/* SVG transform on checked */
input:checked + label > svg {
opacity: 1;
transform: scale(2.25) rotate(45deg);
transition-delay: 700ms, 500ms, 2000ms;
}
/* Avatar transform styles */
.avatar {
--radius: 14rem;
--d: calc(var(--i) / var(--total));
--r-offset: -0.15turn;
--r-amount: 1turn;
--r: calc((var(--r-amount) * var(--d)) + var(--r-offset));
transform: rotate(var(--r)) translate(var(--radius)) rotate(calc(-1 * var(--r)));
}
JavaScript
// uncheck radio buttons (unfortunatley this cannot be done with CSS alone)
document.querySelectorAll('input[type="radio"]').forEach(radio => {
radio.addEventListener('click', (e) => {
e.preventDefault();
// setting a timeout enables this hack to work
setTimeout(() => radio.checked = !radio.checked, 0);
});
});