Penguin
The Project
Animated and interactive penguin developed with CSS Transforms, creating a complete character with animations, interactions and an Antarctic landscape. The last guided project before the final portfolio.
Source Code
- index.html
- styles.css
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Penguin</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div class="left-mountain"></div>
<div class="back-mountain"></div>
<div class="sun"></div>
<div class="penguin">
<div class="penguin-head">
<div class="face left"></div>
<div class="face right"></div>
<div class="chin"></div>
<div class="eye left">
<div class="eye-lid"></div>
</div>
<div class="eye right">
<div class="eye-lid"></div>
</div>
<div class="blush left"></div>
<div class="blush right"></div>
<div class="beak top"></div>
<div class="beak bottom"></div>
</div>
<div class="shirt">
<div>💜</div>
<p>I CSS</p>
</div>
<div class="penguin-body">
<div class="arm left"></div>
<div class="arm right"></div>
<div class="foot left"></div>
<div class="foot right"></div>
</div>
</div>
<div class="ground"></div>
</body>
</html>
:root {
--penguin-face: white;
--penguin-picorna: orange;
--penguin-skin: gray;
}
body {
background: linear-gradient(45deg, rgb(118, 201, 255), rgb(247, 255, 222));
margin: 0;
padding: 0;
width: 100%;
height: 100vh;
overflow: hidden;
}
.left-mountain {
width: 300px;
height: 300px;
background: linear-gradient(rgb(203, 241, 228), rgb(80, 183, 255));
position: absolute;
transform: skew(0deg, 44deg);
z-index: 2;
margin-top: 100px;
}
.back-mountain {
width: 300px;
height: 300px;
background: linear-gradient(rgb(203, 241, 228), rgb(47, 170, 255));
position: absolute;
z-index: 1;
transform: rotate(45deg);
left: 110px;
top: 225px;
}
.sun {
width: 200px;
height: 200px;
background-color: yellow;
position: absolute;
border-radius: 50%;
top: -75px;
right: -75px;
}
.penguin {
width: 300px;
height: 300px;
margin: auto;
margin-top: 75px;
z-index: 4;
position: relative;
transition: transform 1s ease-in-out 0ms;
}
.penguin * {
position: absolute;
}
.penguin:active {
transform: scale(1.5);
cursor: not-allowed;
}
.penguin-head {
width: 50%;
height: 45%;
background: linear-gradient(
45deg,
var(--penguin-skin),
rgb(239, 240, 228)
);
border-radius: 70% 70% 65% 65%;
top: 10%;
left: 25%;
z-index: 1;
}
.face {
width: 60%;
height: 70%;
background-color: var(--penguin-face);
border-radius: 70% 70% 60% 60%;
top: 15%;
}
.face.left {
left: 5%;
}
.face.right {
right: 5%;
}
.chin {
width: 90%;
height: 70%;
background-color: var(--penguin-face);
top: 25%;
left: 5%;
border-radius: 70% 70% 100% 100%;
}
.eye {
width: 15%;
height: 17%;
background-color: black;
top: 45%;
border-radius: 50%;
}
.eye.left {
left: 25%;
}
.eye.right {
right: 25%;
}
.eye-lid {
width: 150%;
height: 100%;
background-color: var(--penguin-face);
top: 25%;
left: -23%;
border-radius: 50%;
}
.blush {
width: 15%;
height: 10%;
background-color: pink;
top: 65%;
border-radius: 50%;
}
.blush.left {
left: 15%;
}
.blush.right {
right: 15%;
}
.beak {
height: 10%;
background-color: var(--penguin-picorna);
border-radius: 50%;
}
.beak.top {
width: 20%;
top: 60%;
left: 40%;
}
.beak.bottom {
width: 16%;
top: 65%;
left: 42%;
}
.shirt {
font: bold 25px Helvetica, sans-serif;
top: 165px;
left: 127.5px;
z-index: 1;
color: #6a6969;
}
.shirt div {
font-weight: initial;
top: 22.5px;
left: 12px;
}
.penguin-body {
width: 53%;
height: 45%;
background: linear-gradient(
45deg,
rgb(134, 133, 133) 0%,
rgb(234, 231, 231) 25%,
white 67%
);
border-radius: 80% 80% 100% 100%;
top: 40%;
left: 23.5%;
}
.penguin-body::before {
content: "";
position: absolute;
width: 50%;
height: 45%;
background-color: var(--penguin-skin);
top: 10%;
left: 25%;
border-radius: 0% 0% 100% 100%;
opacity: 70%;
}
.arm {
width: 30%;
height: 60%;
background: linear-gradient(
90deg,
var(--penguin-skin),
rgb(209, 210, 199)
);
border-radius: 30% 30% 30% 120%;
z-index: -1;
}
.arm.left {
top: 35%;
left: 5%;
transform-origin: top left;
transform: rotate(130deg) scaleX(-1);
animation: 3s linear infinite wave;
}
.arm.right {
top: 0%;
right: -5%;
transform: rotate(-45deg);
}
@keyframes wave {
10% {
transform: rotate(110deg) scaleX(-1);
}
20% {
transform: rotate(130deg) scaleX(-1);
}
30% {
transform: rotate(110deg) scaleX(-1);
}
40% {
transform: rotate(130deg) scaleX(-1);
}
}
.foot {
width: 15%;
height: 30%;
background-color: var(--penguin-picorna);
top: 85%;
border-radius: 50%;
z-index: -1;
}
.foot.left {
left: 25%;
transform: rotate(80deg);
}
.foot.right {
right: 25%;
transform: rotate(-80deg);
}
.ground {
width: 100vw;
height: calc(100vh - 300px);
background: linear-gradient(90deg, rgb(88, 175, 236), rgb(182, 255, 255));
z-index: 3;
position: absolute;
margin-top: -58px;
}
The "Total Review" Feeling
At multiple moments during this project I thought it was oriented toward total review. freeCodeCamp was created with this perspective, but in this last project, maybe because it's the last guided project to conclude the course, I felt this sensation even more.
It's like the "greatest hits" of everything I've learned so far: CSS Variables, transforms, animations, positioning, gradients, pseudo-elements, advanced selectors... all in one adorable project!
The CSS Cursors Discovery
I really liked the part where I learned cursor: not-allowed, I wanted to delve deeper to discover the others and this is what I found:
cursor: pointer; /* 👆 Hand (clickable) */
cursor: grab; /* ✋ Open hand (grabbable) */
cursor: grabbing; /* ✊ Closed hand (dragging) */
cursor: not-allowed; /* 🚫 Access denied */
cursor: wait; /* ⏳ Hourglass (wait) */
cursor: help; /* ❓ Question mark */
cursor: text; /* 📝 Text cursor */
The UX impact of cursors: Each cursor instantly communicates an affordance to the user. pointer says "you can click", grab suggests "you can drag", wait informs "the system is processing", not-allowed prevents frustration by clearly showing limits. They're micro-interactions that make the interface more intuitive.
What I Learned
Advanced CSS Transforms:
- transform-origin for custom rotation points
- scaleX(-1) to flip elements horizontally
- Complex combinations of rotate + scale
- transform on interactive states (:active)
Sophisticated Animations:
- @keyframes with precise timing
- animation with linear, infinite and custom durations
- Waving animations that repeat infinitely
CSS Variables in Action:
- Design system for penguin colors
- Chromatic consistency throughout the project
- Easy global modification
Creative Pseudo-elements:
- ::before to create additional shapes
- Layering with z-index for depth
- Opacity for overlay effects
Creative Layout:
- Absolute positioning for millimetric precision
- Complex border-radius for organic shapes
- Linear gradients for realistic gradations
The Energy for the Final Project
I'm super excited for the final project, namely Personal Portfolio Webpage Certification Project!
Now it's time to put everything together in a portfolio that tells this incredible journey.
Next Project: Personal Portfolio Webpage (CERTIFICATION PROJECT!)