Sticky Headers And Full-Height Elements: A Tricky Combination

Category Image 080

I was recently asked by a student to help with a seemingly simple problem. She’d been working on a website for a coffee shop that sports a sticky header, and she wanted the hero section right underneath that header to span the rest of the available vertical space in the viewport.

Here’s a visual demo of the desired effect for clarity.

Looks like it should be easy enough, right? I was sure (read: overconfident) that the problem would only take a couple of minutes to solve, only to find it was a much deeper well than I’d assumed.

Before we dive in, let’s take a quick look at the initial markup and CSS to see what we’re working with:

<body>
<header class=”header”>Header Content</header>
<section class=”hero”>Hero Content</section>
<main class=”main”>Main Content</main>
</body>

.header {
position: sticky;
top: 0; /* Offset, otherwise it won’t stick! */
}

/* etc. */

With those declarations, the .header will stick to the top of the page. And yet the .hero element below it remains intrinsically sized. This is what we want to change.

The Low-Hanging Fruit

The first impulse you might have, as I did, is to enclose the header and hero in some sort of parent container and give that container 100vh to make it span the viewport. After that, we could use Flexbox to distribute the children and make the hero grow to fill the remaining space.

<body>
<div class=”container”>
<header class=”header”>Header Content</header>
<section class=”hero”>Hero Content</section>
</div>
<main class=”main”>Main Content</main>
</body>

.container {
height: 100vh;
display: flex;
flex-direction: column;
}

.hero {
flex-grow: 1;
}

/* etc. */

This looks correct at first glance, but watch what happens when scrolling past the hero.

See the Pen Attempt #1: Container + Flexbox [forked] by Philip.

The sticky header gets trapped in its parent container! But.. why?

If you’re anything like me, this behavior is unintuitive, at least initially. You may have heard that sticky is a combination of relative and fixed positioning, meaning it participates in the normal flow of the document but only until it hits the edges of its scrolling container, at which point it becomes fixed. While viewing sticky as a combination of other values can be a useful mnemonic, it fails to capture one important difference between sticky and fixed elements:

A position: fixed element doesn’t care about the parent it’s nested in or any of its ancestors. It will break out of the normal flow of the document and place itself directly offset from the viewport, as though glued in place a certain distance from the edge of the screen.

Conversely, a position: sticky element will be pushed along with the edges of the viewport (or next closest scrolling container), but it will never escape the boundaries of its direct parent. Well, at least if you don’t count visually transform-ing it. So a better way to think about it might be, to steal from Chris Coyier, that “position: sticky is, in a sense, a locally scoped position: fixed.” This is an intentional design decision, one that allows for section-specific sticky headers like the ones made famous by alphabetical lists in mobile interfaces.

See the Pen Sticky Section Headers [forked] by Philip.

Okay, so this approach is a no-go for our predicament. We need to find a solution that doesn’t involve a container around the header.

Fixed, But Not Solved

Maybe we can make our lives a bit simpler. Instead of a container, what if we gave the .header element a fixed height of, say, 150px? Then, all we have to do is define the .hero element’s height as height: calc(100vh – 150px).

See the Pen Attempt #2: Fixed Height + Calc() [forked] by Philip.

This approach kinda works, but the downsides are more insidious than our last attempt because they may not be immediately apparent. You probably noticed that the header is too tall, and we’d wanna do some math to decide on a better height.

Thinking ahead a bit,

What if the .header’s children need to wrap or rearrange themselves at different screen sizes or grow to maintain legibility on mobile?
What if JavaScript is manipulating the contents?

All of these things could subtly change the .header’s ideal size, and chasing the right height values for each scenario has the potential to spiral into a maintenance nightmare of unmanageable breakpoints and magic numbers — especially if we consider this needs to be done not only for the .header but also the .hero element that depends on it.

I would argue that this workaround also just feels wrong. Fixed heights break one of the main affordances of CSS layout — the way elements automatically grow and shrink to adapt to their contents — and not relying on this usually makes our lives harder, not simpler.

So, we’re left with…

A Novel Approach

Now that we’ve figured out the constraints we’re working with, another way to phrase the problem is that we want the .header and .hero to collectively span 100vh without sizing the elements explicitly or wrapping them in a container. Ideally, we’d find something that already is 100vh and align them to that. This is where it dawned on me that display: grid may provide just what we need!

Let’s try this: We declare display: grid on the body element and add another element before the .header that we’ll call .above-the-fold-spacer. This new element gets a height of 100vh and spans the grid’s entire width. Next, we’ll tell our spacer that it should take up two grid rows and we’ll anchor it to the top of the page.

This element must be entirely empty because we don’t ever want it to be visible or to register to screen readers. We’re merely using it as a crutch to tell the grid how to behave.

<body>
<!– This spacer provides the height we want –>
<div class=”above-the-fold-spacer”></div>

<!– These two elements will place themselves on top of the spacer –>
<header class=”header”>Header Content</header>
<section class=”hero”>Hero Content</section>

<!– The rest of the page stays unaffected –>
<main class=”main”>Main Content</main>
</body>

body {
display: grid;
}

.above-the-fold-spacer {
height: 100vh;
/* Span from the first to the last grid column line */
/* (Negative numbers count from the end of the grid) */
grid-column: 1 / -1;
/* Start at the first grid row line, and take up 2 rows */
grid-row: 1 / span 2;
}

/* etc. */

This is the magic ingredient.

By adding the spacer, we’ve created two grid rows that together take up exactly 100vh. Now, all that’s left to do, in essence, is to tell the .header and .hero elements to align themselves to those existing rows. We do have to tell them to start at the same grid column line as the .above-the-fold-spacer element so that they won’t try to sit next to it. But with that done… ta-da!

See the Pen The Solution: Grid Alignment [forked] by Philip.

The reason this works is that a grid container can have multiple children occupying the same cell overlaid on top of each other. In a situation like that, the tallest child element defines the grid row’s overall height — or, in this case, the combined height of the two rows (100vh).

To control how exactly the two visible elements divvy up the available space between themselves, we can use the grid-template-rows property. I made it so that the first row uses min-content rather than 1fr. This is necessary so that the .header doesn’t take up the same amount of space as the .hero but instead only takes what it needs and lets the hero have the rest.

Here’s our full solution:

body {
display: grid;
grid-template-rows: min-content 1fr;
}

.above-the-fold-spacer {
height: 100vh;
grid-column: 1 / -1;
grid-row: 1 / span 2;
}

.header {
position: sticky;
top: 0;
grid-column-start: 1;
grid-row-start: 1;
}

.hero {
grid-column-start: 1;
grid-row-start: 2;
}

And voila: A sticky header of arbitrary size above a hero that grows to fill the remaining visible space!

Caveats and Final Thoughts

It’s worth noting that the HTML order of the elements matters here. If we define .above-the-fold-spacer after our .hero section, it will overlay and block access to the elements underneath. We can work around this by declaring either order: -1, z-index: -1, or visibility: hidden.

Keep in mind that this is a simple example. If you were to add a sidebar to the left of your page, for example, you’d need to adjust at which column the elements start. Still, in the majority of cases, using a CSS Grid approach is likely to be less troublesome than the Sisyphean task of manually managing and coordinating the height values of multiple elements.

Another upside of this approach is that it’s adaptable. If you decide you want a group of three elements to take up the screen’s height rather than two, then you’d make the invisible spacer span three rows and assign the visible elements to the appropriate one. Even if the hero element’s content causes its height to exceed 100vh, the grid adapts without breaking anything. It’s even well-supported in all modern browsers.

The more I think about this technique, the more I’m persuaded that it’s actually quite clean. Then again, you know how lawyers can talk themselves into their own arguments? If you can think of an even simpler solution I’ve overlooked, feel free to reach out and let me know!

Linking to an Image Folder Within a WordPress Theme

Featured Imgs 26

During WordPress theme development you will more then likely need to display some images that are located within your theme directory. The location of the images folder can vary greatly. It really comes down to how you like to set things up. Generally speaking if you were to have an images folder in the root of your theme you can … Read more

The post Linking to an Image Folder Within a WordPress Theme appeared first on Web Design Weekly.

How To Create A Weekly Google Analytics Report That Posts To Slack

Featured Imgs 29

Google Analytics is great, but not everyone in your organization will be granted access. In many places I’ve worked, it was on a kind of “need to know” basis.

In this article, I’m gonna flip that on its head and show you how I wrote a GitHub Action that queries Google Analytics, generates a top ten list of the most frequently viewed pages on my site from the last seven days and compares them to the previous seven days to tell me which pages have increased in views, which pages have decreased in views, which pages have stayed the same and which pages are new to the list.

The report is then nicely formatted with icon indicators and posted to a public Slack channel every Friday at 10 AM.

Not only would this surfaced data be useful for folks who might need it, but it also provides an easy way to copy and paste or screenshot the report and add it to a slide for the weekly company/department meeting.

Here’s what the finished report looks like in Slack, and below, you’ll find a link to the GitHub Repository.

GitHub

To use this repository, follow the steps outlined in the README.

https://github.com/PaulieScanlon/smashing-weekly-analytics

Prerequisites

To build this workflow, you’ll need admin access to your Google Analytics and Slack Accounts and administrator privileges for GitHub Actions and Secrets for a GitHub repository.

Customizing the Report and Action

Naturally, all of the code can be changed to suit your requirements, and in the following sections, I’ll explain the areas you’ll likely want to take a look at.

Customizing the GitHub Action

The file name of the Action weekly-analytics.report.yml isn’t seen anywhere other than in the code/repo but naturally, change it to whatever you like, you won’t break anything.

The name and jobs: names detailed below are seen in the GitHub UI and Workflow logs.

The cron syntax determines when the Action will run. Schedules use POSIX cron syntax and by changing the numbers you can determine when the Action runs.

You could also change the secrets variable names; just make sure you update them in your repository Settings.

# .github/workflows/weekly-analytics-report.yml

name: Weekly Analytics Report

on:
schedule:
– cron: ‘0 10 * * 5′ # Runs every Friday at 10 AM UTC
workflow_dispatch: # Allows manual triggering

jobs:
analytics-report:
runs-on: ubuntu-latest

env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
GA4_PROPERTY_ID: ${{ secrets.GA4_PROPERTY_ID }}
GOOGLE_APPLICATION_CREDENTIALS_BASE64: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS_BASE64 }}

steps:
– name: Checkout repository
uses: actions/checkout@v4

– name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ’20.x’

– name: Install dependencies
run: npm install

– name: Run the JavaScript script
run: node src/services/weekly-analytics.js

Customizing the Google Analytics Report

The Google Analytics API request I’m using is set to pull the fullPageUrl and pageTitle for the totalUsers in the last seven days, and a second request for the previous seven days, and then aggregates the totals and limits the responses to 10.

You can use Google’s GA4 Query Explorer to construct your own query, then replace the requests.

// src/services/weekly-analytics.js#L75

const [thisWeek] = await analyticsDataClient.runReport({
property: `properties/${process.env.GA4_PROPERTY_ID}`,
dateRanges: [
{
startDate: ‘7daysAgo’,
endDate: ‘today’,
},
],
dimensions: [
{
name: ‘fullPageUrl’,
},
{
name: ‘pageTitle’,
},
],
metrics: [
{
name: ‘totalUsers’,
},
],
limit: reportLimit,
metricAggregations: [‘MAXIMUM’],
});

Creating the Comparisons

There are two functions to determine which page views have increased, decreased, stayed the same, or are new.

The first is a simple reduce function that returns the URL and a count for each.

const lastWeekMap = lastWeekResults.reduce((items, item) => {
const { url, count } = item;
items[url] = count;
return items;
}, {});

The second maps over the results from this week and compares them to last week.

// Generate the report for this week
const report = thisWeekResults.map((item, index) => {
const { url, title, count } = item;
const lastWeekCount = lastWeekMap[url];
const status = determineStatus(count, lastWeekCount);

return {
position: (index + 1).toString().padStart(2, ‘0’), // Format the position with leading zero if it’s less than 10
url,
title,
count: { thisWeek: count, lastWeek: lastWeekCount || ‘0’ }, // Ensure lastWeekCount is displayed as ‘0’ if not found
status,
};
});

The final function is used to determine the status of each.

// Function to determine the status
const determineStatus = (count, lastWeekCount) => {
const thisCount = Number(count);
const previousCount = Number(lastWeekCount);

if (lastWeekCount === undefined || lastWeekCount === ‘0’) {
return NEW;
}

if (thisCount > previousCount) {
return HIGHER;
}

if (thisCount < previousCount) {
return LOWER;
}

return SAME;
};

I’ve purposely left the code fairly verbose, so it’ll be easier for you to add console.log to each of the functions to see what they return.

Customizing the Slack Message

The Slack message config I’m using creates a heading with an emoji, a divider, and a paragraph explaining what the message is.

Below that I’m using the context object to construct a report by iterating over comparisons and returning an object containing Slack specific message syntax which includes an icon, a count, the name of the page and a link to each item.

You can use Slack’s Block Kit Builder to construct your own message format.

// src/services/weekly-analytics.js#151

const slackList = report.map((item, index) => {
const {
position,
url,
title,
count: { thisWeek, lastWeek },
status,
} = item;

return {
type: ‘context’,
elements: [
{
type: ‘image’,
image_url: ${reportConfig.url}/images/${status},
alt_text: ‘icon’,
},
{
type: ‘mrkdwn’,
text: ${position}. &lt;${url}|${title}&gt; | *${x${thisWeek}}`* / x${lastWeek}`,
},
],
};
});

Before you can run the GitHub Action, you will need to complete a number of Google, Slack, and GitHub steps.

Ready to get going?

Creating a Google Cloud Project

Head over to your Google Cloud console, and from the dropdown menu at the top of the screen, click Select a project, and when the modal opens up, click NEW PROJECT.

Project name

On the next screen, give your project a name and click CREATE. In my example, I’ve named the project smashing-weekly-analytics.

Enable APIs & Services

In this step, you’ll enable the Google Analytics Data API for your new project. From the left-hand sidebar, navigate to APIs & Services > Enable APIs & services. At the top of the screen, click + ENABLE APIS & SERVICES.

Enable Google Analytics Data API

Search for “Google analytics data API,” select it from the list, then click ENABLE.

Create Credentials for Google Analytics Data API

With the API enabled in your project, you can now create the required credentials. Click the CREATE CREDENTIALS button at the top right of the screen to set up a new Service account.

A Service account allows an “application” to interact with Google APIs, providing the credentials include the required services. In this example, the credentials grant access to the Google Analytics Data API.

Service Account Credentials Type

On the next screen, select Google Analytics Data API from the dropdown menu and Application data, then click NEXT.

Service Account Details

On the next screen, give your Service account a name, ID, and description (optional). Then click CREATE AND CONTINUE.

In my example, I’ve given my service account a name and ID of smashing-weekly-analytics and added a short description that explains what the service account does.

Service Account Role

On the next screen, select Owner for the Role, then click CONTINUE.

Service Account Done

You can leave the fields blank in this last step and click DONE when you’re ready.

Service Account Keys

From the left-hand navigation, select Service Accounts, then click the “more dots” to open the menu and select Manage keys.

Service Accounts Add Key

On the next screen, locate the KEYS tab at the top of the screen, then click ADD KEY and select Create new key.

Service Accounts Download Keys

On the next screen, select JSON as the key type, then click CREATE to download your Google Application credentials .json file.

Google Application Credentials

If you open the .json file in your code editor, you should be looking at something similar to the one below.

In case you’re wondering, no, you can’t use an object as a variable defined in an .env file. To use these credentials, it’s necessary to convert the whole file into a base64 string.

Note: I wrote a more detailed post about how to use Google Application credentials as environment variables here: “How to Use Google Application .json Credentials in Environment Variables.”

From your terminal, run the following: replace name-of-creds-file.json with the name of your .json file.

cat name-of-creds-file.json | base64

If you’ve already cloned the repo and followed the Getting started steps in the README, add the base64 string returned after running the above and add it to the GOOGLE_APPLICATION_CREDENTIALS_BASE64 variable in your .env file, but make sure you wrap the string with double quotation makes.

GOOGLE_APPLICATION_CREDENTIALS_BASE64=”abc123″

That completes the Google project side of things. The next step is to add your service account email to your Google Analytics property and find your Google Analytics Property ID.

Google Analytics Properties

Whilst your service account now has access to the Google Analytics Data API, it doesn’t yet have access to your Google Analytics account.

Get Google Analytics Property ID

To make queries to the Google Analytics API, you’ll need to know your Property ID. You can find it by heading over to your Google Analytics account. Make sure you’re on the correct property (in the screenshot below, I’ve selected paulie.dev — GA4).

Click the admin cog in the bottom left-hand side of the screen, then click Property details.

On the next screen, you’ll see the PROPERTY ID in the top right corner. If you’ve already cloned the repo and followed the Getting started steps in the README, add the property ID value to the GA4_PROPERTY_ID variable in your .env file.

Add Client Email to Google Analytics

From the Google application credential .json file you downloaded earlier, locate the client_email and copy the email address.

In my example, it looks like this: smashing-weekly-analytics@smashing-weekly-analytics.iam.gserviceaccount.com.

Now navigate to Property access management from the left hide side navigation and click the + in the top right-hand corner, then click Add users.

On the next screen, add the client_email to the Email addresses input, uncheck Notify new users by email, and select Viewer under Direct roles and data restrictions, then click Add.

That completes the Google Analytics properties section. Your “application” will use the Google application credentials containing the client_email and will now have access to your Google Analytics account via the Google Analytics Data API.

Slack Channels and Webhook

In the following steps, you’ll create a new Slack channel that will be used to post messages sent from your “application” using a Slack Webhook.

Creating The Slack Channel

Create a new channel in your Slack workspace. I’ve named mine #weekly-analytics-report. You’ll need to set this up before proceeding to the next step.

Creating a Slack App

Head over to the slack api dashboard, and click Create an App.

On the next screen, select From an app manifest.

On the next screen, select your Slack workspace, then click Next.

On this screen, you can give your app a name. In my example, I’ve named my Weekly Analytics Report. Click Next when you’re ready.

On step 3, you can just click Done.

With the App created, you can now set up a Webhook.

Creating a Slack Webhook

Navigate to Incoming Webhooks from the left-hand navigation, then switch the Toggle to On to activate incoming webhooks. Then, at the bottom of the screen, click Add New Webook to Workspace.

On the next screen, select your Slack workspace and a channel that you’d like to use to post messages, too, and click Allow.

You should now see your new Slack Webhook with a copy button. Copy the Webhook URL, and if you’ve already cloned the repo and followed the Getting started steps in the README, add the Webhook URL to the SLACK_WEBHOOK_URL variable in your .env file.

Slack App Configuration

From the left-hand navigation, select Basic Information. On this screen, you can customize your app and add an icon and description. Be sure to click Save Changes when you’re done.

If you now head over to your Slack, you should see that your app has been added to your workspace.

That completes the Slack section of this article. It’s now time to add your environment variables to GitHub Secrets and run the workflow.

Add GitHub Secrets

Head over to the Settings tab of your GitHub repository, then from the left-hand navigation, select Secrets and variables, then click Actions.

Add the three variables from your .env file under Repository secrets.

A note on the base64 string: You won’t need to include the double quotes!

Run Workflow

To test if your Action is working correctly, head over to the Actions tab of your GitHub repository, select the Job name (Weekly Analytics Report), then click Run workflow.

If everything worked correctly, you should now be looking at a nicely formatted list of the top ten page views on your site in Slack.

Finished

And that’s it! A fully automated Google Analytics report that posts directly to your Slack. I’ve worked in a few places where Google Analytics data was on lockdown, and I think this approach to sharing Analytics data with Slack (something everyone has access to) could be super valuable for various people in your organization.

A Better Google Analytics Alternative

Featured Imgs 29

Our recent migration to GA4 left a lot to be desired and led us to explore for better google analytics alternatives. We tried just about everything out there, including Plausible, Fathom, and several others, all with their own pros and cons. The biggest hurdles were: limited features and higher costs.

That’s why we were so excited when we stumbled across Fullres recently. Not only do they have the best pricing around but they’re bundling multiple tools we use—ad revenue, analytics, web vitals—all into a single platform. Usually, you have to subscribe to multiple services and jump between browser tabs to see that amount of data together. Looking at their roadmap, there’s a lot more coming too.

Fullres also stood out with their quick 5-second installation setup. You get instant access to audience statistics in a GDPR-compliant manner and built-in Web Vitals data to continuously improve key metrics such as First Contentful Paint (FCP), Largest Contentful Paint (LCP), and other more.

For those who found the switch to GA4 challenging, Fullres is worth a try. It’s currently invite-only, so join the waitlist as soon as possible to get early access.

Reverse engineering minified JS with ChatGPT

Category Image 062

#​703 — September 5, 2024

Read on the Web

JavaScript Weekly

An SSR Performance Showdown — Fastify’s Matteo Collina set out to find the current state of server-side rendering performance across today’s most popular libraries. The first attempt faced negative feedback due to implementation issues, but the showdown has been improved and re-run.

Matteo Collina

Announcing Vue 3.5 — While v3.5 is a minor release, it’s one Vue users will love, with big performance and memory usage improvements in its reactivity system. With no breaking changes, upgrade and watch memory consumption drop.

Evan You

WorkOS: The Modern Identity Platform for B2B SaaS — WorkOS is a modern identity platform for B2B SaaS, offering flexible and easy-to-use APIs to integrate SSO, SCIM, and RBAC in minutes instead of months. It’s trusted by hundreds of high-growth startups such as Perplexity, Vercel, Drata, and Webflow.

WorkOS sponsor

Reverse Engineering Minified JavaScript with ChatGPTWriting new code with AI is one thing, but could it be even better at understanding existing code that you’re struggling to grok? Yes, it seems.

Frank Fiegel

Inside ECMAScript: JavaScript Standards Get an Extra Stage — After nine years of annual updates, TC39 has tweaked the process to make rolling out new features faster and smoother. The so-called ‘Stage 2.7’ has been around for a while, but this is a neat primer to what it represents.

Mary Branscombe (The New Stack)

IN BRIEF:

⭐ Vercel goes deep into what’s new in React 19.

💰 Alpine.js creator Caleb Porzio shares his tale of passing $1m on GitHub Sponsors.

Bye NgModules, the future of Angular is standalone! Angular v19 will make standalone: true the default for components, directives, and pipes. This is already the recommended best practice, however.

Angular’s product lead, Minko Gechev, has also shared a little about what it means to mange the Angular project.

OpenAI has switched ChatGPT from Next.js to a Remix-based app, according to Remix’s Ryan Florence on X.

🇵🇱 Poland’s WarsawJS community is holding a 10th anniversary meetup on September 11. They invite you to ▶️ watch live on YouTube.

🤖 Lee Robinson shows off ▶️ the latest enhancements to Vercel’s v0, an AI-based tool for creating apps and components from prompts you supply.

[Workshop] Fix Your Front-End: JavaScript Edition — Learn practical tips to make debugging more tolerable. Join our JavaScript team live for a masterclass on Sept 24.

Sentry sponsor

RELEASES:

Node.js v22.8.0 (Current) – Adds a new API for enabling on-disk code caching at runtime, as well as options to set thresholds for code coverage success.

Astro 4.15 – The popular content site framework stabilizes Astro Actions, a solution for fully type-safe backend functions.

Jimp 1.3 – Pure JS image processing library for Node.

Turborepo 2.1, Puppeteer 23.3, Mermaid 11.1

📒 Articles & Tutorials

▶  Behind the Scenes: The Making of VS Code — A detailed conversation with two of the popular editor’s principal engineers on what makes it tick. VS Code is surely one of the world’s most widely distributed JavaScript-powered apps.

Holland, Rieken and Pasero (Microsoft)

How I Created a 3.78MB Docker Image for a JavaScript Service — The smallest JavaScript app container images tend to run into tens of megabytes, but tailoring your app to run on a lighter runtime like llrt can yield striking results.

Shenzilong

Leave Forms to SurveyJS and Get Back to What You Love Coding — Extensible JavaScript libraries for form management. Drag-and-drop UI, JSON form definitions, and seamless integration with any backend for full data control.

SurveyJS sponsor

Exploring Goja: A Go-Powered JavaScript RuntimeGoja is a pure Go(lang) JS runtime that makes it possible to embed JS into Go apps.

JT Archie

How to Use React Compiler — The compiler feature in React 19 is generating a lot of buzz — this “complete guide”, as described by this author, covers much of what you’ll need to get started.

Tapas Adhikary

Multithreaded Programming in Node.js using AtomicsWorker threads enable you to write multi-threaded Node apps, but sharing resources across them can quickly become tricky. Atomics can help avoid some of the pain.

Pavel Romanov

📄 A Complete Guide to Beginning with JavaScript – A rather epic article packed with background knowledge, context, and third party resources for starting a modern JavaScript learning journey. Cody Lindley

📄 Implementing Filtered Semantic Search Using pgvector and JavaScript Team Timescale

📄 How to Quickly (and Weightlessly) Convert Chrome Extensions to Safari Nina Torgunakova (Evil Martians)

📄 How Sentry Uses Mutation Testing on its JavaScript SDKs Lukas Stracke (Sentry)

🎤 Talking Deno 2 with Ryan Dahl Syntax․fm Podcast

🛠 Code & Tools

jsdiff 6.0: A JavaScript Text Diffing Implementation — Can compare strings for differences in various ways including creating patches. There’s an online demo. (Don’t worry – we’re not going monthly ;-))

Kevin Decker

Redwood v8.0 Released — A long standing, opinionated React & GraphQL (and/or RSC) full-stack framework that covers all the bases for professional dev teams with best-in-class tool support. v8.0 introduces a background jobs system, Docker support, and easier SSR and RSC setup.

Redwood Team

Tests Are Dead. Meticulous Is Here — Automatically creates & maintains E2E UI tests. Zero flakes. Backed by YC, CTO of GitHub, CPO of Adobe, CEO of Vercel.

Meticulous sponsor

🇬🇧 GOV.UK Vue 1.0: Build Vue Apps, the British Way — The UK government is known for having an effective, well-designed site where Brits can complete various official tasks. Now you can get all of their components in Vue 3 form.

UK Government

👀 style-observer: A Mutation Observer for CSS — Attach JavaScript callbacks to changes in computed values of CSS properties.

Bramus Van Damme

Goxygen: Quickly Generate a Go Backend for a JS Project — A tool that sets up a new Go-based project with Angular, React, or Vue in the front-end, and Docker and Docker Compose files to make it all work.

Sasha Shpota

Typist 7.0: Tiptap-Based Rich Text Editor Component — Simple and opinionated. You can try several examples in the sidebar. Well suited for basic rich text situations like writing comments or messages and has a single-line mode.

Doist

Belt: A New Tool for Starting React Native Apps — A CLI tool for starting a new React Native app that takes various mundane decisions away from you and uses tooling and conventions established by a productive app development team.

Thoughtbot

Tinybase 5.2 – Powerful reactive data store for local‑first apps. Now with Postgres support (which can even work in-browser!)

jsdoc-to-markdown 9.0 – Generate Markdown docs from JSDoc-annotated code.

LogTape 0.5 – No-dependency logging lib for Deno, Node, Bun & browsers.

Plasmo 0.89 – Imagine Next.js but for building browser extensions.

JsonTree.js 3.0 – Customizable tree views for JSON data.

Poku 2.6 – Cross-platform JavaScript test runner.

Faker 9.0 – Generate large amounts of fake data.

Minimizing User Decision Fatigue in Web Design

Category Image 076

Offering an array of choices might seem like an excellent way to cater to diverse user preferences, but more often than not, it can cause decision fatigue, negatively impacting the user experience and conversion rates. So, how do we strategically minimize this fatigue through effective web design?

The UX Designer Toolbox

Unlimited Downloads: 500,000+ Wireframe & UX Templates, UI Kits & Design Assets
Starting at only $16.50 per month!


Decision Fatigue in Web Design

Decision fatigue can lead to a decline in the quality of decisions after a continuous decision-making process. In web design, users can experience this fatigue when faced with too many choices, leading to indecisiveness, frustration, and eventual disengagement.

Hick’s Law plays a part in this, suggesting that the time to make a decision increases with the number and complexity of choices. Nonetheless, Hick’s Law is just a fraction of a much broader picture. Balancing user choices and decision fatigue effectively also requires understanding principles like settling for the first reasonable option, avoiding potential losses, and making decisions based on readily available information.

Strategies to Minimize Decision Fatigue

To help users make confident decisions without causing fatigue, several tactics can be implemented.

Streamlined Navigation

Develop a logical, intuitive navigation path to eliminate unnecessary decision-making. For example, clear categorization in a website’s menu helps users find what they need without going through numerous options.

Prioritized Choices

Present the users with essential choices first and omit irrelevant ones. A home page showcasing the most popular products instead of an extensive catalog can prevent choice overload.

Restricted Options

Limit the number of options at each decision point to avoid overwhelming users. For instance, in a subscription selection, offering three plans – basic, premium, and advanced, can be more effective than having numerous slightly differing options.

Design Strategies to Reduce Cognitive Load

Strategic design choices can further alleviate decision fatigue.

Consistent Design

Keeping design elements consistent throughout the website simplifies cognitive processing. For instance, maintaining the same style for all buttons or icons aids user recognition and reduces the cognitive load.

Utilizing Familiar Patterns

Use recognizable icons and layouts to reduce cognitive effort and decision-making time. Employing standard symbols for shopping carts or menus enables users to interact with your website effortlessly.

Anticipatory Design

Predicting user actions and simplifying processes can lessen the number of decisions a user needs to make. Autofilling forms based on past user data is one such example.

Effective Error Handling

Minimize frustration and decision fatigue by guiding users effectively when errors occur. For instance, a clear error message with a suggested solution can keep a user engaged, even in the event of a mistake.

Final Thoughts

Taking into account the principles of decision fatigue and integrating the mentioned design strategies, your web design can become more user-friendly, reducing decision fatigue. Our overview aims to set you on the right path but remember, UX practices often involve deeper explorations and constant testing. Your understanding of decision fatigue will deepen as you engage more with UX research and real-world testing.

While we’re grappling with the complexities of choice, remember there’s another potent tool at your disposal – social proof. Using elements like reviews, testimonials, or popularity indicators can steer users toward decisions others have already made, thus easing their decision-making process. To learn more about how social proof can reinforce user decisions, we invite you to read our article on the topic.

In a world where choice overload is a reality, appreciating the power of simplicity and efficiency in decision-making is invaluable. It’s about striking that optimal balance – giving users ample choice without sparking decision fatigue.

The npm tea party

Featured Imgs 26

#​700 — August 15, 2024

Read on the Web

👋 Wow, issue 700! We’re back after a week away. Technically I’m still on vacation, but I didn’t want to leave you in the lurch for too long.. 😉
__
Peter Cooper, your editor

JavaScript Weekly

ECMAScript Safe Assignment Operator Proposal — We often feature ECMAScript proposals that are in their later stages, but how about a brand new one you could get involved with? This one proposes an interesting additional bit of language syntax (?=) that returns a [error, value] tuple from an assignment.

Arthur Fiorette

Crafting a 13KB Game: The Story of Space Huggers — We always love Frank’s dives into how he produces neat JavaScript experiments and, in this case, a complete game in just 13KB — and if it inspires you, the latest js13kGames game development competition has just started.

Frank Force

WorkOS: The Modern Identity Platform for B2B SaaS — WorkOS is a modern identity platform for B2B SaaS, offering flexible and easy-to-use APIs to integrate SSO, SCIM, and RBAC in minutes instead of months. It’s trusted by hundreds of high-growth startups such as Perplexity, Vercel, Drata, and Webflow.

WorkOS sponsor

Google’s Angular Lead Sees Convergence in JavaScript Frameworks“When picking a framework, don’t overthink it. It will end up being the same technology anyway with a different facade.” Minko Gechev talks about leading the way in converging Google’s Angular and Wiz frameworks.

Loraine Lawson (The New Stack)

Announcing Official Puppeteer Support for Firefox — As of version 23, Google’s originally Chrome-only Puppeteer browser automation library now has first-class support for Firefox too.

Mozilla Hacks

IN BRIEF:

⭐ If you’ve wondered why so many new npm packages are spam these days, it may be because of ‘Tea’. Though not the drinking kind..

Brendan Eich has expressed his support for the currently stage 1 Decimal draft proposal for bringing a more precise decimal number representation to JavaScript.

There’s an early technical preview of React Native WebGPU. William Candillon shows it off in ▶️ this 9-minute screencast.

RELEASES:

jQuery UI 1.14.0 – The legacy effects and widgets library reduces support for older browsers.

Madge 8.0 – Create graphs of module dependencies.

React Native 0.75, Angular 18.2, Bun 1.1.23, ESLint 9.9

📒 Articles & Tutorials

Patterns for Memory Efficient DOM Manipulation — Marc shares a solid look at the best practices to employ in order to avoid excess memory usage when managing/updating the DOM, all with a hope to make your apps faster. A good overview of the core principles behind DOM manipulation and optimization.

Marc Grabanski

‘How I Won $2,750 using JavaScript, AI, and a Can of WD-40’ — This is far from a technical JavaScript article, but it’s a fun story, involves some code and statistics, and ultimately might make you laugh.

Dave Kiss

Breakpoints and console.log Is the Past, Time Travel Is the Future — 15x faster JavaScript debugging than with breakpoints and console.log, supports Vitest, jest, node:test, and more. Huge changes are coming in Wallaby 2.0! Stay tuned. 🚀

Wallaby Team sponsor

Common Causes of Memory Leaks in JavaScript — Filled with basic examples oriented around V8-based runtimes like Node.js and Deno.

Trevor Indrek Lasn

Learn Web Components — If you’re looking to scrub on your Web Components know-how, this road map should prove useful. It’s a collection of good third party articles covering a wide range of knowledge.

Andrico Karoulla

A Tale of Evading JavaScript Anti-Debugging Techniques — When debugging code written by a third party, there could be some traps thrown in your way to prevent your usual debugging techniques. What to do? Revisiting a popular article from 2023.

Veritas

Fine-Grained Reactivity in Svelte 5 — Taking a close look at Svelte’s new so-called fine-grained reactivity.

Adam Rackis

📄 Tips for Using React Testing Library to Write Unit Tests Pavan Policherla

📄 45 VS Code Shortcuts for Boosting Your Productivity Shahed Nasser

🛠 Code & Tools

Volta 2.0: Install and Run JavaScript Tools Quickly — A long-standing Rust powered tool for installing and switching JavaScript related tools (like Node, TypeScript, Yarn, etc.) … “no matter the package manager, Node runtime, or OS.” GitHub repo.

Volta

Floating UI: Positioning for Tooltips, Popovers, Dropdowns, etc. — A library to create ‘floating’ elements such as tooltips, popovers, and dropdowns. Essentially a next-gen Popper which it now officially succeeds.

atomiks

😘 Kiss Bugs Goodbye — Get 80% automated E2E web and mobile app coverage in under four months with QA Wolf
. With QA cycles complete in minutes (not days), bugs don’t stand a chance. Schedule a demo.

QA Wolf sponsor

React Figma: Use Components as a Source for Figma Designs — A lot of folks use Figma to mock up designs for their React components, but what about the other way around? Use React components as a source for your designs in Figma! GitHub repo.

Ilya Lesik

Ky 1.6 – Simple HTTP client based upon Fetch for browsers, Node & Deno.

True Myth 8.0 – Safe, idiomatic null and error handling in TypeScript with Maybe and Result types.

Protobuf-ES 2.0 – Fully compliant Protobuf implementation for JS/TS.

🕹️ Kontra 10.0 – Lightweight gaming micro-library, optimized for js13kGames.

React Tooltip 5.28 – A tooltip component, surprisingly. (Demo.)

express-validator 7.2 – Express.js middleware for validator.js.

jscodeshift 17.0 – JavaScript codemod toolkit from Facebook.

🌍 Turf.js 7.1 – Modular geospatial analysis engine.

Marked 14.0 – Fast Markdown compiler / parser.

Retro CSS Text Effect: A Step-by-Step Tutorial

Category Image 076

CSS offers an array of tools that, when used correctly, can improve the visual experience on your website. In this tutorial, we’ll explore a straightforward way to design a retro text effect with pure CSS. The approach, while not overly complex, yields a visually appealing result and serves as a foundation for further customization.

The HTML Setup

We’ll begin with our markup, containing the text we’ll be styling – “1stWebDesigner“.

<div class=”retro-text”> 1stWebDesigner</div>

The div class .retro-text will be the hook for our CSS styling.

Designing the Retro Style with CSS

Next, let’s move on to our CSS file to create the retro text effect.

@import url(‘https://fonts.googleapis.com/css2?family=Lobster+Two:wght@700&display=swap’);

body {
background: #6868AC; /* Retro background color */
}

.retro-text {
font-family: ‘Lobster Two’, serif; /* Stylish, retro font */
font-size: 10vw; /* Responsive font size */
position: relative; /* Enables use of z-index */
color: #F9f1cc; /* Primary color of the text */
text-shadow: -2px 2px 0 #FFB650, /* Orange shadow */
-4px 4px 0 #FF80BF, /* Pink shadow */
-6px 6px 0 #6868AC; /* Dark blue shadow */
transform: skewX(-10deg); /* Skew the text on the X-axis */
transition: all 0.5s ease; /* Smooth transition for hover effects */
z-index: 2; /* Ensures text is layered above any potential background or border */
}

.retro-text:hover {
color: #FFFFFF; /* Brighter color on hover */
font-size: 15vw; /* Slightly larger text on hover */
text-shadow: -2px 2px 0 #FFC162, /* Brighter orange shadow on hover */
-4px 4px 0 #FF92D0, /* Brighter pink shadow on hover */
-6px 6px 0 #8888D3; /* Brighter blue shadow on hover */
}

To explain our CSS setup:

font-family: ‘Lobster Two’, serif;: We’re using Lobster Two, a stylish retro font.
font-size: 10vw;: Sets a responsive font size that adapts to the viewport width.
position: relative;: The relative positioning is necessary for the use of the z-index property.
color: #F9f1cc;: This determines the primary color of the text. Here, we’re using #F9f1cc, a light cream color.
text-shadow: -2px 2px 0 #FFB650, -4px 4px 0 #FF80BF, -6px 6px 0 #6868AC;: Three layers of text-shadow (orange, pink, and dark blue) are added, creating a 3D effect that enhances the retro feel.
transform: skewX(-10deg);: The text is skewed on the X-axis to add a dynamic touch.
transition: all 0.5s ease;: Smooth transition for hover effects.
z-index: 2;: A z-index of 2 ensures the text is always layered above any potential background or border.
:hover: The hover state includes a brighter color, slightly larger text size, and brighter shadows.

The Result

Here’s how the above code renders:

See the Pen
Retro CSS Text Effects by 1stWebDesigner (@firstwebdesigner)
on CodePen.

Final Thoughts

As you can see, CSS provides numerous opportunities to enhance your design. Using our retro text effect as a launching pad, you could experiment with further tweaks like altering text shadows, adjusting opacities or incorporating gradient backgrounds to intensify the retro vibe.

However, it’s crucial to remember the function of your text. The aim is to create a visually engaging site while maintaining readability. This is particularly important when using viewport units like vw for font sizes, which we used in our example. These units allow your text to adjust with the viewport size, ensuring a responsive design.

Yet, care is required. In some contexts, such as headings, vw units could cause your text to appear disproportionately large or small. To prevent this, consider using a mix of viewport and fixed units like em or rem, or setting max/min font sizes with media queries. Always remember: while design is important, it should never compromise the user’s ability to comfortably read and understand your content.

So, whether you’re introducing new elements, tweaking existing ones, or harnessing advanced techniques, every step you take helps you create unique styles that reflect your design aspirations.

Conducting UX Surveys: A Practical Guide

Featured Imgs 29

UX surveys can be pivotal tools for designers seeking to understand user preferences, opinions, and behaviors. They foster alignment between design strategies and user expectations and can improve product or service usability. Our overview unravels the process of conducting UX surveys, highlighting how both quantitative and qualitative approaches can yield essential user insights.

The UX Designer Toolbox

Unlimited Downloads: 500,000+ Wireframe & UX Templates, UI Kits & Design Assets
Starting at only $16.50 per month!


Conducting UX Surveys: Their Role and Execution

UX surveys serve as channels to collect insights directly from users about a product or service. They come in various forms, from online questionnaires to in-person discussions. These surveys aim to acquire both qualitative and quantitative data about user satisfaction, ease of use, and areas of potential improvement.

Conducting UX surveys follows a structured process. You begin by setting clear goals, and deciding what you aim to learn from the users. Then, you design a set of questions that invite insightful and actionable responses. Following the data collection, the task of data interpretation begins, leading to design changes that respond to the user’s needs.

Quantitative vs Qualitative: A Balancing Act

Quantitative surveys are useful when your goal is to collect numerical data. These types of surveys are great for tracking metrics such as usage frequency, user demographics, or user preferences. They offer the advantage of capturing data from a large audience, which can then be statistically analyzed to discern broader patterns and trends.

However, qualitative surveys offer something different. They are used when you want to dive deeper into the user’s thoughts, emotions, and experiences. Crucially, open-ended questions are the cornerstone of qualitative surveys, encouraging users to express their opinions freely. Although they might not yield broad statistical data, qualitative surveys provide detailed, nuanced information that can be invaluable for your design process.

Effective UX Survey: The Practical Steps

A well-designed UX survey is a careful process, requiring both strategic thinking and an empathetic understanding of your users. We’ll observe some of the indispensable steps that can guide your survey creation.

Objective Setting

Every UX survey must start with clear objectives. Whether you’re seeking to understand user behavior, assess user satisfaction, or gather feedback on a new feature, defining these goals will steer the development of your survey. It influences the kind of questions you will ask, the selection of respondents, and even the choice of the survey method. Clear goals ensure the collected data is genuinely useful and purpose-driven for your design strategy.

Drafting and Revision

The initial draft of your survey questions serves as a blueprint that should ideally be subjected to a review process. Don’t hesitate to involve your team, respected peers, or mentors in refining the questions. Their feedback will help eliminate ambiguities, prevent biased questions, and ensure the questionnaire resonates with your target audience.

Choosing the Right Platform

Selecting the most suitable platform for your UX survey significantly affects response rates and data quality. The nature of your survey – whether it’s a quick poll, an in-depth questionnaire, or an interactive survey – plays a huge role in this decision. Other factors to consider include the complexity of your survey, the technical competency of your target demographic, the platform’s user-friendliness on various devices, its visual appeal, and cost-effectiveness.

Question Design

The construction of your questions can be vital for the insights you gather. Close-ended questions, such as multiple-choice or Likert scale items, provide structured responses that are easier to analyze and compare. Meanwhile, open-ended questions encourage users to express their thoughts freely, providing deeper context and insight into their experiences. The key is to strike a balance: ask specific, direct questions to capture hard data, and open-ended ones to allow space for unexpected but valuable feedback.

Strategic Question Ordering

The placement of questions in your survey requires careful thought. Given the reality that some respondents will not complete the entire survey, it’s practical to position the most critical questions at the beginning. With this, you can somewhat secure the most valuable data, regardless of whether the user completes the entire questionnaire. Still, ensure a natural flow that doesn’t feel abrupt to the participant.

Testing the Waters

Prior to a full-scale launch of the survey, it’s beneficial to conduct a pilot test with a smaller, yet representative, sample of your user base. This approach allows for the identification and rectification of any potential issues – from ambiguous questions and technical glitches to unexpectedly long completion times. Moreover, pilot testing provides an opportunity to assess the survey’s ease and relevance, ensuring that the final version is as refined as possible before it reaches all users.

Wrapping Up

UX surveys can yield valuable user perspectives, but they should be seen as guides rather than definitive decision-makers in design choices.

Additionally, remember that a survey is a time commitment for your users. Avoid deterring completion or introducing response bias by overloading it with questions. Aim for a concise, engaging survey with a balance of question types.

Instead of duplicating data from analytics, use surveys to uncover user motivations, thoughts, and feelings that analytics can’t capture.

Lastly, consider both the user experience and your analysis capabilities when formatting questions. Open-ended questions offer rich insights but can overwhelm users and complicate analysis. Pilot-test these questions and refine them based on feedback. Some may work better as closed-ended questions for easier response and analysis.

For additional insights on managing broader yet valuable UX aspects, such as minimizing decision fatigue, feel free to check out this article.

Making an Underwater CSS Text Effect

Category Image 076

Web design can serve as a playful exploration ground for learning new techniques. In today’s guide, we’ll dive into the creation of an underwater CSS text effect, not just for the visual outcome, but to deepen our understanding of how different CSS properties harmonize to create dynamic text effects.

Your Web Designer Toolbox

Unlimited Downloads: 500,000+ Web Templates, Icon Sets, Themes & Design Assets
Starting at only $16.50/month!


Setting up the Structure

Our journey into the deep sea starts with a simple HTML structure: a div element with the class underwater, wrapping around an h1 tag.

<div class=”underwater”>
<h1>1stWebDesigner</h1>
</div>

Achieving the Underwater Effect

For our underwater CSS text effect, we introduce a range of CSS properties such as background-image, animation, and -webkit-background-clip.

@import url(‘https://fonts.googleapis.com/css2?family=Maven+Pro:wght@700&amp;display=swap’);

body{
/* Using a dark background color for optimal contrast */
background-color: #000;
font-family: ‘Maven Pro’, sans-serif;
}

.underwater h1{
/* Font settings: sizing and a semi-transparent color */
font-size: 2.5rem;
color: #2c3e5010;

/* Assigning an underwater image as the background */
background-image: url(‘https://w7.pngwing.com/pngs/183/509/png-transparent-under-water-scenery-sunlight-underwater-ray-star-ocean-atmosphere-cloud-computer-wallpaper.png’);

/* Clipping the background image to the outline of the text */
-webkit-background-clip:text;

/* Setting a 10s infinite animation for a dynamic effect */
animation: waterEffect 10s infinite;
}

/* Animation to simulate flowing water */
@keyframes waterEffect {
0% { background-position: left 0 top 0; }
100% { background-position: left 100% top 0; }
}

Explaining Key CSS Properties and Values

Breaking down our CSS code, the first point of interest is the background-image property. By setting an underwater image as the background, we immediately set the tone for our effect.

The -webkit-background-clip:text property clips the background image to the shape of the text. It allows the underwater image to fill the text, setting the stage for our effect.

The color property plays a vital role as well. We’re using a semi-transparent color (color: #2c3e5010;), where the last two digits 10 represent the alpha channel in hexadecimal format, controlling the transparency. This enables the background image to shine through, enhancing the underwater illusion.

The animation property sets our waterEffect animation into motion. Defined by the @keyframes rule, it continuously shifts the background-position from left 0 top 0 to left 100% top 0, creating the illusion of water flowing over the text.

The Result

See the Pen
Underwater Text Effect by 1stWebDesigner (@firstwebdesigner)
on CodePen.

Exploring Other Methods

Different methods can achieve similar effects. An alternate approach involves utilizing the clip-path property with CSS animations, yielding a wavy text appearance akin to an underwater CSS text effect. This method manipulates the clip region of an element over time, evoking a dynamic sense of movement reminiscent of water’s rhythmic flow. In addition, the technique doesn’t necessitate a background image, instead, it transforms the appearance of the text directly. By turning to this method, you’re exposed to yet another aspect of CSS and its potential for dynamic text effects.