Showcase your professional profile with this modern gradient CV template using HTML5, CSS3, and JavaScript. The design combines a profile sidebar, indigo and violet gradient accents, consistent icons, and skill bars to create a visually rich digital resume.
Interactive tabs let visitors explore your background, experience, education, skills, projects, and contact information in separate panels. The responsive layout adapts to desktop and mobile screens, while dedicated print styles bring all sections together for printing or saving as a PDF.
What you will build
You will build an interactive CV website with a modern gradient design and tab-based navigation. The template includes:
A profile photo, name, and professional title.
A sidebar with contact details and social links.
Dark navy styling with indigo, violet, and cyan gradient accents.
Six tabs: About, Experience, Education, Skills, Projects, and Contact.
A professional summary and career highlight cards.
A timeline for work experience.
Education and certification entries.
Labeled skill bars with sample self-assessment values.
Soft-skill badges and project cards.
Contact links for email and phone.
Keyboard-accessible tab controls and visible focus styles.
Responsive layouts and reduced-motion support.
A “Print / Save CV” button with print styles that include every section.
HTML source
<!doctype html>
<html lang="en"><head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="Alex Morgan — a fictional frontend developer CV template featuring experience, skills, and selected projects.">
<title>Alex Morgan | Frontend Developer CV</title>
</head>
<body>
<!-- Shared, decorative inline SVG icons. No external icon library required. -->
<svg class="icon-library" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><defs>
<symbol id="user" viewBox="0 0 24 24"><circle cx="12" cy="8" r="4"></circle><path d="M4 21v-2a8 8 0 0 1 16 0v2"></path></symbol>
<symbol id="briefcase" viewBox="0 0 24 24"><rect x="3" y="7" width="18" height="14" rx="2"></rect><path d="M8 7V3h8v4M3 12a21 21 0 0 0 18 0M12 11v4"></path></symbol>
<symbol id="education" viewBox="0 0 24 24"><path d="m2 9 10-6 10 6-10 6L2 9Zm4 3v6c4 3 8 3 12 0v-6M22 9v9"></path></symbol>
<symbol id="code" viewBox="0 0 24 24"><path d="m8 6-6 6 6 6m8-12 6 6-6 6M14 3l-4 18"></path></symbol>
<symbol id="grid" viewBox="0 0 24 24"><rect x="3" y="3" width="7" height="7" rx="1"></rect><rect x="14" y="3" width="7" height="7" rx="1"></rect><rect x="3" y="14" width="7" height="7" rx="1"></rect><rect x="14" y="14" width="7" height="7" rx="1"></rect></symbol>
<symbol id="mail" viewBox="0 0 24 24"><rect x="3" y="5" width="18" height="14" rx="2"></rect><path d="m3 6 9 7 9-7"></path></symbol>
<symbol id="pin" viewBox="0 0 24 24"><path d="M20 10c0 6-8 12-8 12S4 16 4 10a8 8 0 1 1 16 0Z"></path><circle cx="12" cy="10" r="2"></circle></symbol>
<symbol id="phone" viewBox="0 0 24 24"><path d="m5 3 4 1 1 5-3 2a16 16 0 0 0 6 6l2-3 5 1 1 4c0 2-3 3-5 2C9 19 5 15 3 8 2 6 3 3 5 3Z"></path></symbol>
<symbol id="link" viewBox="0 0 24 24"><path d="m10 14 4-4m-6 6-2 2a4 4 0 0 1-6-6l5-5a4 4 0 0 1 6 0m2 1 2-2a4 4 0 0 1 6 6l-5 5a4 4 0 0 1-6 0" transform="translate(1 0)"></path></symbol>
<symbol id="print" viewBox="0 0 24 24"><path d="M6 9V3h12v6M6 18H3V9h18v9h-3M6 15h12v7H6Z"></path></symbol>
<symbol id="arrow" viewBox="0 0 24 24"><path d="M5 19 19 5M5 5h14v14"></path></symbol>
</defs></svg>
<a class="skip-link" href="#main">Skip to CV content</a>
<div class="page-heading"><a class="wordmark" href="#main">am<span>.</span></a><span>DIGITAL CV <span class="slash">/</span> 2026</span></div>
<div class="cv-shell">
<aside class="profile" aria-label="Profile and contact details">
<div class="portrait"><img src="images/profile.jpg" alt="Portrait of Alex Morgan, fictional frontend developer" width="160" height="160"><span class="portrait-fallback" aria-hidden="true">AM</span></div>
<span class="availability"><span></span> Available for opportunities</span>
<h1>Alex Morgan<span class="accent">.</span></h1>
<p class="job-title">Frontend Developer</p>
<p class="intro">I turn thoughtful design into accessible, delightful experiences for the web.</p>
<dl class="contact-list">
<div><dt><svg class="icon" aria-hidden="true"><use href="#pin"></use></svg> Location</dt><dd>Bristol, United Kingdom</dd></div>
<div><dt><svg class="icon" aria-hidden="true"><use href="#mail"></use></svg> Email</dt><dd><a href="mailto:alex.morgan@example.com">alex.morgan@example.com</a></dd></div>
<div><dt><svg class="icon" aria-hidden="true"><use href="#phone"></use></svg> Phone</dt><dd><a href="tel:+447700900123">+44 7700 900123</a></dd></div>
</dl>
<div class="socials" aria-label="Sample social profiles">
<a href="https://example.com/portfolio"><svg class="icon" aria-hidden="true"><use href="#link"></use></svg>Portfolio</a>
<a href="https://example.com/linkedin">LinkedIn</a>
<a href="https://example.com/github">GitHub</a>
</div>
<button class="print-button" type="button" hidden=""><svg class="icon" aria-hidden="true"><use href="#print"></use></svg> Print / Save CV</button>
<p class="sample-note">Fictional sample CV · Replace all details and links before sharing.</p>
</aside>
<main id="main" class="content" tabindex="-1">
<!-- JS adds the tab roles and hides inactive panels; without JS these are anchor links. -->
<nav class="tabs" aria-label="CV sections">
<a href="#about" id="tab-about"><svg class="icon" aria-hidden="true"><use href="#user"></use></svg>About</a>
<a href="#experience" id="tab-experience"><svg class="icon" aria-hidden="true"><use href="#briefcase"></use></svg>Experience</a>
<a href="#education" id="tab-education"><svg class="icon" aria-hidden="true"><use href="#education"></use></svg>Education</a>
<a href="#skills" id="tab-skills"><svg class="icon" aria-hidden="true"><use href="#code"></use></svg>Skills</a>
<a href="#projects" id="tab-projects"><svg class="icon" aria-hidden="true"><use href="#grid"></use></svg>Projects</a>
<a href="#contact" id="tab-contact"><svg class="icon" aria-hidden="true"><use href="#mail"></use></svg>Contact</a>
</nav>
<div class="panels">
<section id="about" class="panel" aria-labelledby="heading-about">
<p class="eyebrow">A LITTLE ABOUT ME</p><h2 id="heading-about">Thoughtful code.<br><span class="gradient-text">Meaningful experiences.</span></h2>
<p class="lead">A frontend developer who cares as much about how a product feels as how it works.</p>
<p>I’m Alex, a Bristol-based developer with five years of sample experience building responsive interfaces. I bring design sensitivity, a practical engineering mindset, and a focus on accessibility to every project.</p>
<p>From the first wireframe to the final keyboard interaction, I enjoy making complex ideas feel simple. I work closely with designers and product teams to ship useful, maintainable experiences.</p>
<div class="stats"><article><strong>5+</strong><span>Years building</span></article><article><strong>24</strong><span>Projects delivered</span></article><article><strong>12</strong><span>Team collaborations</span></article></div>
<p class="sample-note">Illustrative career statistics for this fictional profile.</p>
<h3>Where I can help</h3><div class="expertise"><article><svg class="icon" aria-hidden="true"><use href="#code"></use></svg><h4>Frontend development</h4><p>Fast, responsive interfaces built on strong web foundations.</p></article><article><svg class="icon" aria-hidden="true"><use href="#grid"></use></svg><h4>Design systems</h4><p>Consistent components that help teams build with confidence.</p></article><article><svg class="icon" aria-hidden="true"><use href="#user"></use></svg><h4>Accessible experiences</h4><p>Inclusive interactions, clear content, and keyboard-friendly flows.</p></article></div>
</section>
<section id="experience" class="panel" aria-labelledby="heading-experience"><p class="eyebrow">THE JOURNEY SO FAR</p><h2 id="heading-experience">Work <span class="gradient-text">experience.</span></h2><p class="lead">Building better products, one thoughtful detail at a time.</p>
<div class="timeline">
<article class="timeline-entry"><span class="date">JAN 2024 — PRESENT</span><h3>Frontend Developer</h3><p class="company">Northstar Studio · Bristol · Fictional company</p><ul><li>Built a reusable interface library used across four sample client products.</li><li>Reduced the sample storefront’s largest contentful paint from 3.2s to 1.8s through image and script optimization.</li><li>Partnered with designers to improve keyboard navigation and form feedback.</li></ul></article>
<article class="timeline-entry"><span class="date">JUL 2022 — DEC 2023</span><h3>Frontend Developer</h3><p class="company">Orbit Digital · Remote · Fictional company</p><ul><li>Delivered responsive dashboards for three illustrative product teams.</li><li>Introduced shared UI patterns that simplified maintenance and design reviews.</li><li>Added meaningful interaction tests for critical account and checkout flows.</li></ul></article>
<article class="timeline-entry"><span class="date">JUL 2021 — JUN 2022</span><h3>Junior Web Developer</h3><p class="company">Fieldwork Creative · Bristol · Fictional company</p><ul><li>Translated design mockups into responsive HTML, CSS, and JavaScript pages.</li><li>Improved semantic structure and image loading across a sample portfolio of websites.</li></ul></article>
</div>
</section>
<section id="education" class="panel" aria-labelledby="heading-education"><p class="eyebrow">ALWAYS LEARNING</p><h2 id="heading-education">Education & <span class="gradient-text">growth.</span></h2>
<div class="timeline"><article class="timeline-entry"><span class="date">2018 — 2021</span><h3>BSc (Hons) Computer Science</h3><p class="company">Westbridge University · Fictional institution</p><p>Focused on human-computer interaction, software engineering, and web technologies. Final project: an accessible community events platform.</p></article><article class="timeline-entry"><span class="date">2016 — 2018</span><h3>Diploma in Digital Design</h3><p class="company">Bristol Creative College · Fictional institution</p><p>Studied visual communication, interface design, and the foundations of interactive media.</p></article></div>
<h3>Certifications</h3><div class="certifications"><article><h4>Web Accessibility Foundations</h4><p>Open Learning Studio · 2025</p></article><article><h4>Advanced JavaScript</h4><p>Frontend Learning Academy · 2023</p></article></div><p class="sample-note">All institutions, issuers, and credentials are fictional samples.</p>
</section>
<section id="skills" class="panel" aria-labelledby="heading-skills"><p class="eyebrow">MY TOOLKIT</p><h2 id="heading-skills">Skills that <span class="gradient-text">connect.</span></h2><p class="lead">Strong fundamentals. A curious mindset.</p><p id="skill-note">Percentages are sample self-assessments, not independently verified proficiency scores.</p>
<!-- Update aria-valuenow, the visible percentage, and --level together. -->
<div class="skill-list">
<div class="skill"><div class="skill-label"><span id="skill-html">HTML & semantic markup</span><span>95%</span></div><div class="skill-track" role="progressbar" aria-labelledby="skill-html" aria-describedby="skill-note" aria-valuemin="0" aria-valuemax="100" aria-valuenow="95"><span style="--level:95%"></span></div></div>
<div class="skill"><div class="skill-label"><span id="skill-css">CSS & responsive design</span><span>92%</span></div><div class="skill-track" role="progressbar" aria-labelledby="skill-css" aria-describedby="skill-note" aria-valuemin="0" aria-valuemax="100" aria-valuenow="92"><span style="--level:92%"></span></div></div>
<div class="skill"><div class="skill-label"><span id="skill-js">JavaScript</span><span>88%</span></div><div class="skill-track" role="progressbar" aria-labelledby="skill-js" aria-describedby="skill-note" aria-valuemin="0" aria-valuemax="100" aria-valuenow="88"><span style="--level:88%"></span></div></div>
<div class="skill"><div class="skill-label"><span id="skill-a11y">Web accessibility</span><span>85%</span></div><div class="skill-track" role="progressbar" aria-labelledby="skill-a11y" aria-describedby="skill-note" aria-valuemin="0" aria-valuemax="100" aria-valuenow="85"><span style="--level:85%"></span></div></div>
<div class="skill"><div class="skill-label"><span id="skill-git">Git & collaborative workflows</span><span>90%</span></div><div class="skill-track" role="progressbar" aria-labelledby="skill-git" aria-describedby="skill-note" aria-valuemin="0" aria-valuemax="100" aria-valuenow="90"><span style="--level:90%"></span></div></div>
</div><h3>The human side</h3><div class="tags"><span>Clear communication</span><span>Creative problem solving</span><span>Collaboration</span><span>Attention to detail</span><span>Continuous learning</span></div>
</section>
<section id="projects" class="panel" aria-labelledby="heading-projects"><p class="eyebrow">SELECTED WORK</p><h2 id="heading-projects">Ideas brought <span class="gradient-text">to life.</span></h2><p class="lead">Three fictional projects, built around real-world challenges.</p>
<div class="project-list"><article class="project-card"><span class="project-number">01 / PRODUCTIVITY</span><h3>Focus Workspace</h3><p>A distraction-free task dashboard with keyboard shortcuts, adaptable views, and browser-local preferences.</p><div class="tags"><span>JavaScript</span><span>CSS Grid</span><span>Local storage</span></div><a href="https://example.com/projects/focus">Explore Focus Workspace <svg class="icon" aria-hidden="true"><use href="#arrow"></use></svg></a></article><article class="project-card"><span class="project-number">02 / DESIGN SYSTEM</span><h3>Prism UI</h3><p>A small component system with accessible navigation patterns, reusable tokens, and practical usage examples.</p><div class="tags"><span>HTML</span><span>CSS</span><span>Accessibility</span></div><a href="https://example.com/projects/prism">Explore Prism UI <svg class="icon" aria-hidden="true"><use href="#arrow"></use></svg></a></article><article class="project-card"><span class="project-number">03 / COMMUNITY</span><h3>Local Loop</h3><p>A responsive events directory with client-side filtering and clear, mobile-friendly event details.</p><div class="tags"><span>JavaScript</span><span>Responsive design</span></div><a href="https://example.com/projects/local-loop">Explore Local Loop <svg class="icon" aria-hidden="true"><use href="#arrow"></use></svg></a></article></div><p class="sample-note">All project URLs are replaceable example.com placeholders.</p>
</section>
<section id="contact" class="panel" aria-labelledby="heading-contact"><p class="eyebrow">LET’S CONNECT</p><h2 id="heading-contact">Good things start<br><span class="gradient-text">with a conversation.</span></h2><p class="lead">Have an interesting challenge in mind?</p><p>I’d love to discuss frontend opportunities, thoughtful products, and teams that care about building an inclusive web.</p><div class="contact-cards"><a href="mailto:alex.morgan@example.com"><svg class="icon" aria-hidden="true"><use href="#mail"></use></svg><span><small>Email</small>alex.morgan@example.com</span></a><a href="tel:+447700900123"><svg class="icon" aria-hidden="true"><use href="#phone"></use></svg><span><small>Phone</small>+44 7700 900123</span></a><div><svg class="icon" aria-hidden="true"><use href="#pin"></use></svg><span><small>Location</small>Bristol, United Kingdom</span></div></div><h3>Elsewhere on the web</h3><div class="socials"><a href="https://example.com/portfolio">Portfolio ↗</a><a href="https://example.com/linkedin">LinkedIn ↗</a><a href="https://example.com/github">GitHub ↗</a></div><p class="sample-note">Sample contact details and replaceable social URLs.</p></section>
</div>
<footer>DESIGNED WITH INTENTION <span>Built for the web. Ready for what’s next.</span></footer>
</main>
</div>
</body></html>
CSS source
/* Edit these tokens to personalize the entire template. */
:root{color-scheme:dark;--bg:#090e1d;--panel:#10182a;--text:#f1f3fa;--muted:#adb8ce;--line:#2a334b;--violet:#a99aff;--cyan:#71dce4;--gradient:linear-gradient(110deg,#a99aff,#bd9afa 45%,#71dce4);--space:clamp(1.4rem,3vw,2.8rem);--radius:24px;--small-radius:14px}
*{box-sizing:border-box}html{scroll-behavior:smooth}body{margin:0;padding:32px 24px 64px;background:radial-gradient(ellipse at 15% 0%,#30225c66,transparent 45%),radial-gradient(ellipse at 95% 70%,#12516b33,transparent 45%),var(--bg);color:var(--text);font-family:Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;font-size:15px;line-height:1.7;min-width:280px}a{color:inherit;text-decoration-thickness:1px;text-underline-offset:4px}button{font:inherit}a,button{-webkit-tap-highlight-color:transparent}a:hover{color:var(--cyan)}:focus-visible{outline:3px solid var(--cyan);outline-offset:5px}.icon-library{position:absolute;width:0;height:0;overflow:hidden}.icon{width:20px;height:20px;fill:none;stroke:currentColor;stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round;flex-shrink:0;vertical-align:middle}.skip-link{position:absolute;top:8px;left:20px;transform:translateY(-160%);padding:10px;background:var(--panel);z-index:5}.skip-link:focus{transform:none}.page-heading{max-width:1200px;margin:0 auto 25px;display:flex;align-items:center;justify-content:space-between;color:var(--muted);font-size:11px;letter-spacing:2px}.wordmark{font-size:30px;letter-spacing:-2px;font-weight:800;text-decoration:none;color:var(--text)}.wordmark span,.accent{color:var(--violet)}.slash{margin:0 12px;color:var(--violet)}.cv-shell{max-width:1200px;margin:auto;display:grid;grid-template-columns:minmax(0,30fr) minmax(0,70fr);border:1px solid var(--line);border-radius:var(--radius);background:linear-gradient(140deg,#151c30e8,#101727f5);box-shadow:0 24px 80px #0003;overflow:hidden}.profile{padding:var(--space);border-right:1px solid var(--line);background:linear-gradient(160deg,#9381f50b,transparent 70%)}.portrait{width:148px;height:148px;margin:0 0 24px;border-radius:50%;padding:5px;background:var(--gradient);position:relative;isolation:isolate}.portrait img{width:100%;height:100%;object-fit:cover;border-radius:50%;background:#202c45;position:relative;z-index:1}.portrait img.photo-missing{visibility:hidden}.portrait-fallback{position:absolute;inset:5px;display:grid;place-items:center;background:#202c45;border-radius:50%;font-size:42px;font-weight:700;color:var(--violet);z-index:0}.availability{display:inline-flex;align-items:center;gap:8px;color:#9ce5c9;font-size:11px;background:#215e4526;border:1px solid #478c664f;border-radius:30px;padding:5px 10px}.availability>span{width:6px;height:6px;border-radius:50%;background:#8ce0b8}h1{font-size:clamp(1.8rem,3vw,2.4rem);letter-spacing:-1.5px;line-height:1.2;margin:20px 0 8px}.job-title{color:var(--violet);font-weight:550;margin:0}.intro{color:var(--muted);margin:20px 0 26px;font-size:14px}.contact-list{padding:24px 0;margin:0;border-block:1px solid var(--line)}.contact-list>div+div{margin-top:17px}.contact-list dt{font-size:11px;color:var(--muted);display:flex;align-items:center;gap:8px}.contact-list dt .icon{width:15px;height:15px;color:var(--violet)}.contact-list dd{margin:3px 0 0 23px;font-size:12px;overflow-wrap:anywhere}.contact-list a{text-decoration:none}.socials{display:flex;gap:10px;flex-wrap:wrap;margin:24px 0}.socials a{display:inline-flex;gap:5px;align-items:center;font-size:12px;text-decoration:none;padding:7px 9px;border:1px solid var(--line);border-radius:8px;min-height:44px}.socials .icon{width:14px;height:14px}.print-button{display:flex;align-items:center;justify-content:center;gap:10px;min-height:48px;width:100%;border:1px solid #a99aff70;background:linear-gradient(100deg,#7361d8,#6758b5);color:white;border-radius:10px;cursor:pointer;font-weight:600;transition:filter .2s,transform .2s}.print-button:hover{filter:brightness(1.15);transform:translateY(-2px)}[hidden]{display:none!important}.sample-note{font-size:11px!important;color:var(--muted);line-height:1.7}.profile>.sample-note{margin-top:22px}.content{min-width:0}.tabs{display:flex;overflow-x:auto;gap:4px;padding:20px 23px;border-bottom:1px solid var(--line);scrollbar-width:thin;scrollbar-color:#6758b5 transparent}.tabs a{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:6px;flex:1 0 85px;min-height:65px;padding:8px 10px;border:1px solid transparent;border-radius:10px;font-size:12px;text-decoration:none;color:var(--muted);transition:background .2s,color .2s}.tabs a:hover{background:#a99aff0c;color:var(--text)}.tabs a[aria-selected=true]{background:#a99aff18;border-color:#a99aff50;color:#c6baff}.tabs a:focus-visible{outline-offset:-3px}.panels{padding:var(--space)}.panel{scroll-margin-top:20px}.panel+.panel{margin-top:48px;padding-top:32px;border-top:1px solid var(--line)}.js .panel+.panel{margin-top:0;padding-top:0;border:0}.js .panel.is-entering{animation:enter .22s ease-out}.eyebrow{font-size:10px;letter-spacing:2.5px;font-weight:700;color:var(--violet);margin:0 0 16px}h2{font-size:clamp(2rem,3.6vw,3rem);font-weight:700;line-height:1.18;letter-spacing:-1.7px;margin:0 0 22px}.gradient-text{background:var(--gradient);background-clip:text;-webkit-background-clip:text;color:transparent}.panel>p:not(.eyebrow){color:var(--muted)}.panel .lead{font-size:17px;line-height:1.6;color:#dce1ef;margin-bottom:22px}h3{font-size:18px;letter-spacing:-.4px;margin:30px 0 16px}h4{font-size:14px;margin:12px 0 6px}.stats{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:12px;margin:30px 0 10px}.stats article{padding:17px 12px;background:linear-gradient(120deg,#9581f512,#4cbad708);border:1px solid var(--line);border-radius:var(--small-radius)}.stats strong{display:block;font-size:29px;color:#c2b5ff;line-height:1.3;letter-spacing:-1px}.stats span{display:block;font-size:11px;color:var(--muted);margin-top:5px}.expertise{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:18px}.expertise .icon{color:var(--cyan);margin-top:5px}.expertise p{font-size:12px;color:var(--muted);margin:0}.timeline{margin:28px 0 0 7px;border-left:1px solid #655d91}.timeline-entry{padding:0 0 28px 25px;position:relative}.timeline-entry:before{content:"";position:absolute;left:-5px;top:9px;width:9px;height:9px;border-radius:50%;background:var(--violet);box-shadow:0 0 0 5px #1e2440}.date,.project-number{font-size:10px;letter-spacing:1.3px;color:var(--cyan);font-weight:600}.timeline h3{margin:7px 0 0}.company{color:var(--violet);font-size:12px;margin:4px 0 12px}.timeline p:not(.company),.timeline li{font-size:14px;color:var(--muted)}ul{padding-left:18px}li+li{margin-top:7px}.certifications{display:grid;grid-template-columns:1fr 1fr;gap:12px}.certifications article{padding:8px 18px;border:1px solid var(--line);border-radius:var(--small-radius)}.certifications p{font-size:12px;color:var(--muted)}.skill-list{display:grid;gap:24px;margin:32px 0}.skill-label{display:flex;justify-content:space-between;gap:15px;font-size:14px;margin-bottom:9px}.skill-label>span:last-child{color:var(--cyan)}.skill-track{height:7px;border-radius:20px;background:#283149;overflow:hidden}.skill-track>span{display:block;height:100%;width:var(--level);background:var(--gradient);border-radius:inherit;transform-origin:left}.skills-animate .skill-track>span{animation:fill .65s ease-out both}.tags{display:flex;flex-wrap:wrap;gap:8px}.tags span{padding:5px 10px;border-radius:7px;background:#a99aff10;border:1px solid #a99aff25;color:#c8c0ec;font-size:11px}.project-list{display:grid;gap:16px;margin-top:28px}.project-card{padding:22px;border:1px solid var(--line);border-radius:var(--small-radius);background:linear-gradient(120deg,#9b84ef09,transparent);transition:border-color .2s,transform .2s}.project-card:hover{border-color:#8878b6;transform:translateY(-2px)}.project-card h3{margin:7px 0}.project-card p{font-size:14px;color:var(--muted)}.project-card>a{display:inline-flex;align-items:center;gap:9px;font-size:12px;color:var(--cyan);margin-top:18px}.project-card>a .icon{width:15px;height:15px}.contact-cards{display:grid;gap:12px;margin:30px 0}.contact-cards>a,.contact-cards>div{display:flex;align-items:center;gap:18px;border:1px solid var(--line);border-radius:12px;padding:18px;text-decoration:none;overflow-wrap:anywhere;min-width:0}.contact-cards .icon{color:var(--violet)}.contact-cards span{min-width:0}.contact-cards small{display:block;font-size:11px;color:var(--muted)}footer{display:flex;justify-content:space-between;gap:15px;margin:0 var(--space);padding:20px 0;border-top:1px solid var(--line);font-size:8px;letter-spacing:1.2px;color:var(--muted)}footer span{letter-spacing:0;font-size:10px}@keyframes enter{from{opacity:0;transform:translateY(5px)}to{opacity:1;transform:none}}@keyframes fill{from{transform:scaleX(0)}to{transform:scaleX(1)}}
@media(min-width:1100px){.cv-shell{min-height:850px}}@media(max-width:900px){body{padding:20px 15px 40px}.cv-shell{grid-template-columns:minmax(0,32fr) minmax(0,68fr)}.profile{padding:24px 20px}.socials{gap:6px}.expertise{grid-template-columns:1fr}.expertise article{display:grid;grid-template-columns:24px 1fr;column-gap:12px}.expertise h4{margin:0 0 4px}.expertise p{grid-column:2}.tabs{padding:12px}.tabs a{flex-basis:80px}.certifications{grid-template-columns:1fr}}
@media(max-width:650px){.cv-shell{grid-template-columns:1fr}.profile{border-right:0;border-bottom:1px solid var(--line);padding:28px}.portrait{width:120px;height:120px}.contact-list{display:grid;gap:14px;grid-template-columns:1fr 1fr}.contact-list>div+div{margin-top:0}.contact-list>div:nth-child(2){grid-column:1/-1;grid-row:2}.profile .intro{max-width:430px}.print-button{max-width:300px}.tabs a{flex:0 0 85px}h2{letter-spacing:-1px}.stats{gap:8px}.stats article{padding:15px 10px}.stats strong{font-size:25px}footer{flex-wrap:wrap}.contact-cards>a,.contact-cards>div{padding:14px;font-size:13px}}
@media(prefers-reduced-motion:reduce){html{scroll-behavior:auto}*,*::before,*::after{animation:none!important;transition:none!important}}
/* All sections print even when hidden by the tab interaction. */
@page{size:A4;margin:16mm}
@media print{ :root{color-scheme:light;--text:#172033;--muted:#424b5d;--line:#cdd1da;--violet:#49377b;--cyan:#185866}body{padding:0;background:white!important;color:var(--text);font-size:10pt;line-height:1.5}.page-heading,.tabs,.print-button,.skip-link,.portrait-fallback,footer{display:none!important}.cv-shell{display:block;min-height:0;border:0;border-radius:0;background:white;box-shadow:none;overflow:visible;max-width:none}.profile{padding:0 0 16pt;border:0;border-bottom:1px solid var(--line);background:none}.portrait{float:right;width:80px;height:80px;margin:0;background:none;padding:0}.portrait img{border:1px solid #bbb}.availability{border:0;background:none;color:#18513b;padding:0}.availability>span{display:none}h1{font-size:24pt;margin:8pt 0 4pt}.intro{margin:10pt 0}.contact-list{display:flex;flex-wrap:wrap;gap:10pt;border:0;padding:4pt 0}.contact-list>div+div{margin:0}.socials{margin:8pt 0}.socials a{border:0;padding:0;min-height:0}.panels{padding:0}.panel[hidden],.panel{display:block!important;opacity:1!important;transform:none!important;animation:none!important;margin:0!important;padding:18pt 0 0!important;border:0!important}.eyebrow{margin:0 0 5pt;font-size:7pt}h2{font-size:21pt;margin:0 0 12pt;letter-spacing:-.6pt}.gradient-text{background:none;color:#49377b;-webkit-text-fill-color:#49377b}.panel .lead{color:#172033;font-size:12pt}.panel p,.timeline p:not(.company),.timeline li,.project-card p{font-size:10pt}.stats{margin:12pt 0}.stats article,.project-card,.certifications article{background:none;box-shadow:none}.stats strong{color:#49377b}.expertise{grid-template-columns:repeat(3,1fr)}.expertise p{font-size:9pt}.timeline-entry,.project-card,.certifications article,.skill,.contact-cards>a,.contact-cards>div{break-inside:avoid;page-break-inside:avoid}.timeline-entry:before{box-shadow:none}.timeline-entry{padding-bottom:12pt}h2,h3,h4{break-after:avoid}p,li{orphans:3;widows:3}.skill-list{gap:10pt;margin:14pt 0}.skill-track{display:none}.skill-label{margin:0}.tags span{background:none;color:#49377b}.project-list{gap:10pt}.project-card{padding:12pt}.project-card:hover{transform:none}.contact-cards{margin:12pt 0}.contact-cards>a,.contact-cards>div{padding:10pt}.sample-note{font-size:8pt!important}a{color:inherit}.skill-label>span:last-child{color:#185866}}
JavaScript source
/* Progressive enhancement: without JavaScript every section remains visible. */
(() => {
'use strict';
const navigation = document.querySelector('.tabs');
const tabs = Array.from(navigation.querySelectorAll('a'));
const panels = tabs.map(tab => document.querySelector(tab.getAttribute('href')));
const reducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)');
let skillsOpened = false;
navigation.setAttribute('role', 'tablist');
navigation.setAttribute('aria-orientation', 'horizontal');
tabs.forEach((tab, index) => {
tab.setAttribute('role', 'tab');
tab.setAttribute('aria-controls', panels[index].id);
panels[index].setAttribute('role', 'tabpanel');
panels[index].setAttribute('aria-labelledby', tab.id);
panels[index].tabIndex = 0;
});
function activate(index, animate = true) {
tabs.forEach((tab, position) => {
const selected = position === index;
tab.setAttribute('aria-selected', String(selected));
tab.tabIndex = selected ? 0 : -1;
panels[position].hidden = !selected;
panels[position].classList.remove('is-entering');
});
const panel = panels[index];
if (animate && !reducedMotion.matches) panel.classList.add('is-entering');
if (panel.id === 'skills' && !skillsOpened) {
skillsOpened = true;
if (!reducedMotion.matches) panel.classList.add('skills-animate');
}
}
tabs.forEach((tab, index) => {
tab.addEventListener('click', event => {
event.preventDefault();
activate(index);
});
tab.addEventListener('keydown', event => {
let destination;
if (event.key === 'ArrowRight') destination = (index + 1) % tabs.length;
if (event.key === 'ArrowLeft') destination = (index - 1 + tabs.length) % tabs.length;
if (event.key === 'Home') destination = 0;
if (event.key === 'End') destination = tabs.length - 1;
if (destination !== undefined) {
event.preventDefault();
tabs.forEach((item, position) => { item.tabIndex = position === destination ? 0 : -1; });
tabs[destination].focus({ preventScroll: true });
tabs[destination].scrollIntoView({ block: 'nearest', inline: 'nearest', behavior: 'instant' });
} else if (event.key === 'Enter' || event.key === ' ') {
event.preventDefault();
activate(index);
}
});
});
document.documentElement.classList.add('js');
const initialIndex = panels.findIndex(panel => `#${panel.id}` === window.location.hash);
activate(initialIndex >= 0 ? initialIndex : 0, false);
window.addEventListener('hashchange', () => {
const index = panels.findIndex(panel => `#${panel.id}` === window.location.hash);
if (index >= 0) activate(index);
});
const printButton = document.querySelector('.print-button');
printButton.hidden = false;
printButton.addEventListener('click', () => window.print());
// Keep a clean initials fallback until the owner's local photo is supplied.
const photo = document.querySelector('.portrait img');
const showFallback = () => photo.classList.add('photo-missing');
photo.addEventListener('error', showFallback);
if (photo.complete && photo.naturalWidth === 0) showFallback();
})();
How it works
The project uses index.html for the CV content, style.css for the gradient design and responsive layout, and script.js for tab navigation, skill animations, and printing. Personal details, images, links, and skill values can be customized directly in the source files.
Try a change
Choose Edit code, make a small change, then press Run to preview it.
Use the source Copy buttons, choose Edit code to open the editor, or Download ZIP to save the project after a six-second countdown.



.webp)



Discussion (0)
Leave a comment