Quantcast
Viewing latest article 15
Browse Latest Browse All 15

Building a 3D Card Flip Animation with CSS Houdini

In this article, we'll explore Houdini's features by constructing a 3D card flip animation. This will help you uncover Houdini's core concepts and guide you through practical code implementation.

We'll explore how you can elevate your development workflow and achieve cutting-edge CSS animations using CSS Houdini, thereby gaining more control over your animation process.

Traditional CSS animations, while powerful, often confine developers to a predefined set of tools and effects. On the other hand, Houdini — a collection of experimental browser APIs — breaks these limitations, granting unprecedented control over the browser's rendering engine. It gives developers the ability to create custom visual experiences that were previously unimaginable, thereby pushing the boundaries of web design.

Key Concepts Covered in this Article

Here's a breakdown of the key concepts you'll learn in this article:

How to Work with Houdini's Major Triad

CSS Houdini is a collection of browser APIs that empower developers to extend and enhance the capabilities of the browser's rendering engine. With Houdini, developers can create custom animations, effects, and styles, pushing the boundaries of web design.

In the upcoming sections, we'll delve into a detailed explanation of the three primary APIs, unlocking their potential and understanding how they can elevate your web design and development capabilities.

Note: to enable Houdini on your browser, enter chrome://flags/ in the address bar, then search for experiments and activate it.

Image may be NSFW.
Clik here to view.
Enabling experimental features

Worklets

Houdini worklets are JavaScript modules that operate within the browser's rendering engine, allowing developers to define custom paint, layout, and animation behaviors, thereby extending the capabilities of CSS. With worklets, you can do the following:

  • Create dynamic animations. Imagine animating the stroke width of a path based on user interaction or dynamically controlling the speed of an animation based on scroll position. These are some of the possibilities that can be achieved with Houdini worklets.

  • Craft interactive effects. Create custom effects like particle systems, ripple animations, or even interactive text manipulation, all powered by worklet logic.

  • Extend visual styles. Generate custom gradients, patterns, or even textures based on complex algorithms, all within the worklet environment.

  • Bridge the gap with JavaScript. Integrate your existing JavaScript libraries and functionalities seamlessly into your CSS styles using worklet communication channels.

Getting Started with Worklets

As mentioned, worklets enable developers to create more complex and customizable effects in real life applications. To illustrate further, let's build a starry night effect using Houdini worklets:

<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="styles.css">
<title>Starry Night Sky</title>
</head>
<body>
<section id="night-sky">
</section>

<script>
CSS.paintWorklet.addModule('./app.js');
</script>
</body>
</html>

In the code snippet above, we prepare a dedicated section in the HTML, ready to accommodate the worklet effect when it's implemented:

<script>
    CSS.paintWorklet.addModule('./app.js');
</script>

The line CSS.paintWorklet.addModule('./app.js') tells the browser to grab the JavaScript code defining our paint worklet.

body {
margin: 0;
background-color: #000; /* Dark background for the night sky */
}

#night-sky {
width: 100vw;
height: 100vh;
background-image: paint(starrySky);
}

In the CSS code above, background-image: paint(starrySky) tells the #night-sky element to use our registered paint worklet named starrySky to generate the background instead of an image.

The JavaScript code below directly employs a standard loop and canvas drawing techniques to generate a varied starry sky effect with customizable colors, sizes, and random star positions:

class Star {
paint(ctx, geom, properties) {
const numStars = 100; // Adjust this to change the number of stars
const starColors = properties.get('--star-colors') || ['white', 'grey', 'darkorange'];
const sizeRange = properties.get('--star-size-range') || '2,3'; // the browser interprets the unit as pixels as default

for (let i = 0; i < numStars; i++) {
 const randomColor = starColors[Math.floor(Math.random() * starColors.length)];
 const minSize = parseFloat(sizeRange.split(',')[0]);
 const maxSize = parseFloat(sizeRange.split(',')[1]);
 const starSize = Math.random() * (maxSize - minSize) + minSize;
 const x = Math.random() * geom.width;
 const y = Math.random() * geom.height;
 ctx.fillStyle = randomColor;
 ctx.beginPath();
 ctx.arc(x, y, starSize, 0, 2 * Math.PI);
 ctx.fill();
 ctx.closePath();
}
}
}

registerPaint('starrySky', Star);

Here are some things to note in the code above:

  • class Star. This defines our paint worklet, a blueprint for drawing a single star.
  • paint(ctx, geom, properties). This is the core of the worklet. ctx provides drawing tools, geom gives information about the element's size, and properties accesses our custom CSS properties for star colors and size.
  • Loop and randomness. We draw multiple stars in a loop, choosing their position and color randomly for a natural starry effect.
  • registerPaint('starrySky', Star). This registers our Star class as a paint worklet named starrySky, making it accessible from CSS.

Image may be NSFW.
Clik here to view.
starry night

CSS Houdini Custom Properties

Custom properties in CSS Houdini are advanced variables offering enhanced control in web development. They go beyond traditional CSS variables, providing features like type checking, syntax definition, and custom logic for dynamic styling.

A circular progress bar with custom rendering

Let's dive into a practical example that showcases the power of paint worklets in creating visually captivating progress bars, looking at a simple example.

The simple HTML structure below establishes the foundation for our progress bar. A <div> element with the class progress serves as the canvas, while the data-progress attribute dynamically stores the current progress value:

<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Moving Circular Progress Bar</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div class="progress" data-progress="0"></div>

<script src="app.js"></script>
</body>

The CSS snippet below employs Houdini's custom properties to craft a circular progress bar. The @property rule introduces --progress with a <percentage> syntax, initialized at 0%, ensuring non-inheritance. Subsequently, the .progress class styles the circular container, utilizing a conic gradient to depict progress dynamically. This concise code harnesses the flexibility of Houdini custom properties for creating visually engaging circular progress elements in web development:

@property --progress {
 syntax: '<percentage>';
 inherits: false;
 initial-value: 0%;
}

.progress {
 --progress: 0%;
 width: 200px;
 height: 200px;
 border-radius: 50%;
 background: conic-gradient(rgb(255, 58, 255) 0%, rgb(255, 58, 255) var(--progress), transparent var(--progress), transparent 100%);
 position: relative;
 overflow: hidden;
}

.progress::before {
 content: attr(data-progress);
 position: absolute;
 top: 50%;
 left: 50%;
 transform: translate(-50%, -50%);
 font-size: 24px;
 font-weight: bolder;
 color: purple;
 text-align: center;
}

Next, we have the custom property definition (@property rule):

@property --progress {
 syntax: '<percentage>';
 inherits: false;
 initial-value: 0%;
}

Some things to note in the code above:

  • The @property rule is part of the Houdini CSS Typed OM specification.
  • It defines a custom CSS property named --progress with the syntax of <percentage>.
  • inherits: false; specifies that the custom property doesn't inherit its value from its parent elements.
  • initial-value: 0%; sets the initial value of the custom property to 0%.

Next, let's style the circular progress bar:

.progress {
 --progress: 0%;
 width: 200px;
 height: 200px;
 border-radius: 50%;
 background: conic-gradient(#ccc 0%, #ccc var(--progress), transparent var(--progress), transparent 100%);
 position: relative;
 overflow: hidden;
}

Some things to note above:

  • --progress: 0%; initializes the custom property to 0%.
  • The .progress class styles the circular progress bar.
  • width and height set the dimensions of the circular container.
  • border-radius: 50%; creates a perfect circle.
  • background uses a conic gradient to create the circular progress effect, with the progress determined by the --progress property.
  • position: relative; and overflow: hidden; are used for positioning and overflow management.

Next, we'll create our paint worklet.

Our circular progress bar springs to life through the dynamic partnership of CSS Houdini and JavaScript. Leveraging CSS Houdini, we define a custom property, --progress, while the paint worklet takes charge of custom painting. This synergy enables real-time updates to our progress bar based on the evolving value of the custom property. This collaboration not only enhances flexibility but also provides a potent avenue for creating unique rendering effects, resulting in an engaging and visually captivating circular progress bar for our web application:

class PaintWorklet {
 paint(ctx, { width, height, progress }) {
 ctx.clearRect(0, 0, width, height);
 ctx.beginPath();
 ctx.arc(width / 2, height / 2, width / 2, 0, (Math.PI * 2 * progress) / 100);
 ctx.fillStyle = '#42f445';
 ctx.fill();
 }
}

Here are some points to not in the code above:

  • class PaintWorklet is a JavaScript class representing a paint worklet, part of the Houdini Paint API.
  • The paint method defines the custom painting logic for the circular progress bar.
  • ctx is the 2D rendering context, and it's used to draw the circular progress.

Next, we register the paint worklet and custom property:

CSS.paintWorklet.addModule('paint-worklet.js');
const progressElements = document.querySelectorAll('.progress');
progressElements.forEach(element => {
 const paintWorklet = new PaintWorklet();
 CSS.registerProperty({
 name: '--progress',
 syntax: '<percentage>',
 inherits: false,
 initialValue: '0%',
 paint: (ctx, geometry, properties) => {
 paintWorklet.paint(ctx, {
 width: geometry.width,
 height: geometry.height,
 progress: parseFloat(properties.get('--progress').toString()),
 });
 },
 });
});

Some points to note in the code above:

  • CSS.paintWorklet.addModule('paint-worklet.js'); loads the paint worklet module.
  • CSS.registerProperty registers the custom property --progress and associates it with the paint worklet.
  • The paint method is called to provide the custom painting logic based on the current value of --progress.

Now let's set the progress over time:

let currentProgress = 0;
function updateProgress() {
 currentProgress += 0.1; // Increment to control the speed of rotation
 if (currentProgress > 100) {
 currentProgress = 0;
 }
 progressElements.forEach(element => {
 element.dataset.progress = currentProgress.toFixed(2);
 element.style.setProperty('--progress', `${currentProgress.toFixed(2)}%`);
 });

 requestAnimationFrame(updateProgress);
}

updateProgress();

Some points to note in the code above:

  • currentProgress is incremented over time to simulate the progress.
  • element.dataset.progress and element.style.setProperty update the DOM and custom property to reflect the progress.
  • requestAnimationFrame ensures smooth animation by requesting the next frame.

Image may be NSFW.
Clik here to view.
circular progress bar

Introducing the Paint API

The Paint API is integral to CSS Houdini, and it revolutionizes web painting by enabling dynamic and customized visual styles. It empowers developers to create on-the-fly designs using user-defined custom properties. Explore its secrets to unleash unparalleled potential.

Simplified foundations

Here are some Paint API features:

  • Paint worklet. A JavaScript function that acts as your artistic genie, conjuring up visuals based on your instructions.
  • Custom properties. Variables you define using CSS's var() syntax, holding values that can be dynamically referenced and manipulated.
  • The paint() function. The magic wand that calls upon your paint worklet to weave its visual enchantment onto elements.

Painting with code: a practical example

To illustrate "painting with code" in action, let's dive into a practical example that showcases the power of the CSS Paint API.

This code snippet below demonstrates how developers can create dynamic and customizable patterns that break free from the constraints of static images, breathing life into web experiences:

<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="styles.css">
<title>Paint API Demo</title>
</head>
<body>
<section id="screen">
</section>

<script>
CSS.paintWorklet.addModule('./app.js');
</script>
</body>
</html>

The post Building a 3D Card Flip Animation with CSS Houdini appeared first on SitePoint.


Viewing latest article 15
Browse Latest Browse All 15

Trending Articles