Skip to content

Commit 1dbb2c2

Browse files
new blog post, added Description to post, updated xml feed
1 parent 970785e commit 1dbb2c2

3 files changed

Lines changed: 351 additions & 3 deletions

File tree

Lines changed: 349 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,349 @@
1+
---
2+
title: Knocking the CSS rust off
3+
description: 2 divs, 1 flip
4+
pubDate: 2026-01-24 14:42
5+
icon: LiNotebookPen
6+
---
7+
Meme aside, it's pretty amazing what you can do with CSS nowadays. Like I mentioned in my previous [post](/blog/so-i-created-a-website-again), CSS was my first love of the web. I wasn't doing the craziest things when I first started, but *Web 2.0* was in its infancy years. When I started doing web, 2.0 was less than 5 years old and the focus was more on the interactivity via user generated content, API's, Ajax and early stages of Social graphs. Hell, I was still writing ActionScript at my company for our client sites that all mashed up with Classic ASP, ASP.Net, and ColdFusion.
8+
9+
You could use the `animation` property and `@keyframes` at-rule then, but it was very browser specific, and in the days of IE, was a huge pain. The amount of hours I spent making something look the same across all the browsers, tweaking one prefix just slightly because Microsoft thinks they can reinvent the wheel. That kind of stuff didn't really get main-stream adoption until like 2010 or so. I had left the front-end space by that time, which is when support and adoption really took off it seems.
10+
11+
Having to add in every prefix you wanted to hope was supported, and then a fallback, just added more headache than it was worth.
12+
13+
For example, if you wanted to animate a div, you had to bloat your CSS like so:
14+
```css
15+
@-webkit-keyframes slide {
16+
0% { -webkit-transform: translateX(-100%); }
17+
100% { -webkit-transform: translateX(0); }
18+
}
19+
20+
@-moz-keyframes slide {
21+
0% { -moz-transform: translateX(-100%); }
22+
100% { -moz-transform: translateX(0); }
23+
}
24+
25+
@-o-keyframes slide {
26+
0% { -o-transform: translateX(-100%); }
27+
100% { -o-transform: translateX(0); }
28+
}
29+
30+
@keyframes slide {
31+
0% { transform: translateX(-100%); }
32+
100% { transform: translateX(0); }
33+
}
34+
35+
.box {
36+
width: 100px;
37+
height: 100px;
38+
background: #4caf50;
39+
-webkit-border-radius: 8px;
40+
-moz-border-radius: 8px;
41+
border-radius: 8px;
42+
-webkit-animation: slide 1s ease-in-out infinite alternate;
43+
-moz-animation: slide 1s ease-in-out infinite alternate;
44+
-o-animation: slide 1s ease-in-out infinite alternate;
45+
animation: slide 1s ease-in-out infinite alternate;
46+
}
47+
```
48+
49+
The Opera prefix, that brings back some memories...
50+
51+
Now you don't need all of that, you can omit the prefixes and every browser supports it. That makes it so much easier, and as a bonus CSS has advanced so much! I have the basic `@view-transition` enabled via the `<ClientRouter />` in Astro, but that opens the doors for so many cool ideas!
52+
53+
I won't be doing anything crazy or advanced in this post, just some practice with a coin flip using the CSS animations.
54+
55+
The following code examples can be found on [GitHub](https://github.com/Kyle-Undefined/examples.kyle-undefined.github.io).
56+
57+
We'll start off with a base of:
58+
<iframe src="https://examples.kyleundefined.dev/coin-flip/base.html" width="100%" height="100" loading="lazy" title="Base"></iframe>
59+
60+
This is just a simple:
61+
```css
62+
.container {
63+
border: solid 1px #848bbd;
64+
display: flex;
65+
justify-content: center;
66+
align-items: center;
67+
height: 400px;
68+
flex-direction: column;
69+
text-align: center;
70+
}
71+
.coin {
72+
width: 25%;
73+
border: solid 1px silver;
74+
}
75+
.table {
76+
width: 75%;
77+
border: solid 1px brown;
78+
}
79+
```
80+
```html
81+
<div class="container">
82+
<div class="coin">Coin</div>
83+
<div class="table">Table</div>
84+
</div>
85+
```
86+
87+
Now let's do a simple "flip" animation on the `coin` div. I have it set to infinitely loop for easier viewing.
88+
<iframe src="https://examples.kyleundefined.dev/coin-flip/base-ani.html" width="100%" height="200" loading="lazy" title="Base Animation"></iframe>
89+
90+
This is achieved with a simple `animation:` on the class like so:
91+
```css
92+
.coin {
93+
width: 25%;
94+
border: solid 1px silver;
95+
animation: coinflip 0.75s ease-in-out infinite normal 1s;
96+
/*
97+
animation-name: coinflip;
98+
animation-duration: 1s;
99+
animation-timing-function: ease-in-out;
100+
animation-iteration-count: infinite;
101+
animation-direction: normal;
102+
animation-delay: 1s;
103+
*/
104+
}
105+
@keyframes coinflip {
106+
0% { transform: rotateZ(0); }
107+
100% { transform: rotateZ(360deg); }
108+
}
109+
```
110+
111+
It's a very quick and dirty flip, but it works. So, I got the flip working, but now let's get the "up" of the flip working. Again, quick and dirty for the base, but I cleaned up the names a bit.
112+
<iframe src="https://examples.kyleundefined.dev/coin-flip/flip-up.html" width="100%" height="300" loading="lazy" title="Flip Up"></iframe>
113+
114+
I have to define the "up" and I can combine them on the `.coin` class like so:
115+
```css
116+
.coin {
117+
width: 25%;
118+
border: solid 1px silver;
119+
animation:
120+
coin-up 0.75s ease-in-out infinite normal 1s,
121+
coin-flip 0.75s ease-in-out infinite normal 1s;
122+
position: relative;
123+
}
124+
@keyframes coin-flip {
125+
0% { transform: rotateZ(0); }
126+
100% { transform: rotateZ(360deg); }
127+
}
128+
129+
@keyframes coin-up {
130+
0% { bottom: 0px; }
131+
100% { bottom: 100px; }
132+
}
133+
```
134+
135+
I have to set the `position` of the coin to be relative, otherwise the `bottom` won't move the div as I expect. But, as you can see the coin just resets back to the `table` when the animation is over.
136+
137+
You could add a new `keyframes` for a coin-down animation and play with the delays and orders of things, or you could just update the `coin-up` animation-direction to be `alternate` instead of `normal` which does what I am looking for.
138+
<iframe src="https://examples.kyleundefined.dev/coin-flip/flip-down.html" width="100%" height="300" loading="lazy" title="Flip Down"></iframe>
139+
140+
Boom! Coin flip animated, blog post done. You wish, I have to take this further!
141+
142+
I can combine the `keyframes` into one as a start, this will allow me to fine tune the animation itself.
143+
```css
144+
@keyframes coin-flip {
145+
0% {
146+
transform: rotateZ(0);
147+
bottom: 0px;
148+
}
149+
50% {
150+
transform: rotateZ(180deg);
151+
bottom: 100px;
152+
}
153+
100% {
154+
transform: rotateZ(360deg);
155+
bottom: 0px;
156+
}
157+
}
158+
```
159+
160+
This gives one flip of the coin when it goes up and down.
161+
<iframe src="https://examples.kyleundefined.dev/coin-flip/flip-one.html" width="100%" height="300" loading="lazy" title="Flip One"></iframe>
162+
163+
Let's add in more rotations.
164+
```css
165+
@keyframes coin-flip {
166+
0% {
167+
transform: rotateZ(0deg);
168+
bottom: 0px;
169+
}
170+
25% {
171+
transform: rotateZ(720deg);
172+
bottom: 75px;
173+
}
174+
50% {
175+
transform: rotateZ(1440deg);
176+
bottom: 100px;
177+
}
178+
75% {
179+
transform: rotateZ(2160deg);
180+
bottom: 75px;
181+
}
182+
100% {
183+
transform: rotateZ(2880deg);
184+
bottom: 0px;
185+
}
186+
}
187+
```
188+
189+
This gives a hilariously fast spin which kind of "jumps" in the air to do the rotations, but it's a start.
190+
<iframe src="https://examples.kyleundefined.dev/coin-flip/flip-funny.html" width="100%" height="300" loading="lazy" title="Flip Funny"></iframe>
191+
192+
In order to smooth out the flips, I need to add in more steps to the `keyframes` for more fine tune control of the transformations.
193+
<iframe src="https://examples.kyleundefined.dev/coin-flip/flip-smooth.html" width="100%" height="300" loading="lazy" title="Flip Smooth"></iframe>
194+
195+
That looks better, we're making progress! Isn't this so cool?! What more can I do to improve this? Well let's add in a delay after the animation is done so the coin sits on the table before the animation restarts. This can be done by adjusting the `keyframes` so the final stage is the delay.
196+
<iframe src="https://examples.kyleundefined.dev/coin-flip/flip-delay.html" width="100%" height="300" loading="lazy" title="Flip Delay"></iframe>
197+
198+
Here is how that looks in the CSS:
199+
```css
200+
@keyframes coin-flip {
201+
0% {
202+
transform: rotateZ(0deg);
203+
bottom: 0px;
204+
}
205+
8% {
206+
transform: rotateZ(72deg);
207+
bottom: 20px;
208+
}
209+
16% {
210+
transform: rotateZ(144deg);
211+
bottom: 40px;
212+
}
213+
24% {
214+
transform: rotateZ(216deg);
215+
bottom: 60px;
216+
}
217+
32% {
218+
transform: rotateZ(288deg);
219+
bottom: 80px;
220+
}
221+
40% {
222+
transform: rotateZ(360deg);
223+
bottom: 100px;
224+
}
225+
48% {
226+
transform: rotateZ(432deg);
227+
bottom: 80px;
228+
}
229+
56% {
230+
transform: rotateZ(504deg);
231+
bottom: 60px;
232+
}
233+
64% {
234+
transform: rotateZ(576deg);
235+
bottom: 40px;
236+
}
237+
72% {
238+
transform: rotateZ(648deg);
239+
bottom: 20px;
240+
}
241+
80% {
242+
transform: rotateZ(720deg);
243+
bottom: 0px;
244+
}
245+
100% {
246+
transform: rotateZ(720deg);
247+
bottom: 0px;
248+
}
249+
}
250+
```
251+
252+
Sure, it's not as simple as just adjusting properties, but it's fun to figure out the stages. CSS started supporting `var()` and `calc()` functions that allow you to set variables that you can use throughout the file and to calculate a value. Dynamic CSS is so neat!
253+
254+
Let's implement those functions in my example, so I can adjust the flip behavior without having to change everything.
255+
256+
First, we'll add in the variables:
257+
```css
258+
.coin {
259+
width: 25%;
260+
border: solid 1px silver;
261+
animation: coin-flip var(--anim-time) ease-in-out infinite normal var(--anim-delay);
262+
position: relative;
263+
264+
--rotation-min: 0deg;
265+
--rotation-max: 720deg;
266+
--rotation-step: calc(var(--rotation-max) / 10);
267+
--height-max: 100px;
268+
--height-step: calc(var(--height-max) / 5);
269+
--anim-delay: 1s;
270+
--anim-time: 5s;
271+
}
272+
```
273+
274+
What this does is create the variables that I can reference later. I set a Min and Max for the rotations, the Max determines how many flips is done by the coin, and is 2 flips by default. Then I set a Step for the rotations which is calculated off of the Max / 10. *Had to do math for this, ew, yuck!* The Max Height is how far up the coin goes up off the table, and that's used to calculate the step for the up/down animation. I call the Time/Delay variables for control over that as well.
275+
276+
With those setup, I can update the `@keyframes` to use those variables, and do some calculations of itself for the steps:
277+
```css
278+
@keyframes coin-flip {
279+
0% {
280+
transform: rotateZ(var(--rotation-min));
281+
bottom: 0px;
282+
}
283+
8% {
284+
transform: rotateZ(calc(var(--rotation-step) * 1));
285+
bottom: calc(var(--height-step) * 1);
286+
}
287+
16% {
288+
transform: rotateZ(calc(var(--rotation-step) * 2));
289+
bottom: calc(var(--height-step) * 2);
290+
}
291+
24% {
292+
transform: rotateZ(calc(var(--rotation-step) * 3));
293+
bottom: calc(var(--height-step) * 3);
294+
}
295+
32% {
296+
transform: rotateZ(calc(var(--rotation-step) * 4));
297+
bottom: calc(var(--height-step) * 4);
298+
}
299+
40% {
300+
transform: rotateZ(calc(var(--rotation-step) * 5));
301+
bottom: var(--height-max);
302+
}
303+
48% {
304+
transform: rotateZ(calc(var(--rotation-step) * 6));
305+
bottom: calc(var(--height-step) * 4);
306+
}
307+
56% {
308+
transform: rotateZ(calc(var(--rotation-step) * 7));
309+
bottom: calc(var(--height-step) * 3);
310+
}
311+
64% {
312+
transform: rotateZ(calc(var(--rotation-step) * 8));
313+
bottom: calc(var(--height-step) * 2);
314+
}
315+
72% {
316+
transform: rotateZ(calc(var(--rotation-step) * 9));
317+
bottom: calc(var(--height-step) * 1);
318+
}
319+
80% {
320+
transform: rotateZ(var(--rotation-max));
321+
bottom: 0px;
322+
}
323+
100% {
324+
transform: rotateZ(var(--rotation-max));
325+
bottom: 0px;
326+
}
327+
}
328+
```
329+
330+
Phew, that's a lot! Let's break that down...
331+
332+
I start with the base step which is just the coin being on the "table". I then calculate the transform value from the Step * step number, and the bottom value from the height step * step number. The step number for the `transform` and `bottom` is the calculated degrees/height per animation stage. The height step goes up to 4 and then back down to 1. The rotation step goes up to 9 for the pause at the end. I then end the animation with the div being "reset" and resting.
333+
334+
Visually nothing changes, and technically functionality doesn't change either. However, this now allows me to adjust the coin flip by changing a few lines instead of the whole `@keyframes` setup.
335+
<iframe src="https://examples.kyleundefined.dev/coin-flip/flip-func.html" width="100%" height="300" loading="lazy" title="Flip Func"></iframe>
336+
337+
Want a slow mode flip? Easy, just adjust the `--anim-time` variable to `5s` and boom, it all updates.
338+
<iframe src="https://examples.kyleundefined.dev/coin-flip/flip-slow.html" width="100%" height="300" loading="lazy" title="Flip Slow"></iframe>
339+
340+
Oh I know what you want, you want that quadruple rotation flip! Coming right up! `--rotation-max: 1440deg;` is all you'd have to adjust.
341+
<iframe src="https://examples.kyleundefined.dev/coin-flip/flip-four.html" width="100%" height="300" loading="lazy" title="Flip Four"></iframe>
342+
343+
I could adjust the borders to make it more coin shaped, but this is just examples and practice.
344+
345+
Again, all the code for these examples can be found in my [examples](https://github.com/Kyle-Undefined/examples.kyle-undefined.github.io) repo over on GitHub. Below is a final example utilizing all of this to have separate coins flip with different animations.
346+
347+
Catch ya on the flip side!
348+
349+
<iframe src="https://examples.kyleundefined.dev/coin-flip/flip-final.html" width="100%" height="1480" loading="lazy" title="Flip Final"></iframe>

src/pages/blog/[...slug].astro

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ const { Content } = await post.render();
3333
<h1 class="text-3xl md:text-5xl font-bold mb-6 text-blog-accent leading-tight">
3434
{post.data.title}
3535
</h1>
36+
<h2>{post.data.description}</h2>
3637
</div>
3738

3839
<div class="prose prose-invert prose-lg max-w-none

src/pages/rss.xml.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,7 @@ export async function GET(context) {
2626
description: post.data.description,
2727
link: `/blog/${post.slug}/`,
2828
pubDate: post.data.pubDate,
29-
content: sanitizeHtml(parser.render(post.body), {
30-
allowedTags: sanitizeHtml.defaults.allowedTags.concat(['img'])
31-
}),
29+
content: sanitizeHtml(parser.render(post.body.replaceAll(/<iframe[^>]*src=["']([^"']+)["'][^>]*>.*?<\/iframe>/gi, '[Note: Embedded content from $1]'))),
3230
})),
3331
});
3432
}

0 commit comments

Comments
 (0)