How to make a profile card with HTML/CSS/JS
Let’s make a profile card for GitHub pages that can be used as a bio link to store various contact information that can be easily shared.
Here is the code for a basic version of such card:
HTML
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="=> META DESCRIPTION OF YOUR CARD." />
<link rel="icon" type="image/x-icon" href="=> PATH TO YOUR FAVICON" />
<link rel="stylesheet" type="text/css" href="=> PATH TO YOUR CSS FILE" />
<title>=> PAGE TITLE</title>
</head>
<body>
<main class="profileCard-main">
<img
src="=> PATH TO THE MAIN IMAGE"
alt="=> DESCRIPTION OF THE PROFILE IMAGE"
class="profileCard-mainImg"
/>
<section class="profileCard-section">
<h1 class="profileCard-h1">=> YOUR NAME</h1>
<p class="profileCard-bio">=> YOUR BIO / POSITION / PITCH / ETC.</p>
<a
href="=> YOUR MAIN SITE LINK"
class="profileCard-mainLink"
target="_blank"
rel="noreferrer"
>
<img
src="=> YOUR MAIN SITE IMAGE FOR THE LINK"
alt="=> DESCRIPTION OF THE MAIN SITE IMAGE"
/>
</a>
<p class="profileCard-imgDescription">
=> IMAGE DESCRIPTION (e.g.: "Click the image to visit my site.")
</p>
<a
href="=> YOUR SOCIALS LINK 1"
class="profileCard-socialLink"
target="_blank"
rel="noreferrer"
>
=> YOUR SOCIALS LINK 1 NAME
</a>
<a
href="=> YOUR SOCIALS LINK 1"
class="profileCard-socialLink"
target="_blank"
rel="noreferrer"
>
=> YOUR SOCIALS LINK 2 NAME
</a>
<button class="profileCard-btn" onclick="copyLink()">
Copy profile link
</button>
</section>
</main>
<script src="PATH TO YOUR JAVASCRIPT FILE"></script>
</body>
</html>
CSS
:root {
/* Change colors for each part/element here */
--backgroundPrimary: #000814;
--backgroundSecondary: #1d2d44;
--text: #333;
--cardBackground: #fff;
--socialLinkBackground: #e9ecef;
--socialLinkHoverBackground: #f8f9fa;
--socialLinkHover: #007bff;
--btnBorder: #e9ecef;
--btnHoverBackground: #f8f9fa;
--btnCopiedBackground: #d4edda;
--btnCopied: #155724;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
align-items: center;
background: linear-gradient(
135deg,
var(--backgroundPrimary) 0%,
var(--backgroundSecondary) 100%
);
color: var(--text);
display: flex;
/* Change font here */
font-family:
-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu,
sans-serif;
justify-content: center;
min-height: 100vh;
padding: 15px;
}
.profileCard-main {
background: var(--cardBackground);
backdrop-filter: blur(10px);
border-radius: 20px;
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.5);
/* Change card width here (make sure to also adjust height
for profileCard-mainImg class below and check mobile view) */
max-width: 400px;
overflow: hidden;
text-align: center;
width: 100%;
}
.profileCard-mainImg {
/* Change main image height here (make sure to also adjust width
for profileCard-main class above and check mobile view) */
height: 300px;
object-fit: cover;
width: 100%;
}
.profileCard-section {
padding: 20px;
}
.profileCard-h1 {
font-size: 2rem;
font-weight: bold;
margin-bottom: 10px;
}
.profileCard-bio {
font-size: 1.1em;
line-height: 1.5;
margin-bottom: 30px;
}
.profileCard-mainLink {
display: block;
}
.profileCard-imgDescription {
font-size: 0.75rem;
margin-bottom: 30px;
}
.profileCard-mainLink img {
border-radius: 15px;
object-fit: cover;
transition:
transform 0.3s ease-in-out,
box-shadow 0.3s ease-in-out;
width: 100%;
}
.profileCard-mainLink img:hover {
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.25);
transform: translateY(-5px);
}
.profileCard-socialLink {
align-items: center;
background: var(--socialLinkBackground);
border: 2px solid transparent;
border-radius: 50px;
color: var(--text);
display: flex;
font-size: 1.1em;
font-weight: 500;
gap: 15px;
justify-content: center;
margin-bottom: 20px;
padding: 15px 25px;
transition: all 0.3s ease-in-out;
text-decoration: none;
}
.profileCard-socialLink:hover {
background: var(--socialLinkHoverBackground);
border-color: var(--socialLinkHover);
box-shadow: 0 10px 25px rgba(0, 123, 255, 0.25);
color: var(--socialLinkHover);
transform: translateY(-2px);
}
.profileCard-btn {
align-items: center;
background: var(--socialLinkBackground);
border: 2px solid var(--btnBorder);
border-radius: 50px;
color: var(--text);
cursor: pointer;
display: flex;
font-size: 1em;
font-weight: 500;
gap: 15px;
justify-content: center;
padding: 12px 20px;
transition: all 0.3s ease-in-out;
width: 100%;
}
.profileCard-btn:hover {
background: var(--btnHoverBackground);
}
.profileCard-btn.copied {
background: var(--btnCopiedBackground);
color: var(--btnCopied);
}
JavaScript
function copyLink() {
const copyLinkBtn = document.querySelector(".profileCard-btn");
const currentUrl = window.location.href;
const originalBtnContent = copyLinkBtn.innerHTML;
function updateBtnText() {
copyLinkBtn.textContent = "Copied!";
copyLinkBtn.classList.add("copied");
setTimeout(() => {
copyLinkBtn.innerHTML = originalBtnContent;
copyLinkBtn.classList.remove("copied");
}, 2000);
}
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard
.writeText(currentUrl)
.then(updateBtnText)
.catch((err) => console.error("Could not copy page link.", err));
} else {
const textArea = document.createElement("textarea");
textArea.value = currentUrl;
textArea.style.position = "fixed";
textArea.style.left = "-9999px";
document.body.appendChild(textArea);
textArea.select();
try {
document.execCommand("copy");
updateBtnText();
} catch (err) {
console.error("Could not copy page link.", err);
}
document.body.removeChild(textArea);
}
}
You can view the final result in this CodePen.
If you want to see a detailed explanation, you can check this article on my Medium blog.
Thank you for reading.