An Introduction To CSS Scroll-Driven Animations: Scroll And View Progress Timelines

Original Source: https://smashingmagazine.com/2024/12/introduction-css-scroll-driven-animations/

You can safely use scroll-driven animations in Chrome as of December 2024. Firefox supports them, too, though you’ll need to enable a flag. Safari? Not yet, but don’t worry — you can still offer a seamless experience across all browsers with a polyfill. Just keep in mind that adding a polyfill involves a JavaScript library, so you won’t get the same performance boost.

There are plenty of valuable resources to dive into scroll-driven animations, which I’ll be linking throughout the article. My starting point was Bramus’ video tutorial, which pairs nicely with Geoff’s in-depth notes Graham that build on the tutorial.

In this article, we’ll walk through the latest published version by the W3C and explore the two types of scroll-driven timelines — scroll progress timelines and view progress timelines. By the end, I hope that you are familiar with both timelines, not only being able to tell them apart but also feeling confident enough to use them in your work.

Note: All demos in this article only work in Chrome 116 or later at the time of writing.

Scroll Progress Timelines

The scroll progress timeline links an animation’s timeline to the scroll position of a scroll container along a specific axis. So, the animation is tied directly to scrolling. As you scroll forward, so does the animation. You’ll see me refer to them as scroll-timeline animations in addition to calling them scroll progress timelines.

Just as we have two types of scroll-driven animations, we have two types of scroll-timeline animations: anonymous timelines and named timelines.

Anonymous scroll-timeline

Let’s start with a classic example: creating a scroll progress bar at the top of a blog post to track your reading progress.

See the Pen Scroll Progress Timeline example – before animation-timeline scroll() [forked] by Mariana Beldi.

In this example, there’s a <div> with the ID “progress.” At the end of the CSS file, you’ll see it has a background color, a defined width and height, and it’s fixed at the top of the page. There’s also an animation that scales it from 0 to 1 along the x-axis — pretty standard if you’re familiar with CSS animations!

Here’s the relevant part of the styles:

#progress {
/* … */
animation: progressBar 1s linear;
}

@keyframes progressBar {
from { transform: scaleX(0); }
}

The progressBar animation runs once and lasts one second with a linear timing function. Linking this animation scrolling is just a single line in CSS:

animation-timeline: scroll();

No need to specify seconds for the duration — the scrolling behavior itself will dictate the timing. And that’s it! You’ve just created your first scroll-driven animation! Notice how the animation’s direction is directly tied to the scrolling direction — scroll down, and the progress indicator grows wider; scroll up, and it becomes narrower.

See the Pen Scroll Progress Timeline example – animation-timeline scroll() [forked] by Mariana Beldi.

scroll-timeline Property Parameters

In a scroll-timeline animation, the scroll() function is used inside the animation-timeline property. It only takes two parameters: <scroller> and <axis>.

<scroller> refers to the scroll container, which can be set as nearest (the default), root, or self.
<axis> refers to the scroll axis, which can be block (the default), inline, x, or y.

In the reading progress example above, we didn’t declare any of these because we used the defaults. But we could achieve the same result with:

animation-timeline: scroll(nearest block);

Here, the nearest scroll container is the root scroll of the HTML element. So, we could also write it this way instead:

animation-timeline: scroll(root block);

The block axis confirms that the scroll moves top to bottom in a left-to-right writing mode. If the page has a wide horizontal scroll, and we want to animate along that axis, we could use the inline or x values (depending on whether we want the scrolling direction to always be left-to-right or adapt based on the writing mode).

We’ll dive into self and inline in more examples later, but the best way to learn is to play around with all the combinations, and this tool by Bramus lets you do exactly that. Spend a few minutes before we jump into the next property associated with scroll timelines.

The animation-range Property

The animation-range for scroll-timeline defines which part of the scrollable content controls the start and end of an animation’s progress based on the scroll position. It allows you to decide when the animation starts or ends while scrolling through the container.

By default, the animation-range is set to normal, which is shorthand for the following:

animation-range-start: normal;
animation-range-end: normal;

This translates to 0% (start) and 100% (end) in a scroll-timeline animation:

animation-range: normal normal;

…which is the same as:

animation-range: 0% 100%;

You can declare any CSS length units or even calculations. For example, let’s say I have a footer that’s 500px tall. It’s filled with banners, ads, and related posts. I don’t want the scroll progress bar to include any of that as part of the reading progress. What I want is for the animation to start at the top and end 500px before the bottom. Here we go:

animation-range: 0% calc(100% – 500px);

See the Pen Scroll Progress Timeline example – animation-timeline, animation-range [forked] by Mariana Beldi.

Just like that, we’ve covered the key properties of scroll-timeline animations. Ready to take it a step further?

Named scroll-timeline

Let’s say I want to use the scroll position of a different scroll container for the same animation. The scroll-timeline-name property allows you to specify which scroll container the scroll animation should be linked to. You give it a name (a dashed-ident, e.g., –my-scroll-timeline) that maps to the scroll container you want to use. This container will then control the animation’s progress as the user scrolls through it.

Next, we need to define the scroll axis for this new container by using the scroll-timeline-axis, which tells the animation which axis will trigger the motion. Here’s how it looks in the code:

.my-class {
/* This is my new scroll-container */
scroll-timeline-name: –my-custom-name;
scroll-timeline-axis: inline;
}

If you omit the axis, then the default block value will be used. However, you can also use the shorthand scroll-timeline property to combine both the name and axis in a single declaration:

.my-class {
/* Shorthand for scroll-container with axis */
scroll-timeline: –my-custom-name inline;
}

I think it’s easier to understand all this with a practical example. Here’s the same progress indicator we’ve been working with, but with inline scrolling (i.e., along the x-axis):

See the Pen Named Scroll Progress Timeline [forked] by Mariana Beldi.

We have two animations running:

A progress bar grows wider when scrolling in an inline direction.
The container’s background color changes the further you scroll.

The HTML structure looks like the following:

<div class=”gallery”>
<div class=”gallery-scroll-container”>
<div class=”gallery-progress” role=”progressbar” aria-label=”progress”></div>
<img src=”image1.svg” alt=”Alt text” draggable=”false” width=”500″>
<img src=”image2.svg” alt=”Alt text” draggable=”false” width=”500″>
<img src=”image3.svg” alt=”Alt text” draggable=”false” width=”500″>
</div>
</div>

In this case, the gallery-scroll-container has horizontal scrolling and changes its background color as you scroll. Normally, we could just use animation-timeline: scroll(self inline) to achieve this. However, we also want the gallery-progress element to use the same scroll for its animation.

The gallery-progress element is the first inside gallery-scroll-container, and we will lose it when scrolling unless it’s absolutely positioned. But when we do this, the element no longer occupies space in the normal document flow, and that affects how the element behaves with its parent and siblings. We need to specify which scroll container we want it to listen to.

That’s where naming the scroll container comes in handy. By giving gallery-scroll-container a scroll-timeline-name and scroll-timeline-axis, we can ensure both animations sync to the same scroll:

.gallery-scroll-container {
/* … */
animation: bg steps(1);
scroll-timeline: –scroller inline;
}

And is using that scrolling to define its own animation-timeline:

.gallery-scroll-container {
/* … */
animation: bg steps(1);
scroll-timeline: –scroller inline;
animation-timeline: –scroller;
}

Now we can scale this name to the progress bar that is using a different animation but listening to the same scroll:

.gallery-progress {
/* … */
animation: progressBar linear;
animation-timeline: –scroller;
}

This allows both animations (the growing progress bar and changing background color) to follow the same scroll behavior, even though they are separate elements and animations.

The timeline-scope Property

What happens if we want to animate something based on the scroll position of a sibling or even a higher ancestor? This is where the timeline-scope property comes into play. It allows us to extend the scope of a scroll-timeline beyond the current element’s subtree. The value of timeline-scope must be a custom identifier, which again is a dashed-ident.

Let’s illustrate this with a new example. This time, scrolling in one container runs an animation inside another container:

See the Pen Scroll Driven Animations – timeline-scope [forked] by Mariana Beldi.

We can play the animation on the image when scrolling the text container because they are siblings in the HTML structure:

<div class=”main-container”>
<div class=”sardinas-container”>
<img …>
</div>

<div class=”scroll-container”>
<p>Long text…</p>
</div>
</div>

Here, only the .scroll-container has scrollable content, so let’s start by naming this:

.scroll-container {
/* … */
overflow-y: scroll;
scroll-timeline: –containerText;
}

Notice that I haven’t specified the scroll axis, as it defaults to block (vertical scrolling), and that’s the value I want.

Let’s move on to the image inside the sardinas-container. We want this image to animate as we scroll through the scroll-container. I’ve added a scroll-timeline-name to its animation-timeline property:

.sardinas-container img {
/* … */
animation: moveUp steps(6) both;
animation-timeline: –containerText;
}

At this point, however, the animation still won’t work because the scroll-container is not directly related to the images. To make this work, we need to extend the scroll-timeline-name so it becomes reachable. This is done by adding the timeline-scope to the parent element (or a higher ancestor) shared by both elements:

.main-container {
/* … */
timeline-scope: –containerText;
}

With this setup, the scroll of the scroll-container will now control the animation of the image inside the sardinas-container!

Now that we’ve covered how to use timeline-scope, we’re ready to move on to the next type of scroll-driven animations, where the same properties will apply but with slight differences in how they behave.

View Progress Timelines

We just looked at scroll progress animations. That’s the first type of scroll-driven animation of the two. Next, we’re turning our attention to view progress animations. There’s a lot of similarities between the two! But they’re different enough to warrant their own section for us to explore how they work. You’ll see me refer to these as view-timeline animations in addition to calling them view progress animations, as they revolve around a view() function.

The view progress timeline is the second type of type of scroll-driven animation that we’re looking at. It tracks an element as it enters or exits the scrollport (the visible area of the scrollable content). This behavior is quite similar to how an IntersectionObserver works in JavaScript but can be done entirely in CSS.

We have anonymous and named view progress timelines, just as we have anonymous and named scroll progress animations. Let’s unpack those.

Anonymous View Timeline

Here’s a simple example to help us see the basic idea of anonymous view timelines. Notice how the image fades into view when you scroll down to a certain point on the page:

See the Pen View Timeline Animation – view() [forked] by Mariana Beldi.

Let’s say we want to animate an image that fades in as it appears in the scrollport. The image’s opacity will go from 0 to 1. This is how you might write that same animation in classic CSS using @keyframes:

img {
/* … */
animation: fadeIn 1s;
}

@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}

That’s great, but we want the image to fadeIn when it’s in view. Otherwise, the animation is sort of like a tree that falls in a forest with no one there to witness it… did the animation ever happen? We’ll never know!

We have a view() function that makes this a view progress animation with a single line of CSS:

img {
/* … */
animation: fadeIn;
animation-timeline: view();
}

And notice how we no longer need to declare an animation-duration like we did in classic CSS. The animation is no longer tied by time but by space. The animation is triggered as the image becomes visible in the scrollport.

View Timeline Parameters

Just like the scroll-timeline property, the view-timeline property accepts parameters that allow for more customization:

animation-timeline: view( );

<inset>
Controls when the animation starts and ends relative to the element’s visibility within the scrollport. It defines the margin between the edges of the scrollport and the element being tracked. The default value is auto, but it can also take length percentages as well as start and end values.
<axis>
This is similar to the scroll-timeline’s axis parameter. It defines which axis (horizontal or vertical) the animation is tied to. The default is block, which means it tracks the vertical movement. You can also use inline to track horizontal movement or simple x or y.

Here’s an example that uses both inset and axis to customize when and how the animation starts:

img {
animation-timeline: view(20% block);
}

In this case:

The animation starts when the image is 20% visible in the scrollport.
The animation is triggered by vertical scrolling (block axis).

Parallax Effect

With the view() function, it’s also easy to create parallax effects by simply adjusting the animation properties. For example, you can have an element move or scale as it enters the scrollport without any JavaScript:

img {
animation: parallaxMove 1s;
animation-timeline: view();
}

@keyframes parallaxMove {
to { transform: translateY(-50px); }
}

This makes it incredibly simple to create dynamic and engaging scroll animations with just a few lines of CSS.

See the Pen Parallax effect with CSS Scroll driven animations – view() [forked] by Mariana Beldi.

The animation-range Property

Using the CSS animation-range property with view timelines defines how much of an element’s visibility within the scrollport controls the start and end points of the animation’s progress. This can be used to fine-tune when the animation begins and ends based on the element’s visibility in the viewport.

While the default value is normal, in view timelines, it translates to tracking the full visibility of the element from the moment it starts entering the scrollport until it fully leaves. This is represented by the following:

animation-range: normal normal;
/* Equivalent to */
animation-range: cover 0% cover 100%;

Or, more simply:

animation-range: cover;

There are six possible values or timeline-range-names:

cover
Tracks the full visibility of the element, from when it starts entering the scrollport to when it completely leaves it.
contain
Tracks when the element is fully visible inside the scrollport, from the moment it’s fully contained until it no longer is.
entry
Tracks the element from the point it starts entering the scrollport until it’s fully inside.
exit
Tracks the element from the point it starts, leaving the scrollport until it’s fully outside.
entry-crossing
Tracks the element as it crosses the starting edge of the scrollport, from start to full crossing.
exit-crossing
Tracks the element as it crosses the end edge of the scrollport, from start to full crossing.

You can mix different timeline-range-names to control the start and end points of the animation range. For example, you could make the animation start when the element enters the scrollport and end when it exits:

animation-range: entry exit;

You can also combine these values with percentages to define more custom behavior, such as starting the animation halfway through the element’s entry and ending it halfway through its exit:

animation-range: entry 50% exit 50%;

Exploring all these values and combinations is best done interactively. Tools like Bramus’ view-timeline range visualizer make it easier to understand.

Target Range Inside @keyframes

One of the powerful features of timeline-range-names is their ability to be used inside @keyframes:

See the Pen target range inside @keyframes – view-timeline, timeline-range-name [forked] by Mariana Beldi.

Two different animations are happening in that demo:

slideIn
When the element enters the scrollport, it scales up and becomes visible.
slideOut
When the element leaves, it scales down and fades out.

@keyframes slideIn {
from {
transform: scale(.8) translateY(100px);
opacity: 0;
}
to {
transform: scale(1) translateY(0);
opacity: 1;
}
}

@keyframes slideOut {
from {
transform: scale(1) translateY(0);
opacity: 1;
}
to {
transform: scale(.8) translateY(-100px);
opacity: 0
}
}

The new thing is that now we can merge these two animations using the entry and exit timeline-range-names, simplifying it into one animation that handles both cases:

@keyframes slideInOut {
/* Animation for when the element enters the scrollport */
entry 0% {
transform: scale(.8) translateY(100px);
opacity: 0;
}
entry 100% {
transform: scale(1) translateY(0);
opacity: 1;
}
/* Animation for when the element exits the scrollport */
exit 0% {
transform: scale(1) translateY(0);
opacity: 1;
}
exit 100% {
transform: scale(.8) translateY(-100px);
opacity: 0;
}
}

entry 0%
Defines the state of the element at the beginning of its entry into the scrollport (scaled down and transparent).
entry 100%
Defines the state when the element has fully entered the scrollport (fully visible and scaled up).
exit 0%
Starts tracking the element as it begins to leave the scrollport (visible and scaled up).
exit 100%
Defines the state when the element has fully left the scrollport (scaled down and transparent).

This approach allows us to animate the element’s behavior smoothly as it both enters and leaves the scrollport, all within a single @keyframes block.

Named view-timeline And timeline-scope

The concept of using view-timeline with named timelines and linking them across different elements can truly expand the possibilities for scroll-driven animations. In this case, we are linking the scroll-driven animation of images with the animations of unrelated paragraphs in the DOM structure by using a named view-timeline and timeline-scope.

The view-timeline property works similarly to the scroll-timeline property. It’s the shorthand for declaring the view-timeline-name and view-timeline-axis properties in one line. However, the difference from scroll-timeline is that we can link the animation of an element when the linked elements enter the scrollport. I took the previous demo and added an animation to the paragraphs so you can see how the opacity of the text is animated when scrolling the images on the left:

See the Pen View-timeline, timeline-scope [forked] by Mariana Beldi.

This one looks a bit verbose, but I found it hard to come up with a better example to show the power of it. Each image in the vertical scroll container is assigned a named view-timeline with a unique identifier:

.vertical-scroll-container img:nth-of-type(1) { view-timeline: –one; }
.vertical-scroll-container img:nth-of-type(2) { view-timeline: –two; }
.vertical-scroll-container img:nth-of-type(3) { view-timeline: –three; }
.vertical-scroll-container img:nth-of-type(4) { view-timeline: –four; }

This makes the scroll timeline of each image have its own custom name, such as –one for the first image, –two for the second, and so on.

Next, we connect the animations of the paragraphs to the named timelines of the images. The corresponding paragraph should animate when the images enter the scrollport:

.vertical-text p:nth-of-type(1) { animation-timeline: –one; }
.vertical-text p:nth-of-type(2) { animation-timeline: –two; }
.vertical-text p:nth-of-type(3) { animation-timeline: –three; }
.vertical-text p:nth-of-type(4) { animation-timeline: –four; }

However, since the images and paragraphs are not directly related in the DOM, we need to declare a timeline-scope on their common ancestor. This ensures that the named timelines (–one, –two, and so on) can be referenced and shared between the elements:

.porto {
/* … */
timeline-scope: –one, –two, –three, –four;
}

By declaring the timeline-scope with all the named timelines (–one, —two, –three, –four), both the images and the paragraphs can participate in the same scroll-timeline logic, despite being in separate parts of the DOM tree.

Final Notes

We’ve covered the vast majority of what’s currently defined in the CSS Scroll-Driven Animations Module Leve 1 specification today in December 2024. But I want to highlight a few key takeaways that helped me better understand these new rules that you may not get directly from the spec:

Scroll container essentials
It may seem obvious, but a scroll container is necessary for scroll-driven animations to work. Issues often arise when elements like text or containers are resized or when animations are tested on larger screens, causing the scrollable area to disappear.
Impact of position: absolute
Using absolute positioning can sometimes interfere with the intended behavior of scroll-driven animations. The relationship between elements and their parent elements gets tricky when position: absolute is applied.
Tracking an element’s initial state
The browser evaluates the element’s state before any transformations (like translate) are applied. This affects when animations, particularly view timelines, begin. Your animation might trigger earlier or later than expected due to the initial state.
Avoid hiding overflow
Using overflow: hidden can disrupt the scroll-seeking mechanism in scroll-driven animations. The recommended solution is to switch to overflow: clip. Bramus has a great article about this and a video from Kevin Powell also suggests that we may no longer need overflow: hidden.
Performance
For the best results, stick to animating GPU-friendly properties like transforms, opacity, and some filters. These skip the heavy lifting of recalculating layout and repainting. On the other hand, animating things like width, height, or box-shadow can slow things down since they require re-rendering. Bramus mentioned that soon, more properties — like background-color, clip-path, width, and height — will be animatable on the compositor, making the performance even better.
Use will-change wisely
Leverage this property to promote elements to the GPU, but use it sparingly. Overusing will-change can lead to excessive memory usage since the browser reserves resources even if the animations don’t frequently change.
The order matters
If you are using the animation shorthand, always place the animation-timeline after it.
Progressive enhancement and accessibility
Combine media queries for reduced motion preferences with the @supports rule to ensure animations only apply when the user has no motion restrictions, and the browser supports them.

For example:

@media screen and (prefers-reduce-motion: no-preference) {
@supports ((animation-timeline: scroll()) and (animation-range: 0% 100%)) {
.my-class {
animation: moveCard linear both;
animation-timeline: view();
}
}
}

My main struggle while trying to build the demos was more about CSS itself than the scroll animations. Sometimes, building the layout and generating the scroll was more difficult than applying the scroll animation. Also, some things that confused me at the beginning as the spec keeps evolving, and some of these are not there anymore (remember, it has been under development for more than five years now!):

x and y axes
These used to be called the “horizontal” and “vertical” axes, and while Firefox may still support the old terminology, it has been updated.
Old @scroll-timeline syntax
In the past, @scroll-timeline was used to declare scroll timelines, but this has changed in the most recent version of the spec.
Scroll-driven vs. scroll-linked animations
Scroll-driven animations were originally called scroll-linked animations. If you come across this older term in articles, double-check whether the content has been updated to reflect the latest spec, particularly with features like timeline-scope.

Resources

All demos from this article can be found in this collection, and I might include more as I experiment further.
A collection of demos from CodePen that I find interesting (send me yours, and I’ll include it!)
This GitHub repo is where you can report issues or join discussions about scroll-driven animations.
Demos, tools, videos, and (even) more information from Bramus
Google Chrome video tutorial

I've never been more tempted to buy a Cricut Explore Air 2 – now only £199

Original Source: https://www.creativebloq.com/creative-inspiration/digital-crafting/ive-never-been-more-tempted-to-buy-a-cricut-explore-air-2-now-only-gbp199

This counts as a necessary wedding expense, right?

10 Tools to Remove Image Background Online – Best of

Original Source: https://www.hongkiat.com/blog/remove-image-background-online/

Are you still manually removing image backgrounds using Photoshop or other photo editing tools? Well, you shouldn’t be, at least not anymore. In this blog post, we have compiled a list of the 10 best online tools to Remove backgrounds effortlessly.

These image background-removing tools, with the assistance of AI, are designed to make your life easier, save you time, and help you achieve professional-looking results.

Whether you are a graphic designer, a social media manager, or just someone looking to enhance your images, these online tools will undoubtedly come in handy. Let’s check them out.

Our Testing Process

We put every image background removal tool on our list through a thorough test. For our tests, we used two different kinds of images:

Image 1: a simple one (an ice cream cone against a plain background) and,
Image 2: a more complex one (a girl wearing a red dress with a detailed background).

Image 1

Image 1

Image 1

Image 2

Click on “Image 1” or “Image 2” in the “See results for:” section at the bottom of each tool’s description.

HitPaw Online Background Remover
HitPaw Online Background Remover

HitPaw Online Background Remover allows users to edit images after removing the background. It offers various functionalities, such as adding different color backgrounds, using pre-designed background templates, or even incorporating photos into the design. Users can also resize the image to meet their needs, ensuring a perfect end result.

A key feature of this tool is the ability to preview the image outcome after the background removal. This allows users to make any necessary adjustments before finalizing their design. However, it is important to note that downloading the edited image requires a paid plan.

Price:

The paid plan offers competitive pricing, starting at just $2.57 per day. Subscribing to the paid plan unlocks additional benefits, such as watermark removal, batch processing for multiple images, and unlimited access to high-definition exports.

See results for:
Image 1
Image 2

Remove background with HitPaw

Freepik Background Remover
Freepik Background Remover

Freepik’s Background Remover is a simple and effective tool for removing image backgrounds. It uses AI technology to detect and remove backgrounds instantly, making it easy to integrate subjects into new designs. The tool supports various image formats and is part of Freepik’s online editor. It also provides access to other AI tools, such as a text-to-image generator, allowing you to create new backgrounds for your images. This makes it flexible for redesigning or repurposing visuals.

Using the Background Remover is straightforward. Upload your image by dragging and dropping it or selecting it from your device. Click the “Remove bg” button, and the AI will automatically remove the background in seconds. You can refine the edges or adjust the results with the brush tool. Once done, you can download the edited image or replace the background with an AI-generated option, Freepik’s visuals, or your own picture.

Price:

Price: Free with limitations. Unlimited access starts at $12/month via the premium plan.

See results for:
Image 1
Image 2

Remove background with Freepik

Fotor’s Bg Remover
Fotor's Bg Remover

With “Bg Remover,” you can remove the background from an image and replace it with a different color or a new photo to enhance its appearance. This feature allows you to create visually appealing and customized images tailored to your specific needs.

To ensure the background removal process is successful and meets your expectations, a convenient “compare” button is provided. This feature allows you to quickly view a side-by-side comparison of the original image and the edited version with the background removed.

One of the great features of this tool is its ability to handle multiple image uploads simultaneously. This batch upload functionality saves time and effort by allowing you to process several images at once, streamlining your workflow and increasing efficiency.

If you wish to download a preview version of the edited image, you can do so without signing in. This preview version will be available in a 500×500 resolution. However, if you require a high-definition version of the image in 2000×2000 resolution, signing in is necessary.

Price:

Signing up for an account is completely free, allowing you to access high-quality edited images at no additional cost.

See results for:
Image 1
Image 2

Remove background with Fotor

Zyro’s AI Background Remover
Zyro's AI Background Remover

The simplicity of Zyro’s AI Background Remover is one of its most appealing features, as it does not include any complicated functions or additional features. It is designed to provide users with a hassle-free experience when removing the background from an image.

All you need to do is drag and drop the image into the designated area, and the tool will handle the rest. Once the background has been successfully removed, you can easily download the final result by clicking the “Download Image” button. The entire process is straightforward and user-friendly.

Price:

Zyro’s AI Background Remover is free.

See results for:
Image 1
Image 2

Remove background with Zyro

Background Remover by Icons8
Icons8' Background Remover

The Icons8 background remover features a user-friendly interface, allowing you to effortlessly remove backgrounds from images with a single click. It supports the bulk upload of up to 500 images simultaneously, accommodating formats like JPG, PNG, and WebP. Simply upload your photo to the background remover, and let the AI do the rest. This tool can be used without creating an account, offering free background removal for up to three images.

Price:

For more extensive needs, consider upgrading to one of three paid plans. The Prepaid package is priced at $0.20 per image. The Limited subscription plan, at $9, allows for up to 100 images per month. Alternatively, the Unlimited subscription, at $99, offers unlimited image background removals.

See results for:
Image 1
Image 2

Remove background with Icons8

VanceAI Background Remover
VanceAI Background Remover

VanceAI’s Background Remover is an easy-to-use tool. To start, drag your chosen image onto the page and click the “Start to process” button. Shortly after, the processed image with the background removed will appear on the right side of the screen.

Price:

With a free account, users receive 3 credits to try out the tool. Downloading a processed image costs 2 credits. To learn more about how credits work, visit this page.

See results for:
Image 1
Image 2

Remove background with VanceAI

AVC.AI
AVC.AI

To remove an image background with Avc.AI, first, sign up for a free account. The free account provides you with 12 credits, and each background removal costs 1 credit. Once your account is set up, upload the image you want to edit, choose the “RemoveBG” option, and click the “Start Processing” button.

In addition to background removal, this tool offers features such as noise removal, image upscaling, and colorization. You can select any or all of these options before clicking the “Start Processing” button to customize your image processing experience.

After processing, download the high-quality image by clicking the “Download in high quality” button. Note that processed photos will remain in your account for 72 hours before being deleted from the server.

Price:

Starts at $9.95/month for 100 credits.

See results for:
Image 1
Image 2

Remove background with AVC.AI

Claid.AI
Claid.AI

To use Claid.AI’s image background removal tool, you must first sign up for an account. Upon successful registration, you will receive 50 credits to explore the tool’s features and capabilities.

One of the main advantages of this tool is its AI-powered technology, which allows for seamless background removal and additional customization options. After removing the background, you can easily resize the image, add a solid background color, or choose from a variety of pre-designed templates.

Furthermore, the AI component lets users enter descriptions or prompts, which the system uses to generate a custom background tailored to their specific needs. Once you have made your selections, simply click “Generate” to obtain the finished result.

Price:

Plans starts at $19/month.

See results for:
Image 1
Image 2

Remove background with Claid.AI

Cutout.pro
Cutout.pro

To remove the background using Cutout.pro, simply drag and drop an image or paste the URL of any online image. The tool will efficiently process the image, displaying the original and resulting images side by side for easy comparison.

One unique feature of this tool is the ability to add a custom background color to the processed image, allowing users to personalize their images according to their preferences.

Downloading the processed image is free and does not require signing up for an account. However, the free version of the image is limited to a size of 500×500 pixels.

For users who require a high-definition version of the processed image, a 2000×2000 resolution is available. To access this feature, you must sign up for an account and use one credit.

Price

A free account includes five free credits to get started. For more information on the credit system and its pricing, click here.

See results for:
Image 1
Image 2

Remove background with Cutout.pro

DeepImage
DeepImage

To use DeepImage for background removal, you must first sign up for an account. Once registered, you can easily upload images by either dragging and dropping them or importing them from Google Drive. The tool offers various image editing features, including background removal, upscaling, enhancing facial details, sharpening, and noise reduction.

Please note that processed images with removed backgrounds will have a watermark. To remove this watermark, you need to subscribe to one of the available paid plans.

Price:

DeepImages comes with free trial. Paid plans starts at $7.50/month for 100 credits.

See results for:
Image 1
Image 2

Remove background with DeepImage

Erase.bg
Erase.bg

Erase.bg can process images up to 5000×500 pixels. To use it, simply drag and drop a single image. Once the processing is complete, you’ll be directed to a results page showing a comparison of the original image and the version with the background removed.

A magnifier tool is provided to help you examine the results more closely. If you’re satisfied with the outcome, click on “Download Original Size” to obtain the processed image.

Price:

Erase.bg is free to use, and there’s no need to sign up for an account.

See results for:
Image 1
Image 2

Remove background with Erase.bg

Removal.ai
Removal.ai

With Remove.ai, once the image is uploaded, you will see a side-by-side comparison in two tabs, displaying the before and after results. This helps you easily visualize the enhancements made to your image.

You can download a free preview image with dimensions of 800×800 pixels without signing up for an account. However, if you want a high-quality image measuring 2000×2000 pixels, you need to create an account.

By signing up for a free account, you can download one high-resolution image for free.

Price:

Paid plans start at $5.99/month for 40 images.

See results for:
Image 1
Image 2

Remove background with Removal.ai

The post 10 Tools to Remove Image Background Online – Best of appeared first on Hongkiat.

Mastering SVG Arcs

Original Source: https://smashingmagazine.com/2024/12/mastering-svg-arcs/

So, I love drawing birds with code. Inspired by my brother’s love for birdwatching, I admire the uniqueness of their feathers, colors, and sounds. But what I notice most is the way their bodies curve and different birds can have dramatically different curves! So, I took my love for drawing with SVG graphics and used it to experiment with bird shapes. Over time, I’ve drawn enough to become incredibly adept at working with arc shapes.

Here are a few of my recent works. Inspired by designs I came across on Dribbble, I created my versions with code. You can browse through the code for each on my CodePen.

But before we dive into creating curves with arcs, please pause here and check out Myriam Frisano’s recent article, “SVG Coding Examples: Useful Recipes For Writing Vectors By Hand.” It’s an excellent primer to the SVG syntax and it will give you solid context heading into the concepts we’re covering here when it comes to mastering SVG arcs.

A Quick SVG Refresher

You probably know that SVGs are crisp, infinitely scalable illustrations without pixelated degradation — vectors for the win! What you might not know is that few developers write SVG code. Why? Well, the syntax looks complicated and unfamiliar compared to, say, HTML. But trust me, once you break it down, it’s not only possible to hand-code SVG but also quite a bit of fun.

Let’s make sure you’re up to speed on the SVG viewBox because it’s a key concept when it comes to the scalable part of *SVG. We’ll use the analogy of a camera, lens, and canvas to explain this concept. Think of your browser window as a camera and the SVG viewBox as the camera lens focusing on the painting of a bird you’ve created (the SVG). Imagine the painting on a large canvas that may stretch far beyond what the camera captures. The viewBox defines which part of this canvas is visible through the camera.

Let’s say we have an SVG element that we’re sizing at 600px square with width and height attributes directly on the <svg> element.

<svg width=”600px” height=”600px”>

Let’s turn our attention to the viewBox attribute:

<svg width=”600px” height=”600px” viewBox=”-300 -300 600 600″>

The viewBox attribute defines the internal coordinate system for the SVG, with four values mapping to the SVG’s x, y, width, and height in that order.

Here’s how this relates to our analogy:

Camera Position and Size
The -300, -300 represents the camera lens’ left and top edge position. Meanwhile, 600 x 600 is like the camera’s frame size, showing a specific portion of that space.
Unchanging Canvas Size
Changing the x and y values adjusts where the camera points, and width and height govern how much of the canvas it frames. It doesn’t resize the actual canvas (the SVG element itself, which remains at 600×600 pixels). No matter where the camera is positioned or zoomed, the canvas itself remains fixed.

So, when you adjust the viewBox coordinates, you’re simply choosing a new area of the canvas to focus on without resizing the canvas itself. This lets you control the visible area without changing the SVG’s actual display dimensions.

You now have the context you need to learn how to work with <path> elements in SVG, which is where we start working with arcs!

The <path> Element

We have an <svg> element. And we’re viewing the element’s contents through the “lens” of a viewBox.

A <path> allows us to draw shapes. We have other elements for drawing shapes — namely <circle>, <line>, and <polygon> — but imagine being restricted to strict geometrical shapes as an artist. That’s where the custom <path> element comes in. It’s used to draw complex shapes that cannot be created with the basic ones. Think of <path> as a flexible container that lets you mix and match different drawing commands.

With a single <path>, you can combine multiple drawing commands into one smooth, elegant design. Today, we’re focusing on a super specific path command: arcs. In other words, what we’re doing is drawing arc shapes with <path>.

Here’s a quick, no-frills example that places a <path> inside the <svg> example we looked at earlier:

<svg width=”600px” height=”600px” viewBox=”-300 -300 600 600″>
<path d=”M 0 0 A 100 100 0 1 1 200 0″
fill=”transparent”
stroke=”black”
stroke-width=”24″
/>
</svg>

Let’s take this information and start playing with values to see how it behaves.

Visualizing The Possibilities

Again, if this is the <path> we’re starting with:

<path d=”M 0 0 A 100 100 0 1 1 200 0″/>

Then, we can manipulate it in myriad ways. Mathematically speaking, you can create an infinite number of arcs between any two points by adjusting the parameters. Here are a few variations of an arc that we get when all we do is change the arc’s endpoints in the X (<ex>) and Y (<ey>) directions.

See the Pen Arc Possibilities b/w 2 points [forked] by akshaygpt.

Or, let’s control the arc’s width and height by updating its radius in the X direction (<rx>) and the Y direction (<ry>). If we play around with the <rx> value, we can manipulate the arc’s height:

See the Pen Rx [forked] by akshaygpt.

Similarly, we can manipulate the arc’s width by updating the <ry> value:

See the Pen Rx [forked] by akshaygpt.

Let’s see what happens when we rotate the arc along its X-axis (<rotation>). This parameter rotates the arc’s ellipse around its center. It won’t affect circles, but it’s a game-changer for ellipses.

See the Pen x-axis-rotation [forked] by akshaygpt.

Even with a fixed set of endpoints and radii (<rx> and <ry>), and a given angle of rotation, four distinct arcs can connect them. That’s because we have the <arc> flag value that can be one of two values, as well as the <sweep> flag that is also one of two values. Two boolean values, each with two arguments, give us four distinct possibilities.

See the Pen 4 cases [forked] by akshaygpt.

And lastly, adjusting the arc’s endpoint along the X (<ex>) and Y (<ey>) directions shifts the arc’s location without changing the overall shape.

See the Pen endx, endy [forked] by akshaygpt.

Wrapping Up

And there you have it, SVG arcs demystified! Whether you’re manipulating radii, rotation, or arc direction, you now have all the tools to master these beautiful curves. With practice, arcs will become just another part of your SVG toolkit, one that gives you the power to create more dynamic, intricate designs with confidence.

So keep playing, keep experimenting, and soon you’ll be bending arcs like a pro — making your SVGs not just functional but beautifully artistic. If you enjoyed this dive into arcs, drop a like or share it with your friends. Let’s keep pushing the boundaries of what SVG can do!

Accessibility Best Practices for Single Page Applications (SPAs)

Original Source: https://www.sitepoint.com/accessibility-best-practices-for-single-page-applications/?utm_source=rss

Discover essential accessibility best practices for Single Page Applications (SPAs) to ensure dynamic content, focus management, and navigation are user-friendly for everyone.

Continue reading
Accessibility Best Practices for Single Page Applications (SPAs)
on SitePoint.

Creating the Morphing Effect of the Luma Dream Machine Website

Original Source: https://tympanus.net/codrops/2024/12/09/creating-the-morphing-effect-of-the-luma-dream-machine-website/

Learn how to create this powerful morphing effect with only JavaScript using the Canvas2D API.

15 Free Tools to Create Professional Resumes

Original Source: https://www.hongkiat.com/blog/simple-free-resume-tools/

Why does everyone need a different resume? Because no single version works for all jobs. Each opportunity demands a unique approach. But what do most people do? They grab a basic template, tweak it a bit, and end up with a dull, one-size-fits-all resume. That doesn’t cut it – especially when you’re trying to stand out in a competitive job market.

If you want a resume that highlights your skills and fits perfectly with a specific job or industry, you’re in luck. There are some excellent free tools available that can help. These tools offer templates, guidance, and customization options to create a professional resume without the hassle. Let’s explore 15 of the best free tools to help you build a resume that’s ready to impress.

30 Free Beautiful Resume Templates to Download

.no-js #ref-block-post-23761 .ref-block__thumbnail { background-image: url(“https://assets.hongkiat.com/uploads/thumbs/250×160/editable-resume-template.jpg”); }

30 Free Beautiful Resume Templates to Download

You probably have seen the professional-looking, eye-catching resumes that talented web designers have been designing and showcasing online…. Read more

Freepik Resume Builder
Freepik Resume Builder

For those who want to wow potential employers with an eye-catching and memorable resume, Freepik’s Resume Builder and its vast selection of professionally designed resume templates is the tool for you. Every aspect of the design is customizable thanks to its unique template editor, allowing users to replace images and alter text easily.

Users can also take advantage of its integrated AI writer, an automated writing tool that can polish and refine text to a high standard. Once happy, you can download the document as a PDF, the standard for most CVs, or as an image, selecting JPEG or PNG.

Visit Freepik Resume Builder

CV Wizard
CV Maker

CV Wizard (formerly known as CV Maker) is a multilingual tool for building a professional resume. What impressed me is, you can choose from a wide range of pre-designed templates per your profession. You do not need to format or arrange the layouts manually – all is already done for you.

Also, you can arrange the sections per your requirement. Another interesting feature is you can host your resume on this site and share its link with anyone. Also, you can export the resume in PDF, HTML, or TXT format. Last but not the least, this platform comes with a simple interface that helps beginners to create an awesome resume seamlessly.

Visit CV Wizard

ResumeGiants
ResumeGiants

ResumeGiants is a resume building tool you can use to make things easier during a job search. It offers a step-by-step guide to design and build an amazing looking resume that gets the results.

The platform offers hundreds of professional resume templates to choose from. And if you think that your chosen template could use some extra sections, or a complete redesign, you can easily make these changes – all without having to start from scratch.

ResumeGiants is a free service and works with filtering software like applicant tracking systems (ATS) to give you the extra support necessary to get the best jobs available.

Visit ResumeGiants

ResumeCoach
ResumeCoach

ResumeCoach features everything that you need from a professional resume maker. On the basis of an array of templates, you can create a stunning resume tailored to your requirements in a few simple steps.

At each step of the resume creation process, ResumeCoach guides you with tips and examples that help you make your document interesting and ideal for the particular industry that you’re applying for.

Moreover, the resume templates available on the site are categorized into student resume, entry-level resume, or professional resume so you can pick the one for your particular needs. There are also resumes from different professional fields like graphic designer, nurse, teacher, or customer service professional, etc.

Visit ResumeCoach

VisualCV
VisualCV

Visual CV lets you choose a handsome yet professional design and build a dynamic web portfolio or a professional resume out of it. The tool, unlike CV Maker, lets you create custom versions of your resume having similar or different formats. That means you can create multiple resumes for different job opportunities and present your best in them.

Moreover, you can create different versions of your resume where a new version is better than the old one. This feature helps in comparing and improving your resume. As a result, the resulting resume looks distinguished and well-polished. When you are done, you can export it to a PDF.

Visit VisualCV

Resume.com
Resume.com

Resume.com is a free resume builder that lets you create, edit, and build a perfect resume, thanks to its user-friendly resume builder. This tool allows you to fetch your details from Facebook and LinkedIn so you can fill your resume quick and easy.

Resume.com can build a job-specific resume with its wide range of brilliant templates. Amazingly, the resume can also be shared with others, like CV Maker. Last but not the least, you can create multiple versions of your resume for applying for different openings.

Visit Resume.com

Resume Builder
Resume Builder

Resume Builder lets you create powerful resumes with step by step instructions. What surprised me is that this tool provides pre-written job-specific sample phrases and punchlines that are created by experts to help people nail jobs. I also like its dozens of resume template designs, which helps building awesome resumes.

You can create, download, and print the resume, and use formatting tools to customize it to showcase your creativity. Resume Builder can be started free of cost like others above, and it also helps to share and promote your resume through social networks.

Visit Resume Builder

DoYouBuzz
DoYouBuzz

DoYouBuzz allows building resumes in web and mobile formats. As with others, you do not need to worry about the layout because its resume template does this job for you. You can choose the content you would like to add in the form fields, and your resume will be built.

You can get feedback from others before finalizing the resume. Your resume is shareable so that you can promote it on social networks. Also, you can opt to show your resume on Google, just like any public site or page appears on it. Last but not the least, the resume can even be downloaded and printed out easily.

Visit DoYouBuzz

Resumonk
Resumonk

Resumonk is a premium resume builder that can generate the resume in PDF and DOCX formats. You can choose from a large range of resume templates, fill in your information, and build your resume easily and quickly. The tool lets you create unlimited resumes, but with its free edition, you can avail just a limited number of templates.

What differentiates this tool from the others is, it offers ‘Photo CV’ templates that allow adding your professional pic to the resume. Interestingly, you can even import details from LinkedIn, like Resume.com, and share your resume with others by sharing its URL. You can also create a cover letter for each resume, but this is limited to its premium pack.

Visit Resumonk

ResumeGenius
ResumeGenius

ResumeGenius is one of the fastest resume builders that can create a professional resume without requiring any writing skills. It helps create your resume with its ‘point, click, and create’ method that simplifies creating resumes. Also, the templates provided by ResumeGenius are software-friendly and help you to not get unrecognized by such tools.

You can choose from over 20+ professional templates and 50k+ phrases for different form fields. That means you can create an impressive resume even if you don’t have a good command on English language. You can also download your resume in PDF, DOCX, and TXT formats and can create an unlimited number of resumes, however with the premium subscription.

Visit ResumeGenius

Kickresume
Kickresume

KickResume offers a wide range of resume and cover letter templates that you can customize your resume with custom colors, icons, and layouts, resulting in a customized resume. Moreover, you can create a personal resume website with its premium subscription.

Contrary to some above-mentioned tools, KickResume’s free version allows limited entries and categories and just the basic resume templates. Moreover, though you can download your resume yet it does not offer any social sharing features like few others. However, its templates support tracking system, so you can be sure you are not missed out.

Visit Kickresume

Novorèsumè
Novoresume

Unlike the other tools, Novorèsumè focuses more on the content than the design to helps you improve the resume. It contains a content optimizer that analyzes your resume content and suggests possible revisions to make it even better. Moreover, you can optimize and customize the resume layout and preview it in live mode.

You can create your resume in multiple languages, as you can do with CV Maker. The free version of the tool allows you to build a one-page resume with predefined layouts. However, unlike few above tools, it does not provide pre-written phrases. After you are done creating your resume, you can download it as PDF, or share it with others.

Visit Novorèsumè

Resume Companion
Resume Companion

Resume Companion provides approved, professional resume as well as cover letter templates with thousands of content options. The tool offers about 5k+ pre-written content phrases, which you can insert with just one click.

You will find many resume sections, and you can arrange them per your requirement. Also, the tool automatically formats the resume for you, after which, the final resume can be exported to a Word or a PDF document. However, it lacks resume hosting and social sharing features that are offered by few of the above tools.

Visit Resume Companion

HipCV
HipCV

HipCV offers professional CV designs and layouts, and also professionally-written phrases and sentences for creating awesome first impressions. The tool is completely free to use, and there’s no limit on the number of resumes, unlike some others.

You can download the CV in PDF format or email it to apply directly. You can also get a link to your resume hosted on its site, and share the same on social media platforms. And what more interestingly is that HipCV tracks the number of visits on your CV, so you always know the traffic arriving to check out your resume – same as Google Analytics work.

Visit HipCV

The post 15 Free Tools to Create Professional Resumes appeared first on Hongkiat.

Case Study: Isabel Moranta Portfolio — 2024

Original Source: https://tympanus.net/codrops/2024/12/05/case-study-isabel-moranta-portfolio-2024/

This case study captures the journey of crafting a personal portfolio—an exploration of bold design, creative freedom, and the beauty of designing for oneself.

Creating An Effective Multistep Form For Better User Experience

Original Source: https://smashingmagazine.com/2024/12/creating-effective-multistep-form-better-user-experience/

For a multistep form, planning involves structuring questions logically across steps, grouping similar questions, and minimizing the number of steps and the amount of required information for each step. Whatever makes each step focused and manageable is what should be aimed for.

In this tutorial, we will create a multistep form for a job application. Here are the details we are going to be requesting from the applicant at each step:

Personal Information
Collects applicant’s name, email, and phone number.
Work Experience
Collects the applicant’s most recent company, job title, and years of experience.
Skills & Qualifications
The applicant lists their skills and selects their highest degree.
Review & Submit
This step is not going to collect any information. Instead, it provides an opportunity for the applicant to go back and review the information entered in the previous steps of the form before submitting it.

You can think of structuring these questions as a digital way of getting to know somebody. You can’t meet someone for the first time and ask them about their work experience without first asking for their name.

Based on the steps we have above, this is what the body of our HTML with our form should look like. First, the main <form> element:

<form id=”jobApplicationForm”>
<!– Step 1: Personal Information –>
<!– Step 2: Work Experience –>
<!– Step 3: Skills & Qualifications –>
<!– Step 4: Review & Submit –>
</form>

Step 1 is for filling in personal information, like the applicant’s name, email address, and phone number:

<form id=”jobApplicationForm”>
<!– Step 1: Personal Information –>
<fieldset class=”step” id=”step-1″>
<legend id=”step1Label”>Step 1: Personal Information</legend>
<label for=”name”>Full Name</label>
<input type=”text” id=”name” name=”name” required />
<label for=”email”>Email Address</label>
<input type=”email” id=”email” name=”email” required />
<label for=”phone”>Phone Number</label>
<input type=”tel” id=”phone” name=”phone” required />
</fieldset>

<!– Step 2: Work Experience –>
<!– Step 3: Skills & Qualifications –>
<!– Step 4: Review & Submit –>
</form>

Once the applicant completes the first step, we’ll navigate them to Step 2, focusing on their work experience so that we can collect information like their most recent company, job title, and years of experience. We’ll tack on a new <fieldset> with those inputs:

<form id=”jobApplicationForm”>
<!– Step 1: Personal Information –>

<!– Step 2: Work Experience –>
<fieldset class=”step” id=”step-2″ hidden>
<legend id=”step2Label”>Step 2: Work Experience</legend>
<label for=”company”>Most Recent Company</label>
<input type=”text” id=”company” name=”company” required />
<label for=”jobTitle”>Job Title</label>
<input type=”text” id=”jobTitle” name=”jobTitle” required />
<label for=”yearsExperience”>Years of Experience</label>
<input
type=”number”
id=”yearsExperience”
name=”yearsExperience”
min=”0″
required
/>
</fieldset>

<!– Step 3: Skills & Qualifications –>
<!– Step 4: Review & Submit –>
</form>

Step 3 is all about the applicant listing their skills and qualifications for the job they’re applying for:

<form id=”jobApplicationForm”>
<!– Step 1: Personal Information –>
<!– Step 2: Work Experience –>

<!– Step 3: Skills & Qualifications –>
<fieldset class=”step” id=”step-3″ hidden>
<legend id=”step3Label”>Step 3: Skills & Qualifications</legend>
<label for=”skills”>Skill(s)</label>
<textarea id=”skills” name=”skills” rows=”4″ required></textarea>
<label for=”highestDegree”>Degree Obtained (Highest)</label>
<select id=”highestDegree” name=”highestDegree” required>
<option value=””>Select Degree</option>
<option value=”highschool”>High School Diploma</option>
<option value=”bachelor”>Bachelor’s Degree</option>
<option value=”master”>Master’s Degree</option>
<option value=”phd”>Ph.D.</option>
</select>
</fieldset>
<!– Step 4: Review & Submit –>
<fieldset class=”step” id=”step-4″ hidden>
<legend id=”step4Label”>Step 4: Review & Submit</legend>
<p>Review your information before submitting the application.</p>
<button type=”submit”>Submit Application</button>
</fieldset>
</form>

And, finally, we’ll allow the applicant to review their information before submitting it:

<form id=”jobApplicationForm”>
<!– Step 1: Personal Information –>
<!– Step 2: Work Experience –>
<!– Step 3: Skills & Qualifications –>

<!– Step 4: Review & Submit –>
<fieldset class=”step” id=”step-4″ hidden>
<legend id=”step4Label”>Step 4: Review & Submit</legend>
<p>Review your information before submitting the application.</p>
<button type=”submit”>Submit Application</button>
</fieldset>
</form>

Notice: We’ve added a hidden attribute to every fieldset element but the first one. This ensures that the user sees only the first step. Once they are done with the first step, they can proceed to fill out their work experience on the second step by clicking a navigational button. We’ll add this button later on.

Adding Styles

To keep things focused, we’re not going to be emphasizing the styles in this tutorial. What we’ll do to keep things simple is leverage the Simple.css style framework to get the form in good shape for the rest of the tutorial.

If you’re following along, we can include Simple’s styles in the document <head>:

<link rel=”stylesheet” href=”https://cdn.simplecss.org/simple.min.css” />

And from there, go ahead and create a style.css file with the following styles that I’ve folded up.

<details>
<summary>View CSS</summary>
body {
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
}
main {
padding: 0 30px;
}
h1 {
font-size: 1.8rem;
text-align: center;
}
.stepper {
display: flex;
justify-content: flex-end;
padding-right: 10px;
}
form {
box-shadow: 0px 0px 6px 2px rgba(0, 0, 0, 0.2);
padding: 12px;
}
input,
textarea,
select {
outline: none;
}
input:valid,
textarea:valid,
select:valid,
input:focus:valid,
textarea:focus:valid,
select:focus:valid {
border-color: green;
}
input:focus:invalid,
textarea:focus:invalid,
select:focus:invalid {
border: 1px solid red;
}
</details>

Form Navigation And Validation

An easy way to ruin the user experience for a multi-step form is to wait until the user gets to the last step in the form before letting them know of any error they made along the way. Each step of the form should be validated for errors before moving on to the next step, and descriptive error messages should be displayed to enable users to understand what is wrong and how to fix it.

Now, the only part of our form that is visible is the first step. To complete the form, users need to be able to navigate to the other steps. We are going to use several buttons to pull this off. The first step is going to have a Next button. The second and third steps are going to have both a Previous and a Next button, and the fourth step is going to have a Previous and a Submit button.

<form id=”jobApplicationForm”>
<!– Step 1: Personal Information –>
<fieldset>
<!– … –>
<button type=”button” class=”next” onclick=”nextStep()”>Next</button>
</fieldset>

<!– Step 2: Work Experience –>
<fieldset>
<!– … –>
<button type=”button” class=”previous” onclick=”previousStep()”>Previous</button>
<button type=”button” class=”next” onclick=”nextStep()”>Next</button>
</fieldset>

<!– Step 3: Skills & Qualifications –>
<fieldset>
<!– … –>
<button type=”button” class=”previous” onclick=”previousStep()”>Previous</button>
<button type=”button” class=”next” onclick=”nextStep()”>Next</button>
</fieldset>

<!– Step 4: Review & Submit –>
<fieldset>
<!– … –>
<button type=”button” class=”previous” onclick=”previousStep()”>Previous</button>
<button type=”submit”>Submit Application</button>
</fieldset>
</form>

Notice: We’ve added onclick attributes to the Previous and Next buttons to link them to their respective JavaScript functions: previousStep() and nextStep().

The “Next” Button

The nextStep() function is linked to the Next button. Whenever the user clicks the Next button, the nextStep() function will first check to ensure that all the fields for whatever step the user is on have been filled out correctly before moving on to the next step. If the fields haven’t been filled correctly, it displays some error messages, letting the user know that they’ve done something wrong and informing them what to do to make the errors go away.

Before we go into the implementation of the nextStep function, there are certain variables we need to define because they will be needed in the function. First, we need the input fields from the DOM so we can run checks on them to make sure they are valid.

// Step 1 fields
const name = document.getElementById(“name”);
const email = document.getElementById(“email”);
const phone = document.getElementById(“phone”);

// Step 2 fields
const company = document.getElementById(“company”);
const jobTitle = document.getElementById(“jobTitle”);
const yearsExperience = document.getElementById(“yearsExperience”);

// Step 3 fields
const skills = document.getElementById(“skills”);
const highestDegree = document.getElementById(“highestDegree”);

Then, we’re going to need an array to store our error messages.

let errorMsgs = [];

Also, we would need an element in the DOM where we can insert those error messages after they’ve been generated. This element should be placed in the HTML just below the last fieldset closing tag:

<div id=”errorMessages” style=”color: rgb(253, 67, 67)”></div>

Add the above div to the JavaScript code using the following line:

const errorMessagesDiv = document.getElementById(“errorMessages”);

And finally, we need a variable to keep track of the current step.

let currentStep = 1;

Now that we have all our variables in place, here’s the implementation of the nextstep() function:

function nextStep() {
errorMsgs = [];
errorMessagesDiv.innerText = “”;

switch (currentStep) {
case 1:
addValidationErrors(name, email, phone);
validateStep(errorMsgs);
break;

case 2:
addValidationErrors(company, jobTitle, yearsExperience);
validateStep(errorMsgs);
break;

case 3:
addValidationErrors(skills, highestDegree);
validateStep(errorMsgs);
break;
}
}

The moment the Next button is pressed, our code first checks which step the user is currently on, and based on this information, it validates the data for that specific step by calling the addValidationErrors() function. If there are errors, we display them. Then, the form calls the validateStep() function to verify that there are no errors before moving on to the next step. If there are errors, it prevents the user from going on to the next step.

Whenever the nextStep() function runs, the error messages are cleared first to avoid appending errors from a different step to existing errors or re-adding existing error messages when the addValidationErrors function runs. The addValidationErrors function is called for each step using the fields for that step as arguments.

Here’s how the addValidationErrors function is implemented:

function addValidationErrors(fieldOne, fieldTwo, fieldThree = undefined) {
if (!fieldOne.checkValidity()) {
const label = document.querySelector(label[for=”${fieldOne.id}”]);
errorMsgs.push(Please Enter A Valid ${label.textContent});
}

if (!fieldTwo.checkValidity()) {
const label = document.querySelector(label[for=”${fieldTwo.id}”]);
errorMsgs.push(Please Enter A Valid ${label.textContent});
}

if (fieldThree && !fieldThree.checkValidity()) {
const label = document.querySelector(label[for=”${fieldThree.id}”]);
errorMsgs.push(Please Enter A Valid ${label.textContent});
}

if (errorMsgs.length > 0) {
errorMessagesDiv.innerText = errorMsgs.join(“n”);
}
}

This is how the validateStep() function is defined:

function validateStep(errorMsgs) {
if (errorMsgs.length === 0) {
showStep(currentStep + 1);
}
}

The validateStep() function checks for errors. If there are none, it proceeds to the next step with the help of the showStep() function.

function showStep(step) {
steps.forEach((el, index) => {
el.hidden = index + 1 !== step;
});
currentStep = step;
}

The showStep() function requires the four fieldsets in the DOM. Add the following line to the top of the JavaScript code to make the fieldsets available:

const steps = document.querySelectorAll(“.step”);

What the showStep() function does is to go through all the fieldsets in our form and hide whatever fieldset is not equal to the one we’re navigating to. Then, it updates the currentStep variable to be equal to the step we’re navigating to.

The “Previous” Button

The previousStep() function is linked to the Previous button. Whenever the previous button is clicked, similarly to the nextStep function, the error messages are also cleared from the page, and navigation is also handled by the showStep function.

function previousStep() {
errorMessagesDiv.innerText = “”;
showStep(currentStep – 1);
}

Whenever the showStep() function is called with “currentStep – 1” as an argument (as in this case), we go back to the previous step, while moving to the next step happens by calling the showStep() function with “currentStep + 1″ as an argument (as in the case of the validateStep() function).

Improving User Experience With Visual Cues

One other way of improving the user experience for a multi-step form, is by integrating visual cues, things that will give users feedback on the process they are on. These things can include a progress indicator or a stepper to help the user know the exact step they are on.

Integrating A Stepper

To integrate a stepper into our form (sort of like this one from Material Design), the first thing we need to do is add it to the HTML just below the opening <form> tag.

<form id=”jobApplicationForm”>
<div class=”stepper”>
<span><span class=”currentStep”>1</span>/4</span>
</div>
<!– … –>
</form>

Next, we need to query the part of the stepper that will represent the current step. This is the span tag with the class name of currentStep.

const currentStepDiv = document.querySelector(“.currentStep”);

Now, we need to update the stepper value whenever the previous or next buttons are clicked. To do this, we need to update the showStep() function by appending the following line to it:

currentStepDiv.innerText = currentStep;

This line is added to the showStep() function because the showStep() function is responsible for navigating between steps and updating the currentStep variable. So, whenever the currentStep variable is updated, the currentStepDiv should also be updated to reflect that change.

Storing And Retrieving User Data

One major way we can improve the form’s user experience is by storing user data in the browser. Multistep forms are usually long and require users to enter a lot of information about themselves. Imagine a user filling out 95% of a form, then accidentally hitting the F5 button on their keyboard and losing all their progress. That would be a really bad experience for the user.

Using localStorage, we can store user information as soon as it is entered and retrieve it as soon as the DOM content is loaded, so users can always continue filling out their forms from wherever they left off. To add this feature to our forms, we can begin by saving the user’s information as soon as it is typed. This can be achieved using the input event.

Before adding the input event listener, get the form element from the DOM:

const form = document.getElementById(“jobApplicationForm”);

Now we can add the input event listener:

// Save data on each input event
form.addEventListener(“input”, () => {
const formData = {
name: document.getElementById(“name”).value,
email: document.getElementById(“email”).value,
phone: document.getElementById(“phone”).value,
company: document.getElementById(“company”).value,
jobTitle: document.getElementById(“jobTitle”).value,
yearsExperience: document.getElementById(“yearsExperience”).value,
skills: document.getElementById(“skills”).value,
highestDegree: document.getElementById(“highestDegree”).value,
};
localStorage.setItem(“formData”, JSON.stringify(formData));
});

Next, we need to add some code to help us retrieve the user data once the DOM content is loaded.

window.addEventListener(“DOMContentLoaded”, () => {
const savedData = JSON.parse(localStorage.getItem(“formData”));
if (savedData) {
document.getElementById(“name”).value = savedData.name || “”;
document.getElementById(“email”).value = savedData.email || “”;
document.getElementById(“phone”).value = savedData.phone || “”;
document.getElementById(“company”).value = savedData.company || “”;
document.getElementById(“jobTitle”).value = savedData.jobTitle || “”;
document.getElementById(“yearsExperience”).value = savedData.yearsExperience || “”;
document.getElementById(“skills”).value = savedData.skills || “”;
document.getElementById(“highestDegree”).value = savedData.highestDegree || “”;
}
});

Lastly, it is good practice to remove data from localStorage as soon as it is no longer needed:

// Clear data on form submit
form.addEventListener(‘submit’, () => {
// Clear localStorage once the form is submitted
localStorage.removeItem(‘formData’);
});

Adding The Current Step Value To localStorage

If the user accidentally closes their browser, they should be able to return to wherever they left off. This means that the current step value also has to be saved in localStorage.

To save this value, append the following line to the showStep() function:

localStorage.setItem(“storedStep”, currentStep);

Now we can retrieve the current step value and return users to wherever they left off whenever the DOM content loads. Add the following code to the DOMContentLoaded handler to do so:

const storedStep = localStorage.getItem(“storedStep”);

if (storedStep) {
const storedStepInt = parseInt(storedStep);
steps.forEach((el, index) => {
el.hidden = index + 1 !== storedStepInt;
});
currentStep = storedStepInt;
currentStepDiv.innerText = currentStep;
}

Also, do not forget to clear the current step value from localStorage when the form is submitted.

localStorage.removeItem(“storedStep”);

The above line should be added to the submit handler.

Wrapping Up

Creating multi-step forms can help improve user experience for complex data entry. By carefully planning out steps, implementing form validation at each step, and temporarily storing user data in the browser, you make it easier for users to complete long forms.

For the full implementation of this multi-step form, you can access the complete code on GitHub.