Archive

Archive for December, 2024

The Law of Diminishing Returns

December 4th, 2024 No comments

Some animation can make things feel natural. Too many animations becomes distracting.

Some line spacing can help legibility. Too much hurts it.

Some alt text is contextual. Too much alt text is noise.

Some padding feels comfy. Too much padding feels exposed.

Some specificity is manageable. Too much specificity is untenable.

Some technical debt is healthy. Too much of it becomes a burden.

Some corner rounding is classy. Too much is just a circle.

Some breakpoints are fluid. Too many of them becomes adaptive.

Some margin adds breathing room. Too much margin collapses things.

Some images add context. Too many images takes a long time to download (and impacts the environment).

Some JavaScript enhances interactions. Too much becomes a bottleneck.

A font pairing creates a typographic system. Too many pairings creates a visual distraction.

Some utility classes come in handy. Too many eliminates a separation of concerns.

Some data helps make decisions. Too much data kills the vibe.

Some AI can help write the boring parts of code. Too much puts downward pressure on code quality.

Some SEO improves search ranking. Too much mutes the human voice.

Some testing provides good coverage. Too much testing requires its own maintenance.

A few colors establish a visual hierarchy. Too many establish a cognitive dissonance.

Some planning helps productivity. Too much planning creates delays.


Striking the right balance can be tough. We don’t want cool mama bear’s porridge or hot papa’s bear porridge, but something right in the middle, like baby bear’s porridge.


The Law of Diminishing Returns originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

Categories: Designing, Others Tags:

Googling Is for Old People: What This Means for Web Designers

December 4th, 2024 No comments

For decades, Google has been the cornerstone of how we navigate the internet. Whether you’re searching for the best pizza in town or troubleshooting a tech issue, Google has been the go-to solution for nearly everyone.

But a recent WallStreet Journal article reveals a troubling trend for the search giant: younger audiences, particularly Gen Z, are skipping Google entirely in favor of platforms like TikTok and Instagram.

For web designers, this shift has profound implications. It challenges how we think about search behavior, content presentation, and user expectations in an evolving digital landscape.

A Generational Shift in Search Behavior

For younger internet users, the way they interact with the digital world is fundamentally different from the habits of older generations.

Instead of typing queries into a search bar, many Gen Z users are turning to platforms where answers are integrated into visual and social content.

TikTok, for instance, has become a surprising hub for finding everything from restaurant recommendations to life hacks, with its algorithm-driven feed offering highly curated and engaging results. Similarly, Instagram’s visually driven content appeals to those seeking inspiration, advice, or entertainment.

This shift in behavior undermines Google’s traditional search model. Younger users expect immediate, personalized results often embedded in a visual and social context, whereas Google’s search experience—dominated by text-heavy links—feels increasingly outdated to this demographic.

Implications for Google’s Core Business

The decline in younger users’ reliance on Google doesn’t just impact search; it threatens the company’s core business model. Google Search drives a significant portion of the company’s revenue through advertising.

If younger audiences continue to migrate to other platforms, advertisers may follow, allocating their budgets to social media channels that better capture this coveted demographic.

This potential erosion of Google’s dominance in search has led the company to introduce new features, such as integrating generative AI into search results to offer more conversational and contextually rich answers. However, whether these adaptations will resonate with younger users remains to be seen.

Regulatory Pressures Add to the Strain

As if the challenge of shifting user behavior weren’t enough, Google is also navigating intense regulatory scrutiny. On November 20, 2024, the U.S. Department of Justice filed antitrust actions against the company, targeting its alleged monopolistic practices.

These lawsuits could result in a significant restructuring of Google’s operations, further complicating its ability to innovate and compete effectively.

The legal battle underscores broader concerns about Big Tech’s outsized influence on markets and consumer choice.

For Google, the stakes are particularly high as its competitors—ranging from Meta to Amazon—are equally eager to claim a larger slice of the digital advertising and AI-driven services markets.

Adapting for the Future

To remain relevant in the face of these challenges, Google will need to embrace more aggressive innovation.

This might involve further integrating AI capabilities, enhancing its mobile experience, or even partnering with emerging platforms to recapture younger audiences. Additionally, Google may need to rethink its approach to advertising, ensuring its solutions remain attractive to brands seeking to engage with Gen Z.

The road ahead for Google is not without precedent. Microsoft faced a similar existential crisis in the early 2000s, when it transitioned from a software-centric company to a cloud powerhouse.

Whether Google can execute a comparable reinvention will determine its ability to stay at the forefront of the tech industry.

What This Means for Web Designers

If Google is becoming “old school,” how should web designers adapt? Here are a few takeaways:

1. Design for Visual Engagement

Web design needs to embrace more visual storytelling. Think beyond stock photos and static banners—users are drawn to short videos, animations, and interactive elements. If your site can mimic the engaging, visual-first approach of TikTok or Instagram, you’re more likely to keep users’ attention.

2. Prioritize Mobile UX

Younger users are almost exclusively mobile-first. A clunky desktop-first design isn’t just inconvenient; it’s irrelevant to how they browse. Ensure your designs are responsive, load quickly, and provide a seamless experience on smaller screens.

3. Rethink Search Interfaces

Search bars remain critical, but their presentation and functionality need an upgrade. Incorporate features like voice search, contextual suggestions, and conversational AI (similar to Google’s new generative AI initiatives). Users should feel like they’re interacting with a helpful guide, not just typing into a void.

4. Optimize for Social Platforms

It’s no longer enough to focus solely on optimizing for Google. Younger users are discovering content through TikTok, Instagram, and even Pinterest.

Designers and content creators need to think about how their work translates to these platforms—whether it’s a catchy video, a swipeable carousel, or a well-designed social ad.

For web designers, this means two things: adapting our designs to fit these platforms and reconsidering how we present information. A static website with dense blocks of text simply won’t cut it anymore.

Instead, we need to focus on creating designs that are fluid, interactive, and optimized for a social-first audience. Whether it’s integrating AI-powered personalization or adopting visual-first layouts, the goal is to stay relevant in an increasingly fragmented digital ecosystem.

Conclusion

The shift in digital habits among younger users highlights the ephemeral nature of tech dominance. What was once indispensable to one generation may become irrelevant to the next.

For Google, this reality represents both a challenge and an opportunity: a chance to evolve and redefine what search means in an age of social media and generative AI.

As regulatory battles loom and new competitors emerge, one thing is clear: the future of search—and Google itself—is being rewritten.

So, is Googling really for old people? Maybe. But if we embrace these changes in user behavior, we can design for the future—and stay ahead of the curve.

Categories: Designing, Others Tags:

FRAKTA Reimagined: A Playful Tribute to IKEA’s Most Versatile Design

December 3rd, 2024 No comments
front view of a stack of ikea frakta blue bags in a shop wit 1640dd1d7b3ea7f8dd77b27e8c695d93.jpg

If you’ve ever owned an IKEA FRAKTA bag (yes, that iconic blue wonder that seems capable of holding your entire life), then you’ll want to check out IKEA’s latest design-inspired pop-up: the ‘Hus of FRAKTA.’

Located on London’s bustling Oxford Street, this pop-up isn’t just a retail space—it’s a celebration of the design innovation and cultural significance behind one of the most recognizable items in IKEA’s catalog.

A Design Icon Reimagined

Let’s talk about the FRAKTA bag. It’s not just a bag—it’s a symbol of IKEA’s democratic design ethos: practical, affordable, and surprisingly stylish.

With its bold blue color, durable polypropylene material, and minimalistic yet functional structure, the FRAKTA bag has been a staple for over 30 years.

It’s the ultimate in “form meets function,” designed to adapt to countless uses, from carrying groceries to serving as a laundry basket or even a plant protector (seriously, people have gotten creative!).

The ‘Hus of FRAKTA’ takes this humble design marvel and elevates it into an experience. Every corner of the pop-up is thoughtfully curated to highlight how a simple design object can inspire creativity and utility in everyday life.

Design Features to Explore at the Pop-Up

1. The Atelier: Customization Meets Craft

At the heart of the pop-up is The Atelier, a personalization station where visitors can transform their FRAKTA bags into unique design pieces.

The beauty of the FRAKTA lies in its simplicity, and this is a perfect blank canvas for creative expression. Think screen prints, patches, and embroidery—elements that allow you to make this everyday object truly your own. It’s design democratization at its finest: a high-end custom experience for just £3 (or free if you’re an IKEA Family member).

a room called atelier with blue carpets and blue walls 7f2ecf42115d5b3604df56043d1dae18.jpg

2. The FRAKTA Walk: Immersive Design Storytelling

Ever wondered what it would feel like to walk inside a FRAKTA bag? The pop-up features an immersive walkway inspired by the bag’s design. It’s playful, bold, and a bit surreal—an ode to the product’s larger-than-life status in the world of functional design.

a front view of a store on a high street says hus of frakta 6eec82a49f8dc4da11c7800e42d23c3f.jpg

3. Curated Collection: A Tribute to IKEA’s Best Designs

The pop-up also showcases a curated collection of IKEA products, with a focus on items that reflect FRAKTA’s bold blue aesthetic.

From the sleek RÄFFELBJÖRK vase to the versatile DOMSTEN stool, this collection highlights IKEA’s ability to balance form, function, and affordability. It’s a reminder that great design doesn’t have to come with a hefty price tag.

Why It Works: The Genius of Simple Design

The success of the FRAKTA bag, and by extension the ‘Hus of FRAKTA’ pop-up, lies in the principles of democratic design.

At IKEA, every product is created with five pillars in mind: form, function, quality, sustainability, and affordability. The FRAKTA embodies all of these, which is why it’s such an enduring classic.

a view of hands holding a phone in a room with mirrors on bo 5caf0b3f30951e47d022792b37000b8d.jpg

By focusing on this bag, the pop-up underscores the idea that even the simplest designs can have a profound impact. It’s a celebration of everyday objects that make life easier and better—and isn’t that what good design is all about?

A Fusion of Fashion and Function

What makes the ‘Hus of FRAKTA’ particularly exciting is how it bridges the gap between fashion and functionality.

The FRAKTA bag has already inspired countless memes, DIY hacks, and even high-fashion knockoffs (remember Balenciaga’s expensive tribute?).

By leaning into this cultural phenomenon, IKEA has created a space that’s as much about lifestyle and creativity as it is about retail.

Final Thoughts

If you’re in London, the ‘Hus of FRAKTA’ is a must-visit for anyone who loves design. It’s playful, inspiring, and a testament to the power of thoughtful design in everyday life.

And if you leave with a personalized FRAKTA bag, even better—it’s not just a shopping tote; it’s a piece of design history.

Categories: Designing, Others Tags:

Creating An Effective Multistep Form For Better User Experience

December 3rd, 2024 No comments

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

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 :

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

Categories: Others Tags:

The Great Filter Comes For Us All

December 2nd, 2024 No comments

With a 13 billion year head start on evolution, why haven’t any other forms of life in the universe contacted us by now?

teaching the aliens how to exit Vim

(Arrival is a fantastic movie. Watch it, but don’t stop there – read the Story of Your Life novella it was based on for so much additional nuance.)

This is called the Fermi paradox:

The Fermi Paradox is a contradiction between high estimates of the probability of the existence of extraterrestrial civilizations, such as in the Drake equation, and lack of any evidence for such civilizations.

– There are billions of stars in the galaxy that are similar to the Sun including many billions of years older than Earth.
– With high probability, some of these stars will have Earth-like planets, and if the Earth is typical, some might develop intelligent life.
– Some of these civilizations might develop interstellar travel, a step the Earth is investigating now.
– Even at the slow pace of currently envisioned interstellar travel, the Milky Way galaxy could be completely traversed in about a million years.

According to this line of thinking, the Earth should have already been visited by extraterrestrial aliens. In an informal conversation, Fermi noted no convincing evidence of this, nor any signs of alien intelligence anywhere in the observable universe, leading him to ask, “Where is everybody?”

To me, this is a compelling argument, in the same way that the lack of evidence of any time travellers is:

Many have argued that the absence of time travelers from the future demonstrates that such technology will never be developed, suggesting that it is impossible. This is analogous to the Fermi paradox related to the absence of evidence of extraterrestrial life. As the absence of extraterrestrial visitors does not categorically prove they do not exist, so the absence of time travelers fails to prove time travel is physically impossible; it might be that time travel is physically possible but is never developed or is cautiously used. Carl Sagan once suggested the possibility that time travelers could be here but are disguising their existence or are not recognized as time travelers.

It seems, to me at least, clear evidence that time travel is not possible, given the enormous amount of time behind us. Something, somewhere, would certainly have invented it by now… right?

So if not, what happened? The Great Filter maybe?

The Great Filter theory says that at some point from pre-life to Type III intelligence, there’s a wall that all or nearly all attempts at life hit. There’s some stage in that long evolutionary process that is extremely unlikely or impossible for life to get beyond. That stage is The Great Filter.

I liked Wait But Why’s take on this a lot, which covers three main filter possibilities:

  1. Life is extraordinarily rare, almost impossible
  1. We are not a rare form of life, but near the first to evolve
  1. Almost no life makes it to this point

Those are three Great Filter possibilities, but the question remains: why are we so alone in the observable universe? I grant you that what we can observe is appallingly tiny given the unimaginable scale of the universe, so “what we can observe” may not be enough by many orders of magnitude.

I encourage you to read the entire article, it’s full of great ideas explained well, including many other Great Filter possibilites. But Mostly I want to share my personal theory of why we haven’t encountered alien life by now. Like computers themselves, things don’t get larger. They get smaller. And faster. And so does intelligent life.

Why build planet-size anything when the real action is in the small things? Small spaces, small units of time, everything gets smaller.

Large is inefficient and unnecessary. Look at the history of computers: from giant to tiny and tinier. From slow to fast and faster. Personally, I have a feeling really advanced life eventually does away with all physical stuff that slows you down as soon as they can, and enters the infinite spaces between:

This is, of course, a variant on the Fermi paradox: We don’t see clues to widespread, large-scale engineering, and consequently we must conclude that we’re alone. But the possibly flawed assumption here is when we say that highly visible construction projects are an inevitable outcome of intelligence. It could be that it’s the engineering of the small, rather than the large, that is inevitable. This follows from the laws of inertia (smaller machines are faster, and require less energy to function) as well as the speed of light (small computers have faster internal communication). It may be – and this is, of course, speculation – that advanced societies are building small technology and have little incentive or need to rearrange the stars in their neighborhoods, for instance. They may prefer to build nanobots instead.

Seth Shostak

Seth delivers an excellent TED talk on this topic as well:

If we can barely see far in the universe as is, there’s no way we could possibly see into the infinite space and time between.

That is of course just my opinion, but we’ll see.. eventually.

Categories: Others, Programming Tags:

Spotify’s Cryptic Tease for 2024 Wrapped Has Everyone Talking

December 2nd, 2024 No comments

It’s that time of year again—Spotify Wrapped season is just around the corner, and this year, the streaming giant has found a new way to keep us guessing.

Instead of the usual hints, Spotify is teasing 2024 Wrapped with mysterious, cryptic logos, and the internet is buzzing with theories.

What’s Spotify Wrapped Again?

If you’ve somehow missed the Wrapped craze, here’s a quick recap: every December, Spotify drops a personalized, colorful snapshot of your music habits from the year. It tells you everything from your most-played songs and artists to the oddest hours you were up listening to your guilty pleasure tracks.

It’s a total vibe—and a major flex when you post your stats on Instagram or TikTok.

Wrapped isn’t just fun; it’s a whole cultural moment. Everyone’s sharing their playlists, tagging friends, and debating their “Top Artist” results. And now, Spotify’s teasing its 2024 edition in the most cryptic way possible.

What’s Up with These Logos?

Instead of a straightforward teaser, Spotify has dropped these wild logo designs that feel like a puzzle waiting to be cracked. They’re bold, colorful, and kind of trippy—think warped shapes, motion-inspired graphics, and colors that pop like your favorite album cover.

So, what’s the deal? Are these logos hinting at new Wrapped features? Maybe we’ll get more dynamic visuals or an entirely new way to interact with our year-end stats. Whatever it is, people are losing it trying to figure it out.

Fans Are ALL In

Naturally, the internet is doing what it does best—overanalyzing everything. Some think Spotify is gearing up to introduce community stats, like regional trends or playlists that show what your city’s been vibing to.

Others are hoping for AI-generated insights (think: “What song defines your 2024 energy?”). And there’s speculation about AR or 3D Wrapped experiences because those logos definitely look futuristic.

On TikTok, users are stitching videos with their predictions, while on Twitter, the theories are flying. And Reddit? Let’s just say the rabbit hole of Wrapped conspiracies runs deep.

Why This Works

Honestly, Spotify knows exactly what it’s doing. These cryptic teasers are brilliant marketing. They’ve turned a yearly recap into an event—and now, the mystery has everyone hyped. Instead of just waiting around for Wrapped, people are talking about it, guessing about it, and hyping it up even more.

This playful, design-forward approach is peak Spotify: it’s creative, engaging, and just cryptic enough to keep us on edge.

So, What Can We Expect?

Let’s be real—we won’t know for sure until Spotify officially drops Wrapped, but the teaser logos definitely suggest some exciting updates. Whether it’s next-level visuals, interactive features, or entirely new ways to relive your year in music, one thing’s for sure: Wrapped 2024 is going to hit differently.

In the meantime, why not revisit your favorite songs and playlists from this year? Who knows—your 3 a.m. summer anthem might just become your top track.

Keep your eyes on Spotify’s socials, and get ready to wrap up 2024 in style!

Categories: Designing, Others Tags:

One of Those “Onboarding” UIs, With Anchor Positioning

December 2nd, 2024 No comments

Welcome to “Anchor Positioning 101” where we will be exploring this interesting new CSS feature. Our textbook for this class will be the extensive “Anchor Positioning Guide” that Juan Diego Rodriguez published here on CSS-Tricks.

I’m excited for this one. Some of you may remember when CSS-Tricks released the “Flexbox Layout Guide” or the “Grid Layout Guide” — I certainly do and still have them both bookmarked! I spend a lot of time flipping between tabs to make sure I have the right syntax in my “experimental” CodePens.

I’ve been experimenting with CSS anchor positioning like the “good old days” since Juan published his guide, so I figured it’d be fun to share some of the excitement, learn a bit, experiment, and of course: build stuff!

CSS Anchor Positioning introduction

Anchor positioning lets us attach — or “anchor” — one element to one or more other elements. More than that, it allows us to define how a “target” element (that’s what we call the element we’re attaching to an anchor element) is positioned next to the anchor-positioned element, including fallback positioning in the form of a new @position-try at-rule.

The most hand-wavy way to explain the benefits of anchor positioning is to think of it as a powerful enhancement to position: absolute; as it helps absolutely-positioned elements do what you expect. Don’t worry, we’ll see how this works as we go.

Anchor positioning is currently a W3C draft spec, so you know it’s fresh. It’s marked as “limited availability” in Baseline which at the time of writing means it is limited to Chromium-based browsers (versions 125+). That said, the considerate folks over at Oddbird have a polyfill available that’ll help out other browsers until they ship support.

This browser support data is from Caniuse, which has more detail. A number indicates that browser supports the feature at that version and up.

Desktop

Chrome Firefox IE Edge Safari
125 No No 125 No

Mobile / Tablet

Android Chrome Android Firefox Android iOS Safari
131 No 131 No

Oddbird contributes polyfills for many new CSS features and you (yes, you!) can support their work on Github or Open Collective!

Tab Atkins-Bittner, contributing author to the W3C draft spec on anchor positioning, spoke on the topic at CSS Day 2024. The full conference talk is available on YouTube:

Here at CSS-Tricks, Juan demonstrated how to mix and match anchor positioning with view-driven animations for an awesome floating notes effect:

Front-end friend Kevin Powell recently released a video demonstrating how “CSS Popover + Anchor Positioning is Magical”.

And finally, in the tradition of “making fun games to learn CSS,” Thomas Park released Anchoreum (a “Flexbox Froggy“-type game) to learn about CSS anchor positioning. Highly recommend checking this out to get the hang of the position-area property!

The homework

OK, now that we’re caught up on what CSS anchor positioning is and the excitement surrounding it, let’s talk about what it does. Tethering an element to another element? That has a lot of potential. Quite a few instances I can remember where I’ve had to fight with absolute positioning and z-index in order to get something positioned just right.

Let’s take a quick look at the basic syntax. First, we need two elements, an anchor-positioned element and the target element that will be tethered to it.

<!-- Anchor element -->
<div id="anchor">
  Anchor
</div>

<!-- Target element -->
<div id="target">
  Target
</div>

We set an element as an anchor-positioned element by providing it with an anchor-name. This is a unique name of our choosing, however it needs the double-dash prefix, like CSS custom properties.

#anchor {
  anchor-name: --anchor;
}

As for our target element, we’ll need to set position: absolute; on it as well as tell the element what anchor to tether to. We do that with a new CSS property, position-anchor using a value that matches the anchor-name of our anchor-positioned element.

#anchor {
  anchor-name: --anchor;
}

#target {
  position: absolute;
  position-anchor: --anchor;
}

May not look like it yet, but now our two elements are attached. We can set the actual positioning on the target element by providing a position-area. To position our target element, position-area creates an invisible 3×3 grid over the anchor-positioned element. Using positioning keywords, we can designate where the target element appears near the anchor-positioned element.

#target {
  position: absolute;
  position-anchor: --anchor;
  position-area: top center;
}

Now we see that our target element is anchored to the top-center of our anchor-positioned element!

CodePen Embed Fallback

Anchoring pseudo-elements

While playing with anchor positioning, I noticed you can anchor pseudo-elements, just the same as any other element.

#anchor {
  anchor-name: --anchor;

  &::before {
    content: "Target";
    position: absolute;
    position-anchor: --anchor;
    left: anchor(center);
    bottom: anchor(center);
  }
}
CodePen Embed Fallback
a semi-transparent red square labelled "Target" is attached to the upper corner of a blue square labelled "Anchor"

Might be useful for adding design flourishes to elements or adding functionality as some sort of indicator.

Moving anchors

Another quick experiment was to see if we can move anchors. And it turns out this is possible!

CodePen Embed Fallback

Notice the use of anchor() functions instead of position-area to position the target element.

#target {
  position: absolute;
  position-anchor: --anchor-one;
  top: anchor(bottom);
  left: anchor(left);
}

CSS anchor functions are an alternate way to position target elements based on the computed values of the anchor-positioned element itself. Here we are setting the target element’s top property value to match the anchor-positioned element’s bottom value. Similarly, we can set the target’s left property value to match the anchor-positioned element’s left value.

Hovering over the container element swaps the position-anchor from --anchor-one to --anchor-two.

.container:hover {
  #target {
    position-anchor: --anchor-two;
  }
}

We are also able to set a transition as we position the target using top and left, which makes it swap smoothly between anchors.

Extra experimental

Along with being the first to release CSS anchor-positioning, the Chrome dev team recently released new pseudo-selectors related to the

and

elements. The ::details-content pseudo-selector allows you to style the “hidden” part of the

element.

With this information, I thought: “can I anchor it?” and sure enough, you can!

CodePen Embed Fallback

Again, this is definitely not ready for prime-time, but it’s always fun to experiment!

Practical examinations

Let’s take this a bit further and tackle more practical challenges using CSS anchor positioning. Please keep in mind that all these examples are Chrome-only at the time of writing!

Tooltips

One of the most straightforward use cases for CSS anchor positioning is possibly a tooltip. Makes a lot of sense: hover over an icon and a label floats nearby to explain what the icon does. I didn’t quite want to make yet another tutorial on how to make a tooltip and luckily for me, Zell Liew recently wrote an article on tooltip best practices, so we can focus purely on anchor positioning and refer to Zell’s work for the semantics.

CodePen Embed Fallback

Now, let’s check out one of these tooltips:

<!-- ... -->;
<li class="toolbar-item">;
  <button type="button" 
    id="inbox-tool" 
    aria-labelledby="inbox-label" 
    class="tool">
    <svg id="inbox-tool-icon">
      <!-- SVG icon code ... -->
    </svg>
  </button>

  <div id="inbox-label" role="tooltip">
    <p>Inbox</p>
  </div>
</li>
<!-- ... -->

The HTML is structured in a way where the tooltip element is a sibling of our anchor-positioned

Categories: Designing, Others Tags:

15 Best New Fonts, November 2024

December 2nd, 2024 No comments
01 formiga

Welcome to our monthly roundup of the best new fonts we’ve found online in the previous four weeks.

November’s edition is particularly strong for script-inspired sans, display faces with motion and energy, and a charming blackletter font. Enjoy!

Formiga

Formiga is a versatile, humanist display typeface designed for attention-grabbing editorials. It has a clear, confident, and fun style, making it perfect for B2C branding projects. There are seven weights (from light to black) with a ton of OpenType features.

Geoscript

GeoScript is a lovely chunky brush script with three weights: Light, Medium, and Bold. It effortlessly combines handwritten and geometric elements making it perfect for a corporate logo with a bit more personality.

Anathera

Anathera is a bold, minimalist typeface with a distinctive pixelation of its diagonal strokes. At large sizes the pixelated details feel disruptive, and at small sizes they create a sense of motion in the text. It’s a great choice for any project that needs to stand out.

03 anathera

Morph

Morph is a versatile display type system built from several different stencil and doubleline styles. It’s a clean modern family with enough variety to create visually interesting word shapes. It’s a great choice for logos, editorial, signage, and poster designs.

04 morph

Brisca Miera

Brisca Miera is a graceful serif, with swashes and alternate characters to add variety and a sense of hand-crafted typography. It’s an excellent option any time you need a font for a sophisticated design.

05 brisca

Dorat

Dorat is an extremely modern blackletter font. The style is vastly under-used — thanks to some unhappy associations — and this font provides the opportunity to lean into a visually strong style while remaining distinctly contemporary.

06 dorat

Mars

Mars is a carefully drawn humanist sans, offering a more interesting corporate face than fonts like Helvetica. It features four different weights: Condensed, Standard, SemiCondensed, and Extended; providing tremendous versatility. It’s a good choice for a company looking for an original voice in its communications.

07 mars

Milling

Milling was designed after research into the shapes that lend themselves to CNC machining. There are three styles: Simplex, Duplex, and Triplex. It’s a practical font for anyone machining lettering, but it’s also an excellent font for conveying industrial production.

08 milling

Wild Lines

Wild Lines is a straight, urban graffiti font that captures the raw energy and edginess of street culture. Its clean, linear style adds structure while preserving graffiti’s rebellious feel. Ideal for projects needing an urban, bold aesthetic, it brings a fresh, city-inspired vibe to designs.

09 wildlines

LiebeHeide Fineliner

LiebeHeide Fineliner is a friendly script font with clean lines and smooth curves. Featuring plenty of ligatures and alternatives, it ensures natural, organic text flow and unique designs. It adds a personal touch to any project.

10 liebeheide

Arkbro

Arkbro is a variable typeface inspired by Ellen Arkbro’s track Mountain of Air, reflecting geometric principles and spatial harmony. Featuring extreme weight contrasts, it’s ideal for playful, animated displays. It’s an excellent choice for designs relating to music.

11 arkbro

Hentak

Hentak is a script font with a flowing, handwritten style and a vintage feel. Featuring dramatic curves and ornamental details, it combines modern and classic calligraphic qualities.

12 hentak

Formale Grotesque

Formale Grotesque is a sans-serif typeface inspired by a 1930s alphabet board, blending geometric and dynamic forms with low stroke contrast. Its alternates shift from grotesque to humanist styles, adding versatility and depth.

13 formalegrotesque

Gonzaga

Gonzaga is a vibrant modern slab serif with contemporary lines and playful rhythms. It has an energy that makes it perfect for logos, posters, and hero text on the web.

14 gonzaga

VFU

VFU (Visionary Font Ultra) is a humble sans with flared strokes that lean in the direction of serifs. It comes with nine weights with matching italics, and a display version.

15 vfu
Categories: Designing, Others Tags:

Blast from the Past: 2Advanced.com

December 1st, 2024 No comments

In the early 2000s, the internet was undergoing a massive transformation. Websites were no longer static, text-heavy pages but were becoming immersive digital experiences.

At the forefront of this revolution stood 2Advanced Studios, a name synonymous with cutting-edge web design and innovation. Their website, 2Advanced.com, became an iconic benchmark in the history of the internet, inspiring countless designers and developers.

2Advanced Studios, have reimagined their iconic 2001 V3 website for 2024. This modern iteration is built entirely using Rive and React JS, showcasing their commitment to blending classic aesthetics with contemporary web technologies.

The updated site maintains the futuristic design elements that originally set 2Advanced apart, now enhanced with responsive layouts and interactive animations. This revival not only pays homage to their influential past but also demonstrates their adaptability and continued innovation in the evolving digital landscape.

For a visual journey through their design evolution, you can explore their official YouTube channel, which features content highlighting their creative milestones, or check their X account for the latest news.

The Rise of 2Advanced Studios

Founded in 1999 by Eric Jordan, 2Advanced Studios carved a niche for itself by creating visually stunning and highly interactive websites. At a time when Flash was the dominant technology for creating dynamic online experiences, 2Advanced leveraged its full potential. Their designs were not just websites; they were art.

The company’s flagship website, 2Advanced.com, was a masterpiece of futuristic aesthetics. With themes that drew heavily from cyberpunk and sci-fi inspirations, the site featured sleek metallic textures, neon-lit interfaces, and fluid animations. The navigation was seamless yet experimental, challenging users to explore its digital landscape.

Design That Defined an Era

The site’s most famous iterations—such as “Expedition,” “Prophecy,” and “V5 Ascension”—demonstrated 2Advanced’s mastery of Flash. Each redesign brought a new visual theme that captured the zeitgeist of the web design community. The vibrant colors, cinematic transitions, and immersive soundscapes were unparalleled.

2Advanced wasn’t just about aesthetics. Their work emphasized usability and storytelling, blending form and function to create experiences that were intuitive despite their visual complexity. For many, visiting 2Advanced.com wasn’t just about browsing—it was an event.

Impact on the Web Design Community

2Advanced.com became a beacon of inspiration for web designers and developers worldwide. It showcased what was possible with emerging web technologies and pushed the boundaries of creativity. Forums and design communities buzzed with admiration and analysis of its every iteration. Tutorials and blogs dissected the techniques behind its magic, attempting to emulate its style.

The studio’s influence extended beyond its own website. Clients ranged from Fortune 500 companies to major entertainment brands, all seeking 2Advanced’s ability to merge futuristic visuals with cutting-edge interactivity.

The Downfall of Flash and 2Advanced’s Legacy

As the web evolved, so did its technologies. The rise of mobile devices and the growing importance of responsive design marked the decline of Flash. By the late 2000s, HTML5, CSS3, and JavaScript had become the new standards for creating dynamic web content. These changes rendered Flash-based designs obsolete, and 2Advanced Studios eventually shuttered its operations in the early 2010s.

Yet, the legacy of 2Advanced.com lives on. It remains a cultural touchstone in the history of web design, a reminder of a time when creativity reigned supreme. Its influence can still be seen in modern designs that prioritize user engagement and visual storytelling.

Why It Still Matters

In today’s world of minimalist and utilitarian design, revisiting 2Advanced.com feels like stepping into a time capsule. It reminds us of the boundless enthusiasm and optimism of the early internet era—a time when designers dared to dream big and technology felt like magic.

For those who lived through the golden age of Flash, 2Advanced.com was more than just a website; it was a movement. And for those discovering it for the first time, it stands as a testament to what’s possible when creativity and technology collide.

The spirit of 2Advanced endures, inspiring new generations of designers to push boundaries and create experiences that captivate and inspire.

Categories: Designing, Others Tags: