JSFiddle - React, Tailwind, and code Playground
by Scott Kaye
HTML
<link rel="stylesheet" href="https://use.typekit.net/rpz7fve.css">
<div class="container">
<svg class="header" viewBox="0 0 100 100" preserveAspectRatio="none">
<defs>
<linearGradient id="g">
<stop offset="0%" stop-color="#7F23E1" />
<stop offset="100%" stop-color="#4C01E0" />
<animateTransform attributeName="gradientTransform" dur="8s" repeatCount="indefinite" type="rotate" values="0;360" />
</linearGradient>
</defs>
<mask id="mask">
<path d="M0 0, V70, C 20 100 80 100 100 70, V0" fill="#fff" />
</mask>
<path d="M0 0, V70, C 20 100 80 100 100 70, V0" stroke-width="2" stroke="#ccc" fill="#ccc" />
<circle cx="50" cy="50" r="75" mask="url(#mask)" fill="url(#g)" />
</svg>
<div class="header-content">
<nav>
<div class="selector"></div>
<ul>
<li class="selected">Activity</li>
<li>Manage</li>
</ul>
</nav>
<header>
<h1>$15,000.00</h1>
<h2>Chequing Account</h2>
<h3>1234567</h3>
</header>
<button class="add-button"></button>
</div>
</div>
SCSS
svg.header {
width: 100%;
height: 250px;
position: absolute;
}
svg.header circle {
animation: circle-in 1s ease 1 forwards;
}
@keyframes circle-in {
0% {
cx: 25;
cy: 25;
r: 10;
opacity: 0.5;
}
100% {
cx: 50;
cy: 50;
}
}
.container {
width: 400px;
height: 100vh;
background: #F2F1FB;
position: relative;
overflow: hidden;
}
body {
overflow: hidden;
margin: 0;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
font-family: sofia-pro;
}
.header-content {
position: relative;
color: #fff;
text-align: center;
nav {
margin: 40px 0 0 0;
display: flex;
justify-content: center;
user-select: none;
animation: nav-in 500ms ease 1 forwards;
@at-root {
@keyframes nav-in {
0% {
opacity: 0.5;
transform: translateY(-15px);
}
}
}
ul {
display: flex;
list-style: none;
margin: 0;
padding: 0;
cursor: pointer;
}
li {
display: inline-block;
padding: 8px 25px;
background: rgba(255, 255, 255, 0.1);
font-weight: 700;
position: relative;
&.selected {
color: #7F23E1;
}
&:first-child {
border-top-left-radius: 50px;
border-bottom-left-radius: 50px;
}
&:last-child {
border-top-right-radius: 50px;
border-bottom-right-radius: 50px;
}
}
.selector {
position: absolute;
padding: 10px 25px;
background: #fff;
border-radius: 50px;
transition: all 500ms cubic-bezier(.56,-0.13,.11,1.45);
}
}
header {
margin-top: 20px;
h1 {
margin: 5px 0;
}
h2, h3 {
margin: 0;
font-size: 0.9em;
text-transform: uppercase;
letter-spacing: 0.1ch;
}
h3 {
color: rgba(255,255,255,0.5);
font-weight: 300;
}
* {
animation: header-item-in 500ms ease 1 forwards;
opacity: 0;
transform: translateX(-30px);
@at-root {
@keyframes header-item-in {
to {
opacity: 1;
transform: none;
}
}
}
@for $i from 1 through 4...
JavaScript
const navSelector = document.querySelector(".header-content nav .selector");
function updateNavSelector(li) {
if (!li) {
navSelector.style.opacity = 0;
}
navSelector.style.opacity = 1;
navSelector.style.top = li.offsetTop + "px";
navSelector.style.height = li.offsetHeight + "px";
navSelector.style.width = li.offsetWidth + "px";
navSelector.style.left = li.offsetLeft + "px";
}
updateNavSelector(document.querySelector(".header-content li.selected"));
document.querySelectorAll(".header-content li").forEach(li => {
li.addEventListener("click", e => {
e.preventDefault();
let currentlySelected = li.parentNode.querySelector(".selected");
if (!currentlySelected.isSameNode(li)) {
currentlySelected.classList.remove("selected");
li.classList.add("selected");
updateNavSelector(li);
}
}, false);
});