Tushar ShuklaA senior frontend developer, curious tech tinkerer and an anime fan.
0 views
18 mins read
Batman image made with CSS
It's not who I am underneath, but what I code that defines me.
Welcome, fellow web vigilantes! Ever dreamt of building Gotham's protector, not with Batarangs and brute force, but with the sheer power of CSS? Well, I did. And let me tell you, it was a wild ride, a bit like chasing the Joker through the labyrinthine streets of Gotham, but ultimately, incredibly rewarding.
Our Mission (Difficult? Nah! Not much)
This blog post chronicles my journey of creating a responsiveBatman face entirely with CSS — yes, no images, not even SVGs. The Joker would love that shortcut, but we're better than that. Why did I take this challenge? Because some developers just want to watch the world learn (Batman quote - kinda 😄). Consider this my Bat-Signal to all frontend developers looking for a fun challenge. And yes, as Batman would say, “Have fun… because why not?”
Why CSS Art? (More Than Just a Pretty Face)
First of all, what is CSS Art — It's a digital image created using CSS. It's a creative way for coders to express themselves by combining their programming and artistic skills. While it's a lot of fun to create CSS art, it's not just limited to the fun factor alone!
Now, let's be real, building Batman's face in CSS is undeniably cool. But the benefits go beyond bragging rights at the
next tech meetup. Creating CSS art isn't just about showing off (though Alfred would approve). It is like a workout for
your frontend skills. It's a formidable exercise (training to be the Dark Knight himself) that challenges you to
think creatively, deepens your understanding of CSS properties, selectors, and layouts, and sharpens your
problem-solving abilities. And yes, it is also about impressing your colleagues with CSS wizardry that even the Riddler
couldn't decode.
Gotham's Villains – The Challenges
Every hero faces villains, and in the CSS world, our nemeses come in the form of:
Mindset Problem (The Scarecrow): Like facing your fears in Scarecrow's fear toxin, the biggest challenge was mental: "Where do I even start?" It's like standing before the Bat-Signal without knowing which direction to run.
Shape Struggles (The Penguin): Crafting those asymmetric curves can feel like trying to replicate the Joker's smile with CSS. How do you even create those complex shapes?
Stacking Index Zingers (The Joker): Z-index can be a tricky beast. Managing it is like dealing with the Joker – chaotic at first, but manageable once you understand the method to the madness. Arranging elements with z-index is akin to managing the layered secrets of Bruce Wayne's double life.
Positioning Perils (The Catwoman): Achieving pixel-perfect alignment while keeping everything responsive is no less challenging than balancing a high-speed chase on Gotham's rooftops.
Debugging Dilemmas (The Two-Face): Ever wondered why that property isn't behaving? It can feel like decoding a message from the Riddler himself.
Breaking Down the Bat: Thinking in Shapes
Before diving headfirst into the code, I found it helpful to visualize the Batman face in terms of basic shapes. Just as Batman breaks down his opponents' fighting styles, we need to break down our artwork into basic shapes. Think like Batman analyzing a crime scene. Here's what I did:
Dissect the image: Be like a butcher, cut every part and think of them as individual shapes. I broke down the Batman face into simple geometric shapes — circles, rectangles, triangles, and complex curves.
Use CSS tools: For those tricky parts like Batman's iconic lips or the asymmetric curves of his cowl, I relied on the clip-path property to mask and shape elements.
Determine a base shape: I chose a central shape as the foundation (batman's face in this case) and defined desired size (width and height) for it, and then derived all the other sizes relative to it. Choosing the right base shape is crucial – it's the foundation upon which everything else is built. Think of it as your Bat-cave — everything revolves around the core.
Batman face outline
Here's a snippet demonstrating how I used clip-path to create a complex shape:
In this snippet, --base-size acts as our core dimension. All other elements can be derived relative to this variable, ensuring responsiveness across devices.
Becoming the CSS Vigilante: Let's Code
Now, it's time to don the cape and get to work. I kickstarted my journey by setting up a CodePen project (because every Batman needs a Batcave) and also pushed the code to GitHub for those who want to fork their own version of the Dark Knight in CSS. The GitHub repo follows a structure that can help you understand the batman creation step-by-step. It's a basic setup using Vite and has the following file structure:
index.html - The main HTML file that sets up the structure.
src/styles - A directory containing CSS files that incrementally build the Batman image from 01.css up to 9.css.
I'd recommend you to check out the repo and follow along for the best understanding.
Enough talk, let's see some action!
Setting Up the Scene (01.css)
Begin by creating an index.html file. This file will serve as the canvas for our CSS art.
In this structure, we have a main tag that will hold our entire art. Inside this, we have a figure tag with the class .batman, which will be styled to represent the Batman image.Let's start with setting up the basic styles for the scene and Batman.
/* Setting initial styles for the app */html { font-size: 10px;}body { margin: 0; /* Making body of full screen width and height */ width: 100vw; height: 100vh; /* Ensuring nothing gets out of the screen and we don't see scroll-bars under any circumstances */ overflow: hidden; /* Setting a BATMAN-ish dark background - OPTIONAL */ background-image: radial-gradient(circle, rgb(0, 69, 93) 0%, rgb(5, 19, 38) 50%);}.scene { display: flex; /* Ensuring our scene is fully contained within */ height: 100%; width: 100%; position: relative;}.batman { /* Adding a red border just to see how things are shaping up */ border: 1px solid red; /* Setting width and height based on whatever looks appropriate */ width: 40vmin; height: 60vmin; /* Below 3 lines are to center the batman element */ position: absolute; inset: 0; margin: auto;}
Notice that I've used viewport units (vmin) for sizing. This ensures that the image scales proportionally with the viewport size. The inset: 0 property is a shorthand for setting top, right, bottom, and left to 0.
This, along with position: absolute and margin: auto, centers the .batman element within the .scene.
Building the Base - The Face (02.css)
Before we begin, scroll up to the top and look at the image of Batman. Notice how the face is a simple trapezoid shape.
A trapezoid is like a rectangle that has at least one pair of parallel sides, making it look like a table top when viewed from the side. We can create this shape cleverly using CSS's border property.
<div class="trapezoid"></div>
.trapezoid { /* Start with an empty box */ width: 200px; height: 100px; /* height can be removed once the border magic is done */ /* The magic happens with borders */ border-bottom: 100px solid #3498db; /* This creates the main body - height of the trapezoid */ border-left: 50px solid transparent; /* Creates the left slant */ border-right: 50px solid transparent; /* Creates the right slant */}
Let me break down how this works:
First, we create a container element and give it a specific width (200px in this case). The height is set to 100px, which will be the height of our trapezoid.
The real magic happens with the borders. Think of it like this: when you make a border transparent and give different sizes to different sides, CSS creates slanted edges (notice the peach slanted dotted lines between the outer and inner box).
Now pay attention to the shaded border-bottom in the diagram. We already have our trapezoid (somewhat). We're using this behavior to our advantage:Box with borders
Trapezoid Box with borders
The bottom border creates the main body of the trapezoid with a solid color (in this case, a nice peach color).
The left and right borders are made transparent, and when they meet the bottom border, they create those characteristic slanted sides.
Border top is removed as we don't need it for a trapezoid shape.
The initial height property can be removed as it's not needed once the border magic is done.
You can adjust the measurements to make your trapezoid wider, taller, or change how much it slants. For example:
Making the left and right borders larger will create steeper slants
Changing the width will make the trapezoid wider or narrower
Adjusting the border-bottom size will make it taller or shorter
This might seem like a tricky way to create a shape, but it's actually one of the most efficient methods in CSS. The border technique is widely used because it performs well and works across all modern browsers.
Now that we know how to create a trapezoid, let's see how we can use this trick in our Batman face and start building
the face of our Dark Knight.
In this snippet, notice the usage of CSS variables in :root. Think of :root as JavaScript's global scope where you can define variables that can be used across the project.
The trick is to define ONE and ONLY ONE size of the base shape and derive all other sizes from it. There is no specific rule to define the base shape, but it should be the most prominent shape in the image. In this case, the face of Batman is the most prominent shape, so I've defined the width and height of the face as the base shape.
As for the logic of deriving other sizes, it's a mix of trial and error and a bit of math. The --bat-face-h variable is derived from the --bat-face-w variable.
This is one of the most crucial techniques to ensure that the image scales proportionally with the viewport size and is responsive.
Now, let's focus on the trapezoid trick we learned earlier. I've used the same technique to create the head of
Batman. I gave border-bottom a solid color (black) with the width of the desired height of the face. The left and right
borders are transparent to create the slanted sides of the trapezoid. The --bat-face-side variable is used to control
the slant of the trapezoid.
By now, we should have something like this: Batman face with trapezoid
Adding ears (03.css)
Now that we have the face, let's add the ears. Batman's ears are a simple triangle shape. We can create this using the border technique as well. Creating a triangle is very similar to creating a trapezoid. This can be achieved by setting the height AND width of the element to 0 while retaining the trapezoid logic.I've used pseudo elements to create ears. pseudo elements are like invisible elements that you can add to any element. They are very useful for adding decorative elements to your page without cluttering your HTML.
Pay attention to the transform: scaleX(-1) property in the batman__eyes::after selector. This flips the element horizontally, creating a mirror image of the batman__eyes::before element. This is a neat trick to create symmetrical shapes without writing additional code. Also notice that instead of creating two separate elements for the eyes, I've used a single element and created two
pseudo-elements to represent the eyes. This is a great way to keep your HTML clean and organized.
The Dark Knight can see now: Batman face with eyes
Adding Mouth (05.css)
Once again, the mouth is a simple rectangle that contains a trapezoid shape chin and a triangle-shaped the nose (let's ignore the lips for now). We can use the same technique as we did for the face, eyes, and ears.
Gradually, our Batman is taking shape:
Batman face with mouth
Adding Lips (06.css)
The lips are a bit more complex than the other shapes we've created so far. The lips appear to be an oddly shaped polygon. We can use the clip-path property to create this shape.
Now that we have the face, let's add the shoulders. The shoulders are once again simple trapezoid shapes (ignore the cape curves for now). We can use the same technique as we did for the face, eyes, ears, and mouth.
Batman is now ready for action:
Batman face with shoulders
Adding Cape (08.css)
The cape is a bit more complex than the other shapes we've created so far. The cape appears to have a lot of inward curves which can be a bit tricky to create. My trick here is to create a transparent box, add curves to it's corners and then use box-shadow to create the illusion of curves. Check the red outlined batman image above to understand what I mean. Let's see how we can create the cape:
In the CSS code snippet above, I've used border-radius to create the curves in the cape. The border-radius property is a powerful tool that allows you to create rounded corners and complex shapes.
Notice the / keyword in border-radius syntax. This is used to define the horizontal and vertical radii of the corners. I've covered this in detail in the tips and tricks section below. I've also used box-shadow to create the illusion of curves in the cape. The box-shadow property is a versatile tool
that allows you to add shadows to elements. By cleverly using multiple values in box-shadow, you can create a variety
of visual effects, including curves, shadows, and highlights. Lastly, I've used the transform: scaleX(-1) property to flip the right side of the cape horizontally. This creates a
mirror image of the left side, giving the cape a symmetrical appearance.
Batman is now ready to take on the night: Batman face with cape
Adding subtle animations (09.css)
To add a bit of life to our Batman, let's add some subtle animations. We can use CSS animations to make Batman's eyes shrink and change it's color to red to show his anger. We'll also change his macho smile to a grim expression.First, let's animate the eyes:
In the CSS code snippet above, I've used the :hover pseudo-class to apply the animation when the user hovers over the Batman face. Notice how I've used the calc() function to calculate the reduced height of the eyes based on the width of the face.
I've not re-written the logic for height of the eye but have re-calculated the CSS variable that was being used for
height of the eye. NEAT!! right? Since the eyes were made using a triangle shape, I've changed the border color to red to show Batman's anger. I've also
used the margin-top property to move the eyes up a bit to give the impression that they are shrinking.
Now let's animate the lips. It's a lot simpler now that we know how to create complex shapes using clip-path.
And now our Batman is ready to take on the night:
Angry Batman face with cape
The Dark Knight's Secret: Tips & Tricks
Over the course of this project, I uncovered several tricks that every CSS superhero should have in their utility belt:
Responsive Sizing: Use a core shape defined in viewport units. All other dimensions? Derive them as multiples of this core. CSS variables are your best friend for customization. It's like having a master plan for every Gotham heist.
Border-Radius Wizardry: Experiment with different border-radius values to morph a rectangle into an ellipse, or even a more complex shape. Each corner can be manipulated individually—just as Batman adapts to every new challenge. The key factor for creating complex curves is to understand that you can provide two radii instead of just one in border-radius. Most of us are already aware of this syntax border-radius: 10px but what many miss is the syntax for adding another radius like border-radius: 10px / 15px . The first part (before forward slash) determines the first radius (for each corner) and the latter defines the other radii. Think of it as an ellipse shape which has two radii. You can refer to this MDN doc for more info on the syntax.
Box-Shadow & Scale: Not just for drop shadows! Use box-shadow to mimic a mirror effect and scale(-1) to flip elements. It's the secret behind many visual illusions in my code.
Translate vs. Margin: Remember, margin creates space by affecting surrounding elements, whereas translate simply moves the element visually. Use them wisely — like choosing the right Batmobile for a quick getaway. Knowing the difference is key.
Diagram showing margin and translate difference
/* Margin - creates space */.spacing { margin-top: 50px;}/_ Translate can move element visually without creating extra space _/.move {translate: transformY(50px);}
Beyond the Bat: Real-World Applications
While our CSS Batman might seem like a fun, isolated project, these techniques have plenty of real-world applications:
Artistic Expressions & Personal Portfolios: Create CSS portraits or abstract designs that stand out. Imagine a personal website that's as unique as Batman's utility belt. For example, my own personal website used lot of CSS wizardry, tailwind magic and framer motion tactics.
Interactive Experiences: Implement interactive elements like animated menus, engaging forms, or even casual web games. Who says coding can't be as entertaining as a night out with the Justice League?
Business Needs: There can be infinite kinds of business use-cases. For example, a clothing brand may use CSS-generated illustrations for character-based product displays or dynamic UI components in modern web applications – talk about dynamic product showcases!
Batman's Utility Belt: Resources & Inspirations (For the Aspiring Robin)
No superhero works in isolation, even Batman often needs Alfred and Robin. — here are some resources that helped me on my journey:
Building a Batman face entirely in CSS was both a challenging and exhilarating experience—a perfect blend of art, logic, and a bit of chaos reminiscent of Gotham itself. Here are my key takeaways:
Plan Your Shapes: Break down complex images into manageable CSS shapes.
Embrace the Challenges: Each obstacle, from stacking issues to positioning dilemmas, is an opportunity to level up your skills.
Leverage Modern CSS: With properties like clip-path, border-radius, box-shadow and CSS variables, the possibilities are as endless as Batman's gadgetry.
Have Fun: Whether you're coding a superhero face or designing an entire website, a little fun goes a long way. After all, even Batman needs a break from brooding in the Batcave sometimes.
I hope this journey inspires you to experiment with CSS in new and creative ways. Remember: In the world of front-end development, you're always just one clever trick away from being the hero Gotham (or your project) needs. And remember, even the Dark Knight started somewhere. Now, if you'll excuse me, I hear the Bat-Signal calling... Time to build a CSS Batmobile!
Stay heroic, code hard, and never forget — it's not who you are underneath, but what you do with your CSS that counts.
Happy coding!
Found an issue?
If you found a typo, incorrect information or have a feature request, please raise an issue by clicking this button.
With more than a decade into front-end wizardry, I can turn your ideas into pixel-perfect magic, with a side of witty banter and enough positivity to fuel a small city. Let's build something awesome together!