📁 last tech Posts

Responsive Profile Card with HTML & CSS [Full Code]

How to build a responsive profile card with HTML and CSS — full source code and step-by-step guide

A step-by-step guide to building a responsive, animated profile card using only HTML and CSS — no frameworks required.

If you're searching for a responsive profile card built with HTML and CSS, you're in exactly the right place. This guide gives you the complete, working source code along with a thorough explanation of every decision — from the HTML skeleton to the SCSS architecture — so you don't just copy and paste, you actually understand what's happening.

In my experience teaching front-end fundamentals, the profile card is one of the most requested beginner projects for a good reason: it forces you to deal with circular images, CSS gradients, hover animations, and responsive breakpoints all at once. Master this component and you'll have the intuition to build virtually any UI card going forward.

I'm Mostafa Amaan, and throughout this guide I'll walk you through the full project from an empty folder to a polished, animated card — explaining not just the how but the why behind each line of code.

What You'll Build in This Guide

By the end of this tutorial you'll have a fully functional profile card that includes:

  • A circular profile photo with a decorative colored border
  • User name and job title
  • Clickable social media icon links
  • An info button that reveals extra details on hover
  • A layout that adapts cleanly to mobile, tablet, and desktop screens
Final result of the responsive HTML CSS profile card project with hover animation

The finished product: an animated, responsive CSS profile card.

What You Need Before You Start

This project is beginner-friendly, but you'll get the most out of it if you already have a basic grasp of:

Skill Level Required Where to Learn
HTML Basic (tags & structure) Programming Languages Guide
CSS Basic (Box Model, Flexbox) —
SCSS Optional — explained in this article Covered below
💡 Quick tip: The complete source code is available in the GitHub repository linked at the end of this article. Feel free to download it and preview the result before reading the explanation — sometimes seeing the end product first makes the code click faster.

Setting Up the Project Structure

The project is made up of seven files organized in a clean, scalable folder structure:

  • index.html — Main HTML file
  • assets/css/styles.css — Compiled CSS output
  • assets/img/perfil.png — Profile photo
  • assets/scss/styles.scss — SCSS entry point
  • assets/scss/base/_base.scss — Global resets and base styles
  • assets/scss/components/_card.scss — Card component styles
  • assets/scss/config/_variables.scss — Design tokens (colors, fonts, sizes)

This structure follows the SCSS Partials pattern — a widely-used approach in professional front-end projects where styles are split into small, focused files (called partials, prefixed with _) and then imported into a single entry point. It might feel like extra overhead for a small project, but learning this pattern now will save you enormous time when your projects grow.

card-info/
├── index.html
└── assets/
    ├── css/
    │   └── styles.css
    ├── img/
    │   └── perfil.png
    └── scss/
        ├── styles.scss
        ├── base/
        │   └── _base.scss
        ├── components/
        │   └── _card.scss
        └── config/
            └── _variables.scss

Step 1 — Building the HTML Structure (index.html)

Start by creating the project's root folder — I named mine card-info, but you can call it anything. Inside, create index.html. This is the skeleton that holds every visual element together.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <!--=============== Icons ===============-->
    <link href="https://cdn.jsdelivr.net/npm/remixicon@2.5.0/fonts/remixicon.css"
          rel="stylesheet">

    <!--=============== CSS ===============-->
    <link rel="stylesheet" href="assets/css/styles.css">

    <title>Profile Card — Valley4Techs</title>
</head>
<body>
    <div class="container">
        <!-- Card markup goes here —
             full code available in the GitHub repository -->
    </div>
</body>
</html>

Line-by-line breakdown:

  • <!DOCTYPE html> — Tells the browser this is an HTML5 document. Always include it; without it, older browsers enter quirks mode and your layout breaks unpredictably.
  • lang="en" — Sets the document language. Screen readers and search engines both use this attribute.
  • charset="UTF-8" — Ensures special characters, em dashes, and emoji render correctly in every browser.
  • name="viewport" — The single most important meta tag for responsive design. Without it, mobile browsers render the page at desktop width and then scale it down, making everything tiny.
  • Remixicon CDN link — Loads the icon library we use for social media buttons. More on this library below.

Step 2 — The Main CSS File (styles.css)

Create the folder path assets/css/ and inside it a file named styles.css. If you're working with plain CSS (no SCSS compiler), this is where all your styles will live. If you're using SCSS, this file is the compiled output — you won't edit it directly.

Here's the core of the file — the CSS custom properties (design tokens) and Google Fonts import:

/*=============== Google Fonts ===============*/
@import url("https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600&display=swap");

/*=============== CSS Variables ===============*/
:root {
  /* Colors — HSL format (hue, saturation, lightness) */
  --first-color:         hsl(175, 55%, 40%);
  --first-color-light:   hsl(175, 30%, 48%);
  --first-color-lighten: hsl(175, 40%, 62%);
  --gradient-color: linear-gradient(
                      180deg,
                      hsl(178, 35%, 45%),
                      hsl(178, 55%, 28%)
                    );
  --title-color: hsl(175, 40%, 16%);
  --text-color:  hsl(175,  8%, 50%);
  --white-color: #fff;
  --body-color:  hsl(175, 100%, 99%);

  /* Typography — .5rem = 8px | 1rem = 16px */
  --body-font:         "Poppins", sans-serif;
  --h2-font-size:      1.25rem;
  --normal-font-size:  .938rem;
  --smaller-font-size: .75rem;
}

/*=============== Base Styles ===============*/
/* Full code available in the GitHub repository */

Why CSS variables? A common mistake I see in beginner projects is hard-coding color values in dozens of places. When the client asks you to change the brand green to a brand blue, you end up doing a find-and-replace that inevitably misses something. By defining all colors in :root, you change one line and the entire card updates. It's the same principle behind design tokens in frameworks like Tailwind or Material UI.

Why HSL colors? HSL (Hue, Saturation, Lightness) is far more intuitive for hand-writing color variations than hex or RGB. To make a color darker, just decrease the lightness value. To make it more muted, decrease saturation. You'll notice the entire palette in this project is built on a single hue (175–178°, a teal-green), with only saturation and lightness varying — that's why everything looks cohesive.

Step 3 — Adding the Profile Image

Create assets/img/ and drop in your profile photo. The filename in the project is perfil.png, but you can name it anything — just update the src attribute in your HTML accordingly.

⚠️ Important: Use a PNG with a transparent background. The card's CSS applies a colored circular border around the image element. If your photo has a white background, that white box will sit on top of the border and hide it completely — the decorative ring just won't appear. Tools like remove.bg can strip the background for free in seconds.

Step 4 — The SCSS Entry Point (styles.scss)

Create assets/scss/styles.scss. This file's only job is to pull together the three partials:

@import 'config/variables';
@import 'base/base';
@import 'components/card';

Order matters here. Variables must be imported first because both _base.scss and _card.scss reference the custom properties defined in _variables.scss. If you flip the order, the SCSS compiler will throw "undefined variable" errors.

If you've never used SCSS before and the compiler step sounds intimidating, install the Live Sass Compiler extension in VS Code. It watches your .scss files and automatically outputs styles.css every time you save — zero command-line required.

Step 5 — Global Resets (_base.scss)

Create assets/scss/base/_base.scss. This partial handles the universal reset styles that every project needs:

/*=============== Base Resets ===============*/
* {
    box-sizing: border-box;
    padding: 0;
    margin: 0;
}

body {
    font-family: var(--body-font);
    font-size: var(--normal-font-size);
    background-color: var(--body-color);
    color: var(--text-color);
}

ul  { list-style: none; }
a   { text-decoration: none; }
img { max-width: 100%; height: auto; }

What each block does:

  • * { box-sizing: border-box } — This is the single most impactful CSS reset you can write. By default, browsers add padding outside an element's declared width. With border-box, padding is included inside the width, so a width: 290px element is always exactly 290px wide — no surprises.
  • padding: 0; margin: 0; — Browsers apply different default margins to headings, paragraphs, and lists. Zeroing them out means your layout behaves identically across Chrome, Firefox, and Safari.
  • ul { list-style: none } — Removes the default bullet points from the social icons list. Without this, you'd see bullets next to your Twitter and GitHub icons.
  • img { max-width: 100%; height: auto } — Makes every image responsive by default. The image scales down on small screens but never overflows its container.

Step 6 — Styling the Card Component (_card.scss)

Create assets/scss/components/_card.scss. This is the heart of the project — it defines the card's shape, gradient background, and the hover animation.

/*=============== Card ===============*/
.container {
    height: 100vh;
    margin-inline: 1.5rem;
    display: grid;
    place-items: center;
}

.card {
    position: relative;
    width: 290px;
    background: var(--gradient-color);
    border-radius: 1rem 1rem 11rem 11rem;
    padding: 2.5rem 1.5rem 3.5rem;
    text-align: center;
    box-shadow: 0 8px 32px hsla(178, 55%, 20%, .15);

    &__img {
        width: 90px;
    }

    &__border {
        /* Full code in GitHub repository */
    }

    &__info {
        position: absolute;
        bottom: -4rem;        /* Hidden by default */
        transition: bottom .3s ease;
    }
}

/* Reveal info panel on hover and focus */
.card:hover .card__info,
.card:focus .card__info {
    bottom: 1.5rem;
}

Design decisions worth noting:

  • border-radius: 1rem 1rem 11rem 11rem — The four values map to top-left, top-right, bottom-right, bottom-left. A subtle rounded top with dramatically rounded bottom corners creates that distinctive "pill bottom" shape you see in the preview GIF.
  • display: grid; place-items: center on .container — The cleanest one-liner for centering anything both horizontally and vertically. No more flexbox justify/align juggling for a centered single element.
  • The hover reveal mechanism — The info panel starts at bottom: -4rem (off-screen below the card) and transitions to bottom: 1.5rem on hover. This is pure CSS — no JavaScript needed.
  • :focus alongside :hover — I've noticed a lot of tutorials forget this. Hover effects don't trigger on touchscreens. Adding tabindex="0" to the card in HTML and pairing :focus with :hover in CSS makes the animation work when a mobile user taps the card.

Step 7 — Design Tokens (_variables.scss)

Create assets/scss/config/_variables.scss. While styles.css already includes CSS custom properties for runtime theming, this SCSS partial is where you define SCSS variables — values used during compilation, before the browser ever sees the file.

/*=============== Google Fonts ===============*/
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;500');

/*=============== CSS Variables ===============*/
:root {
    /* Colors */
    --first-color:         hsl(175, 55%, 40%);
    --first-color-light:   hsl(175, 30%, 48%);
    --first-color-lighten: hsl(175, 40%, 62%);
    --gradient-color: linear-gradient(
                        180deg,
                        hsl(178, 35%, 45%),
                        hsl(178, 55%, 28%)
                      );
    --title-color: hsl(175, 40%, 16%);
    --text-color:  hsl(175,  8%, 50%);
    --white-color: #fff;
    --body-color:  hsl(175, 100%, 99%);

    /* Typography */
    --body-font:         'Poppins', sans-serif;
    --h2-font-size:      1.25rem;
    --normal-font-size:  .938rem;
    --smaller-font-size: .75rem;
}

Making the Profile Card Truly Responsive

The number-one question I get from beginners is: "Why does my card look great on desktop but break on my phone?" Usually the culprit is one of two things.

1. Use relative units instead of fixed pixels

A common mistake I see in portfolio projects is writing font-size: 15px for everything. This project uses rem for spacing and typography. Since 1rem = 16px by default, the math is straightforward — but more importantly, if a user has bumped up their browser's default font size for accessibility, your layout scales with them instead of overriding their preference.

2. Add media queries for edge cases

Append these breakpoints at the bottom of _card.scss:

/*=============== Breakpoints ===============*/

/* Small devices — max 320px */
@media screen and (max-width: 320px) {
    .card {
        width: 250px;
        padding: 2rem 1rem 3rem;
    }
}

/* Medium devices — 576px and up */
@media screen and (min-width: 576px) {
    .card {
        width: 320px;
    }
}
💡 Pro tip: Test responsiveness without a physical device. In Chrome, press F12 to open DevTools, then hit Ctrl + Shift + M (or Cmd + Shift + M on Mac) to toggle the device emulator. You can simulate an iPhone SE, Pixel 7, iPad — any viewport size you want.

Common CSS Profile Card Mistakes (and How to Avoid Them)

After reviewing dozens of beginner CSS projects, these are the mistakes that come up most often:

Mistake Root Cause Fix
Image doesn't clip to a circle Missing overflow: hidden on the wrapper Add overflow: hidden to the image container alongside border-radius: 50%
SCSS won't compile No SCSS compiler installed Install the Live Sass Compiler extension in VS Code
Card overflows on small phones Missing viewport meta tag or fixed px widths Add <meta name="viewport"...> and switch to rem + media queries
Remixicon icons don't appear Wrong CDN URL or offline environment Double-check the CDN link or download the library locally from remixicon.com
Hover effect doesn't work on mobile :hover doesn't fire on touchscreens Add tabindex="0" to the card in HTML and add :focus alongside :hover in CSS

How to Customize the Card for Your Own Projects

The fastest way to make this card yours is to change the design tokens in _variables.scss — one file, everything updates. Here's a quick reference:

What to change Variable Example
Card gradient color --gradient-color Change the HSL hue values (e.g., 230° for blue)
Font family --body-font Replace 'Poppins' with any Google Font
Page background color --body-color Any HSL or hex value
Card width .card { width } Try 260px–340px for most use cases

Want to display multiple cards on one page? Wrap the cards in a grid container:

.cards-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
    gap: 2rem;
    padding: 2rem;
}

This single CSS rule creates a responsive grid that automatically adjusts the number of columns based on the available viewport width — no media queries needed for the grid itself.

For deeper inspiration on building more advanced HTML/CSS components, check out our guide on how to learn programming languages effectively — it includes a structured roadmap for front-end development.

Final Result

Once you've pulled the full source code from the GitHub repository, your result should look like the animation below. Notice how the info panel smoothly slides up on hover, and how the card maintains its proportions across screen sizes:

Animated demo of the final responsive HTML CSS profile card with hover effect showing info panel

Final result: the responsive profile card with slide-up hover animation.

Conclusion

Building a responsive profile card with HTML and CSS is one of those projects that teaches you an outsized number of concepts for its size. In this guide, you covered:

  • Organizing a front-end project with the SCSS Partials pattern
  • Using CSS custom properties to create a maintainable design system
  • Writing a pure-CSS hover animation with zero JavaScript
  • Making a component truly responsive with rem units and media queries
  • Supporting touch devices with the :focus pseudo-class
  • Avoiding the five most common beginner CSS mistakes

The real value isn't the card itself — it's the mental model you now have for building any CSS component: define your tokens, write the base reset, style the component, layer in the interaction, then test responsiveness. Repeat that pattern and you'll be building production-ready UIs faster than you think.

If you want to keep pushing your front-end skills, have a look at our Python and SQLite beginner tutorial — understanding how front-end connects to a database is the natural next step once your UI skills are solid.

📬

Found this guide helpful?

Join hundreds of subscribers and get the latest tutorials and tech articles delivered straight to your inbox.

Yes, subscribe me! ✉️

🔒 No spam, ever. Unsubscribe at any time.

Frequently Asked Questions

❓ Can I use plain CSS instead of SCSS?

Absolutely. SCSS compiles down to regular CSS — the browser never sees SCSS directly. If you're just starting out, use the pre-compiled styles.css file from the GitHub repo and edit it directly. When your projects grow larger, SCSS's partials and variables will save you significant time, so it's worth learning eventually.

❓ What is Remixicon and is it free to use?

Remixicon is an open-source icon library with over 2,400 icons in a clean, neutral style. It's completely free for both personal and commercial use under the Apache 2.0 license. You can load it via CDN (as in this project) or download the files from remixicon.com for offline use.

❓ How do I add a CSS flip card (3D rotation) effect?

A flip card uses two properties: transform: rotateY(180deg) applied on hover and backface-visibility: hidden on both sides to prevent the back face from showing through. You need two child elements — a front face and a back face — inside a wrapper with perspective set. This project uses a slide-up approach instead, but the same CSS transition principles apply.

❓ Will this code work inside a React or Vue component?

Yes, with minor adjustments. In React, convert the file to .jsx and change every class attribute to className. Import the CSS as a module or use styled-components. In Vue, drop the HTML directly into a <template> block and scope the styles with <style scoped>. The CSS itself requires no changes in either framework.

❓ How do I display multiple profile cards in a grid?

Wrap all your cards in a container div and apply: display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 2rem;. This creates a responsive grid that automatically switches between one, two, or three columns depending on viewport width — no media queries needed for the grid itself.

❓ How do I change the card color scheme to something other than teal?

Open _variables.scss (or the :root block in styles.css) and change the hue value in the HSL colors. The entire palette is built on hue 175–178°. To switch to blue, change all hue values to around 220°. To switch to purple, try 270°. Saturation and lightness can stay the same — only the hue number needs updating.

📌 Enjoyed this guide? Share it with a developer friend who's learning front-end. And explore more practical tutorials at Valley4Techs — where we make tech accessible to everyone.

Add Valley4Techs as a Preferred Source

Follow us on Google News for the latest updates

Add Now
Mostafa Amaan
Mostafa Amaan
Technical educational content creator on my blog and YouTube channel. My goal with this content is to eradicate information technology literacy.
Comments