3D Ham Sandwich Animation
FrontEndWebDeveloping
Posted on March 23, 2024
This is a submission for DEV Challenge v24.03.20, CSS Art: Favorite Snack.
Inspiration
Ham sandwiches are my favorite lunch. Especially with Louisiana hot sauce mixed with the mayonnaise.
Here's My Code:
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Ham Sandwich</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<section>
<div class="top-bread">
<div class="top-crust">
<div class="top-center"></div>
</div>
</div>
<div class="mayo-and-hot-sauce">
<div class="blob blob-one"></div>
<div class="blob blob-two"></div>
<div class="blob blob-three"></div>
<div class="blob blob-four"></div>
<div class="blob blob-five"></div>
<div class="blob blob-six"></div>
<div class="blob blob-seven"></div>
<div class="blob blob-eight"></div>
</div>
<div class="ham-edge-one">
<div class="ham-layer-one"></div>
</div>
<div class="ham-edge-two">
<div class="ham-layer-two"></div>
</div>
<div class="bottom-bread">
<div class="bottom-crust">
<div class="bottom-center"></div>
</div>
</div>
</section>
</body>
</html>
CSS
*{
box-sizing: border-box;
}
:root{
--ham-background: linear-gradient(
45deg,
rgb(180,100,120),
rgb(220,140,160),
rgb(180,100,120),
rgb(220,140,160)
);
--ham-border-background: linear-gradient(
45deg,
rgb(200,120,140),
rgb(240,160,180),
rgb(200,120,140),
rgb(240,160,180)
);
--ham-background-two: linear-gradient(
45deg,
rgb(220,140,160),
rgb(180,100,120),
rgb(220,140,160),
rgb(180,100,120)
);
--ham-border-background-two: linear-gradient(
45deg,
rgb(240,160,180),
rgb(200,120,140),
rgb(240,160,180),
rgb(200,120,140)
);
}
body{
display: grid;
align-items: center;
justify-content: center;
height: 100vh;
width: 100vw;
}
section{
height: 300px;
width: 600px;
display: grid;
justify-content: center;
transform-style: preserve-3d;
transition: transform 2.5s;
transform: rotate3d(15, 1, 1, 40deg);
}
section:hover{
transform: rotate3d(1, 1, 1, 25deg) matrix3d(
3, 0, 0, 0,
0, 3, 0, 0,
0, 0, 3, 0,
100, 100, 0, 4
);
}
.top-bread{
display: grid;
z-index: 5;
}
.top-crust{
width: 350px;
height: 130px;
transform: skewX(-50deg);
border-radius: 25px 50px 5px 50px;
background-color: rgb(150,90,60);
display: flex;
align-items: center;
justify-content: center;
padding: 0px 40px 20px 0px;
}
.top-center{
height: 100%;
width: 100%;
background: rgb(220,170,120);
border-radius: 25px 30px 5px 25px;
box-shadow: inset 2px 1px 5px 3px rgb(150,90,60);
}
.mayo-and-hot-sauce{
height: 130px;
width: 350px;
display: grid;
z-index: 4;
margin-top: -163px;
margin-left: 0px;
}
.blob{
background: rgb(255,180,170);
box-shadow: inset 0px 0px 4px 2px rgb(200,120,140);
}
.blob-one{
width: 40%;
margin-left: 245px;
margin-top: 15px;
border-radius: 0px 10px 25px 0px;
height: 35px;
transform: rotate(10deg);
}
.blob-two{
width: 80%;
height: 40px;
margin-left: 45px;
margin-top: 25px;
border-radius: 0px 10px 90px 0px;
transform: rotate(2deg);
}
.blob-three{
width: 80%;
height: 20px;
width: 30px;
margin-left: 20px;
margin-top: 0px;
border-radius: 0px 0px 25px 50px;
transform: rotate(20deg);
}
.blob-four{
width: 80%;
height: 20px;
width: 50px;
margin-left: 220px;
margin-top: -20px;
border-radius: 0px 0px 50px 50px;
transform: rotate(10deg);
}
.blob-five{
width: 50px;
height: 25px;
margin-left: 90px;
margin-top: -22px;
transform: rotate(-20deg);
border-radius: 0px 0px 115px 80px;
}
.blob-six{
height: 40px;
width: 50px;
margin-left: -50px;
margin-top: -35px;
border-radius: 16px 0px 10px 20px;
transform: rotate(-20deg);
}
.blob-seven{
height: 30px;
width: 60px;
margin-top: -30px;
margin-left: 130px;
border-radius: 0px 0px 25px 40px;
transform: rotate(-15deg);
}
.blob-eight{
height: 60px;
width: 30px;
margin-left: 330px;
margin-top: -120px;
border-radius: 0px 0px 20px 0px;
transform: rotate(20deg);
}
.ham-edge-one{
width: 374px;
height: 130px;
transform: skewX(-50deg);
border-radius: 10px 30px 10px 25px;
background: var(--ham-border-background);
padding: 0px 3px 3px 0px;
z-index: 3;
margin-top: -180px;
margin-left: -15px;
}
.ham-layer-one{
width: 370px;
height: 128px;
background: var(--ham-background-two);
border-radius: 10px 27px 10px 24px;
}
.ham-edge-two{
width: 374px;
height: 130px;
transform: skewX(-50deg);
border-radius: 10px 30px 10px 25px;
background: var(--ham-border-background-two);
padding: 0px 3px 3px 0px;
z-index: 2;
margin-top: -205px;
margin-left: -14px;
}
.ham-layer-two{
width: 370px;
height: 128px;
background: var(--ham-background);
border-radius: 10px 27px 10px 24px;
}
.bottom-bread{
display: grid;
z-index: 1;
margin-top: -220px;
}
.bottom-crust{
width: 350px;
height: 130px;
transform: skewX(-50deg);
border-radius: 25px 50px 5px 50px;
background-color: rgb(150,90,60);
display: flex;
align-items: center;
justify-content: center;
padding: 0px 40px 20px 0px;
}
.bottom-center{
height: 100%;
width: 100%;
background: rgb(220,170,120);
border-radius: 25px 30px 5px 25px;
box-shadow: inset 2px 1px 5px 3px rgb(150,90,60);
}
@keyframes spin {
from {
transform:matrix3d();
}
to {
transform: rotate(360deg);
}
}
Code Link
Here is a link to the code in CodePen: myLink
Journey
I started by using a simple paint app I had already built to draw a rough sketch of the sandwich, just to clear things up in my mind. Then I started on my HTML. I chose the class names according to the part of the sandwich I intended each element to represent. Except for the section
, to hold the whole sandwich, (and the body
) I used div
elements for the whole creation.
Once I was done with the HTML I moved to the CSS. I started by defining my *
selector's properties. I set the box-sizing
and also I gave all the elements a border: 1px solid black
property and attribute. From there I started at the top of the sandwich and worked my way down (except that I styled both pieces of bread at once), styling parents, then children. Once everything but the .mayo-and-hot-sauce
element were styled, I put my sandwich together by setting the margin
properties to appropriate values.
Then, I started on the .mayo-and-hot-sauce
element. I added .blob
s and styled them, until it looked good to me.
Finally, I added the animation to the section
element. I've had little practice with CSS animations, so I had to play with it a while before it was to my liking.
With that, the project was finished. I learned several things. One would be, how to use the border-image
property. It's really neat. I used it to give my slices of ham a gradient border to match their background
properties. I also learned about the rotate3D
and matrix3D
properties of CSS.
In building the project I strove to make the sandwich appear 3D. This, along with realistic looking gradients, I would say are it's main high points, and the goal's I tried to achieve.
Posted on March 23, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.