3D Ham Sandwich Animation
Tags: frontendchallenge, devchallenge, css, html
Published: 2024-03-23 23:42:03

_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
``` 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
``` 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](https://codepen.io/Front-End-Learner/pen/MWRmLzZ)

## 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.

[MIT License](https://opensource.org/license/mit)