Design systems are an entire job these days. Agencies are hired to create them. In-house teams are formed to handle them, shipping them so that other teams can use them and helping ensure they do. Design systems aren’t a fad, they are a positive evolution of how digital design is done. Backlight is the ultimate all-in-one development tool for design systems.
I think it’s interesting to start thinking about this at the end. What’s the best-case scenario for a design system for websites? I think it’s when you’ve published a versioned design system to npm. That way teams can pull it in as a dependency on the project and use it. How do you do that? Your design system is on GitHub and you publish from there. How do you do that? You work on your design system through a development environment that pushes to GitHub. What is Backlight? It’s that development environment.
Spin up a complete design system in seconds
Wanna watch me do it?
You don’t have to pick a starter template, but it’s enlightening to see all the possibilities. Backlight isn’t particularly opinionated about what technology you want to use for the system. Lit and Web Components? Great. React and Emotion? Cool. Just Vue? All good. Nunjucks and Sass? That works.
Having a starter design system really gives you a leg up here. If you’re cool with using something off-the-shelf and then customizing it, you’ll be off and running incredibly quickly. Something that you might assume would take a few weeks to figure out and settle into is done in an instant. And if you want to be 100% custom about everything, that’s still completely on the table.
Kick it up to GitHub
Even if you’re still just testing, I think it’s amazingly easy and impressive how you can just create a GitHub (or GitLab) repo and push to it in a few clicks.
To me, this is the moment it really becomes real. This isn’t some third-party tool where everyone is 100% forced to use it and you’re locked into it forever and it’s only really useful when people buy into the third-party tool. Backlight just takes very industry-standard practices and makes them easier and more convenient to work with.
Then, kick it to a registry.
Like I said at the top, this is the big moment for any design system. When you send it to a package registry like npm or GitHub packages, that means that anyone hoping to use your design system can now install it and use it like any other dependency.
In Backlight, this is just a matter of clicking a few buttons.
With a PRO membership, you can change the scope to your own organization. Soon you’ll be handling all your design system releases right from here, including major, minor, and patch versions.
Make a Component
I’d never used Backlight before, nobody helped me, and I didn’t read any of the (robust) documentation. I just clicked around and created a new Component easily. In my case here, I made a new Nunjucks macro, made some SCSS styles, then created a demo of it as a Storybook “story”. All I did was reference an existing component to see how it all worked.
As one of the creators of CodePen, of course, I highly appreciated the in-browser IDE qualities to all this. It runs re-builds your code changes (looks like a Vite process) super quickly, alerting you helpfully to any errors.
Now because this is a Very Real Serious Design System, I wouldn’t push this new component directly to master in our repository, first it becomes a branch, and then I commit to that. I wouldn’t have to know anything at all about Git to pull this off, look how easy it is:
Howdy, Stakeholders!
Design systems are as much of a people concern as they are a technological concern. Design systems need to get talked about. I really appreciate how I can share Backlight with anyone, even if they aren’t logged in. Just copy a sharing link (that nobody could ever guess) and away you go.
There is a lot here.
You can manage an entire design system in here. You’re managing things from the atomic token level all the way up to building example pages and piecing together the system. You’re literally writing the code to build all this stuff, including the templates, stories, and tests, right there in Backlight.
What about those people on your team who really just can’t be persuaded to leave their local development environment. Backlight understands this, and it doesn’t force them to! Backlight has a CLI which enables local development, including spinning up a server to preview active work.
But it doesn’t stop there. You can build documentation for everything right in Backlight. Design systems are often best explained in words! And design systems might actually start life (or live a parallel life) in entirely design-focused software like Figma, Sketch, or Adobe XD. It’s possible to link design documents right in Backlight, making them easy to find and much more organized.
I’m highly impressed! I wasn’t sure at first what to make of a tool that wants to be a complete tool for design systems, knowing how complex that whole world is, but Backlight really delivers in a way that I find highly satisfying, especially coming at it from the role of a front-end developer, designer, and manager.
Now your job is to rotate them. That is, cycle through classes on an HTML element. When some event occurs, if the element has state-1 on it, remove state-1 and add state-2. If it has state-2 on it, remove that and add state-3. On the last state, remove it, and cycle back to state-1.
It’s notable that we’re talking about 3+ classes here. The DOM has a .classList.toggle() function, even one that takes a conditional as a second parameter, but that’s primarily useful in a two-class on/off situation, not cycling through classes.
Why? There is a number of reasons. Changing a class name gives you lots of power to re-style things in the DOM, and state management like that is a cornerstone of modern web development. But to be specific, in my case, I was wanting to do FLIP animations where I’d change a layout and trigger a tween animation between the different states.
Careful about existing classes! I saw some ideas that overwrote .className, which isn’t friendly toward other classes that might be on the DOM element. All these are “safe” choices for cycling through classes in that way.
Because this is programming, there are lots of ways to get this done. Let’s cover a bunch of them — for fun. I tweeted about this issue, so many of these solutions are from people who chimed into that discussion.
A verbose if/else statement to cycle through classes
This is what I did at first to cycle through classes. That’s how my brain works. Just write out very specific instructions for exactly what you want to happen:
if (el.classList.contains("state-1")) {
el.classList.remove("state-1");
el.classList.add("state-2");
} else if (el.classList.contains("state-2")) {
el.classList.remove("state-2");
el.classList.add("state-3");
} else {
el.classList.remove("state-3");
el.classList.add("state-1");
}
I don’t mind the verbosity here, because to me it’s super clear what’s going on and will be easy to return to this code and “reason about it,” as they say. You could consider the verbosity a problem — surely there is a way to cycle through classes with less code. But a bigger issue is that it isn’t very extensible. There is no semblance of configuration (e.g. change the names of the classes easily) or simple way to add classes to the party, or remove them.
RegEx off the old class, increment state, then re-add
This one comes from Tab Atkins. Since we know the format of the class, state-N, we can look for that, pluck off the number, use a little ternary to increment it (but not higher than the highest state), then add/remove the classes as a way of cycling through them:
A bunch of techniques to cycle through classes center around setting up an array of classes up front. This acts as configuration for cycling through classes, which I think is a smart way to do it. Once you have that, you can find the relevant classes for adding and removing them. This one is from Christopher Kirk-Nielsen:
Christopher had a nice idea for making the add/remove technique shorter as well. Turns out it’s the same…
el.classList.remove(classes[activeIndex]);
el.classList.add(classes[nextIndex]);
// Does the same thing.
el.classList.replace(classes[activeIndex], classes[nextIndex]);
Mayank had a similar idea for cycling through classes by finding the class in an array, only rather than using classList.contains(), you check the classes currently on the DOM element with what is in the array.
const states = ["state-1", "state-2", "state-3"];
const current = [...el.classList].find(cls => states.includes(cls));
const next = states[(states.indexOf(current) + 1) % states.length];
el.classList.remove(current);
el.classList.add(next);
Variations of this were the most common idea. Here’s Jhey’s and here’s Mike Wagz which sets up functions for moving forward and backward.
Cascading replace statements
Speaking of that replace API, Chris Calo had a clever idea where you chain them with the or operator and rely on the fact that it returns true/false if it works or doesn’t. So you do all three and one of them will work!
If you pre-configured a 1 upfront, you could cycle through classes 1-3 and add/remove them based on that. This is from Timothy Leverett who lists another similar option in the same tweet.
// Assumes a `let s = 1` upfront
el.classList.remove(`state-${s + 1}`);
s = (s + 1) % 3;
el.classList.add(`state-${s + 1}`);
Use data-* attributes instead
Data attributes have the same specificity power, so I have no issue with this. They might actually be more clear in terms of state handling, but even better, they have a special API that makes them nice to manipulate. Munawwar Firoz had an idea that gets this down to a one-liner:
Give yourself a little abstraction, right? Many of the ideas wrote code this way, but so far I’ve move it out to focus on the idea itself. Here, I’ll leave the function in. This one is from Andrea Giammarchi in which a unique function for cycling through classes is set up ahead of time, then you call it as needed:
I heard from Kyle Simpson who had this same idea, almost character for character.
Others?
There were more ideas in the replies to my original tweet, but are, best I can tell, variations on what I’ve already shared above. Apologies if I missed yours! Feel free to share your idea again in the comments here. I see nobody used a switch statements — that could be a possibility!
David Desandro went as far as recording a video, which is wonderful as it slowly abstracts the concepts further and further until it’s succinct but still readable and much more flexible:
And here’s a demo Pen with all the code for each example in there. They are numbered, so to test out another one, comment out the one that is uncommented, and uncomment another example:
Yesterday’s creativity won’t keep pace with tomorrow’s requirements; businesses need speed and agility without sacrificing creative quality.
“The creativity that was needed in the past is not the creativity that is needed today,” according to Matthew Rayback, a creative director at Adobe. He’s not talking about the function of creativity but rather about the process of creative management in a marketing context.
What is needed today? Speed and agility without sacrificing quality.
Why? Because the pace of change has accelerated. As Rex Salisbury, a deal partner for the venture firm a16z noted early in the pandemic, “Businesses of all kinds are experiencing two years’ worth of digitization compressed into months.”
This accelerated digital transformation has put pressure on marketing teams to turn campaigns around faster. In turn, that places pressure on creative teams to generate the requisite creative for those campaigns. Leaders need to sharpen their awareness of the unfolding creative management trends to keep pace. To that end, below are five such trends to watch in 2022.
1. In-House Creative Teams Continue to Grow
Companies have been building in-house creative teams for the better part of a decade. A 2018 study by Forrester Research and the In-House Agency Forum (IHAF) found the number of in-house teams has grown 22% in the last ten years or so. As The Wall Street Journal reported, more than half of advertisers (64%) have shifted their creative organizations to an in-house team.
According to a more recent version of that same study, the in-housing movement didn’t stop throughout the pandemic. It revealed, “80% of respondents said they have brought more marketing assignments in-house since the onset of the pandemic, with 50% saying the increase was directly triggered by the events of the past two years.”
Businesses seem well-satisfied with the results because the urge to in-house is poised to grow beyond creative teams. For example, a recent survey by the customer intelligence company Axciom found about 50% of respondents believe the “in-housing is currently a top marketing objective, and 40% expect it will remain a top priority in the coming years.”
2. Outside Agencies Hired for Specialized Skills
Despite the in-housing trend, there is still opportunity for agencies, consultants, and freelancers, particularly those with specialized skills. Even the consumer-packaged goods giant Proctor & Gamble, a leading example of brands bringing marketing and creative teams in-house, still needs outside service providers.
Indeed, while in-house creative teams produce the lion’s share of creative work, the vast majority (86%) also continue to partner with agencies and freelancers; according to our own research, published in our 2021 Creative Management Report, which was facilitated by Lytho (formerly inMotionNow) and based on a survey of 400 creatives and marketers.
When the survey asked creatives why they hire outside resources, the top reason was access to specialized skills (60%). That was followed in a distant second by a need for increased capacity (44%), help with developing strategy (24%), and, lastly, to get work done faster (20%).
“It is very unusual for an in-house team to have no outside resources that they lean on,” wrote Alex Blum of Blum Consulting Partners, Inc. in a written assessment of the survey results.
He says there are two primary ways to partner with agencies. “First, for overflow capacity. There is always a need for more creative resources, and agencies can offer that flexibility without the cost of maintaining larger teams,” he wrote. “Second, in-house teams can divide areas of ownership with an agency based on the skill sets they have in-house.”
3. The Creative Process Evolves
Marketing today is dominated by an insatiable thirst for fresh content, produced and polished by creative teams. The demand for that content continues to explode.
What does this portend for creative teams? Despite adding headcount, creative requests exceed the creative team’s capacity to produce it – even as lead times shrink. Matthew Rayback, the creative director at Adobe, suggested the creative process must evolve.
He likens creatives to an auto factory, where “creatives used to be the assembly line to make a single car.” However, today, creatives are tasked with creating more cars, each with unique adjustments such as personalization.
“The assembly line we built can’t accommodate that speed or volume,” he says. So the whole factory – the entire creative process – must be overhauled to adapt.
Current methods for measuring the value of creative teams center on outputs. That is to say, the metrics tracked tend to quantify the number of creative projects in progress, the rounds of review, and the number of projects completed over time.
These metrics are important, but alone they are insufficient. A complementary way to prioritize large volumes of creative requests is focusing on those tasks most likely to move the business needle. The barrier to achieving this is that most creatives aren’t kept informed as to the outcomes of marketing campaigns fueled by their creative efforts. This must change.
With the growing demand for content, the margin of error for applying creative resources to projects that don’t correlate to business results shrinks. Marketing organizations must build a feedback loop that brings quantitative results back to the creative team. In turn, creative teams must learn to use the data to drive their work priorities in collaboration with marketing.
5. Creative Resource Management Becomes Essential
Resource management is both a leadership concept and technology (or a combination of technologies). It’s a means to plan, track, collaborate and measure creative operations, including people, processes, and budgets.
Traditionally, planning and tracking of all things creative and marketing occurred in a spreadsheet. It works well when the future is generally predictable – yet cliché as it may be to say it – we are living in a state of uncertainty.
Like many trends over the last 18-24 months, the global pandemic “forced virtual experiences, disrupted marketing channels and campaigns, and accelerated companies’ transition to digital marketing,” according to Forrester. The research firm calls resource management “essential” because it helps move “planning from static spreadsheets to a dynamic and real-time environment.”
Final Thoughts
Yogi Berra paraphrased an old Danish proverb when he said, “It’s tough to make predictions, especially about the future.” Even so, the pandemic has accelerated trends that were already underway, and these five trends are good examples. More than just watching them, creative and marketing leaders should take steps now to get ahead of them.
On the most basic level, triggered emails are one-on-one emails sent to individuals in response to specific actions.
In contrast with generic emails, triggered emails are timely, relevant, and customized not just with fill-ins like the recipient’s name, but according to the recipient’s actions and recent interest, including personalized subject lines.
That being the case, it’s not surprising that triggered emails have a higher open rate and click-through rate. After all, they’re a lot more interesting for the person receiving them.
According to GetResponse’s research, open rates, click-through rates, and click to reopen rates are all higher for triggered emails than for autoresponder emails, newsletter emails, or RSS emails.
Like everything that’s worth achieving, triggered emails aren’t easy. You need to set up an integrated marketing data and analytics system that can spot the right time to send the right email to the right individual.
What’s more, in contrast with eCommerce businesses, service-based businesses often encompass non-digital touchpoints, making it harder to consolidate all the required signals and to set up the triggers that are most important to your customer experience. But the conversion rates you’ll see if you do it well certainly make it worth the time and effort.
Here are nine triggered emails that service businesses need to have set up in 2022.
1. Funnel interruption emails
Abandoned cart emails are pretty common for eCommerce businesses to remind users who bail out before completing an order, but service businesses can and should leverage the same tactic. Your customers may not be after physical products, but they do select and book services.
Send a triggered email when a visitor to your website chooses a date and time for their appointment but doesn’t click “confirm;” enters their email address to open an account and examines the different packages you offer, but hasn’t made a purchase; or buys a bundled package of services, but doesn’t get as far as scheduling an appointment.
Make sure that your email mentions the specific products or lines of service they were interested in, to make it as personalized as possible.
If the recipient already selected a date and time but didn’t confirm it, include a reminder of the time slot they were considering and a link to confirm it in one click. Email platforms like GetResponse connect with your website to create workflows that spot an unfinished process and trigger this kind of transactional email.
2. Confirmation emails
Confirmation emails are the most obvious kind of triggered email, but somehow they are often the easiest to overlook.
Set up a process that sends your client a short, sweet note that thanks them for making an appointment and recaps their appointment details.
Ideally, you should also include a link that adds the appointment to their Google or iCal calendar, making it all a seamless process that removes friction for the customer.
3. Reminder emails
As well as the confirmation email and calendar link, it’s a good idea to send a reminder email shortly before the appointment, so that users don’t miss their long-awaited slot. People have busy lives, so they generally appreciate a heads up that helps them make the facial, yoga class or dog grooming slot they’ve been looking forward to.
It’s important to select the right interval before the appointment, which could be anything from an hour before to the previous day or the beginning of the week of the appointment. It all depends on what service you offer, how long the appointment is, and how far in advance they booked. You might even send two reminders, one at the beginning of the week and one on the morning of the appointment.
You can do this easily with vcita, which automates reminders by email and SMS, and comes pre-integrated with the platform’s CRM, payments solutions, and appointment booking engine. Set the intervals you want to use for reminders, and vcita will send them using the recipient’s name and reminding them about the exact service they’ve booked.
4. Follow up emails
Customer relationships don’t end when the appointment does. Maintain your connection and add to the value you provide for clients by sending useful content that guides them to keep up their look, health, finances, home decor, etc. in between appointments.
You might also want to recap some of the information and/or techniques that you shared during your session and remind clients to use them at the right intervals.
For example, a yoga teacher might send a reminder the day after class, reminding you to do some basic stretches she showed you; a bookkeeper might send a reminder the following month to download and save your statement ready for the next quarter’s tax return; a beautician might send tips for keeping your skin looking fresh in-between facials, etc.
5. Appointment change or cancellation emails
If there’s any triggered email that’s 100% vital, it’s this one. Life happens, and your customers know and understand that, but they won’t forgive you for keeping them in the dark when it does. You need to send an email any time that the time, date, location, or any other condition of the client’s appointment has to be changed, or if you need to cancel it and ask them to reschedule.
In your triggered email, make sure to include a link to your online calendar, so they can easily reschedule, confirm your suggested new time/date/location/etc, or cancel the appointment and schedule a new one. When you use vcita, the system embeds a link in the body of the email.
6. Thank you emails
It’s polite and good business practice to say a simple but heartfelt “thank you” after the client attended their appointment, especially if this was their first appointment with your business.
What’s more, you can take the opportunity to remind them to book a follow-up appointment at the right interval, so a dentist could send a reminder to book an appointment at the hygienist after someone’s had a check up, or a massage therapist could recommend booking the next appointment in a month so the stress knots don’t get too tight.
Above is a great example of a “thank you for a great year together” type of email that a Massachusets based-spa sends to each customer to celebrate the anniversary of the relationship. The discount-focused call-to action is an especially nice touch.
7. Unpaid invoice reminders
Nobody likes chasing payments, but it has to be done sometimes. When you set triggered emails for this purpose, it’ll save you from tearing your hair out searching for the right firm-yet-kind wording every time.
Include details about the payment, such as the amount, what it’s for, the date you first sent the payment request, etc., together with a link to make it easy for them to pay.
QuickBooks has an easy-to-set-up process where you can write content for different reminder emails and set the conditions that trigger one being sent. This way, you can begin with a light tone and get more severe as more time passes, because the emails are triggered by how long it’s been since the invoice was sent.
8. Reactivation emails
Reactivation emails aren’t just for lapsed clients who haven’t been seen for months, but also whenever it’s verging on too long between appointments.
It’s important that your reactivation reminder is appropriately timed: send it too soon, and the client feels nagged and pestered, but if you wait too long, they might need more or longer sessions to correct the damage to their hair, skin, business accounts, bad back, etc.
There’s no fixed recipe for how long to wait before sending a reminder email, but some things to consider include:
Your service. Pedicure clients might come every 4-6 weeks, for example, but facial clients every 3-4 weeks.
The time of year. Lawn care clients might go 4-5 months between appointments in winter, but only 6 weeks in summer.
The specific client. Hair stylists may send a reminder to a client with short hair after 6 weeks, but wait 10 weeks before emailing someone with long hair.
9. Special event offer emails
These special offers are more tailored than a standard or seasonal discount offer, because they’re personalized according to some significant date in the life of the recipient.
It’s up to you what that is — it could be the anniversary of the date the client first signed up to your business or had their first appointment, or the client’s birthday or wedding anniversary.
Most email platforms like GetResponse, ConstantContact, vcita, and more include this ability, as long as you integrate them with your CRM. It’s worth remembering that vcita is already integrated with your CRM by default, so the process is shorter.
Triggered Emails Can Propel Your Service Business Forwards
Emails might seem old-fashioned, but it’s a mistake to overlook them. As you can see, triggered emails have more uses than you might realize for service businesses, ranging from encouraging people to book their first appointments to bringing them back for more and ensuring they stay on top of their new regimens.
The right arsenal of triggered emails and power your business to renewed growth.
Say you’ve got a component. It’s highly likely it shouldn’t be butted right up against any other components with no spacing around it. That’s true for… pretty much every component. So, how do you handle component spacing in a design system?
Do you apply spacing using margin directly on the ? Perhaps margin-block-end: 1rem; margin-inline-end: 1rem; so it pushes away from the two sides where more content natural flows? That’s a little presumptuous. Perhaps the cards are children inside a component and the grid applies a gap: 1rem. That’s awkward, as now the component spacing is going to conflict with the component spacing, which is very likely not what you want, not to mention the amount of space is hard coded.
You could bake spacing into every component and try to be as clever as you can about it. (But that’s pretty limiting.)
You could pass in component spacing, like . (That can be a good approach, likely needs more than one prop, maybe even one for each direction, which is quite verbose.)
You could use no component spacing and create something like a or component specifically for spacing between components. (It breaks up the job of components nicely, but can also be verbose and add unnecessary DOM weight.)
This conversation has a wide spectrum of viewpoints, some as extreme as Max Stoiber saying just never use margin ever at all. That’s a little dogmatic for me, but I like that it’s trying to rethink things. I do like the idea of taking the job of spacing and layout away from components themselves — like, for example, those content components should completely not care where they are used and let layout happen a level up from them.
Adam Argyle predicted a few years back that the use of margin in CSS would decline as the use of gap rises. He’s probably going to end up right about this, especially now that flexbox has gap and that developers have an appetite these dats to use CSS Flexbox and Grid on nearly everything at both a macro and micro level.
A little bit of animation on a site can add some flair, impress users, and get their attention. You could have them run, no matter where they are on the page, immediately when the page loads. But what if your website is fairly long so it took some time for the user to scroll down to that element? They might miss it.
You could have them run all the time, but perhaps the animation is best designed so that you for sure see the beginning of it. The trick is to start the animation when the user scrolls down to that element — scroll-triggered animation, if you will.
CodePen Embed Fallback
To tackle this we use scroll triggers. When the user scrolls down to any particular element, we can use that event to do something. It could be anything, even the beginning of an animation. It could even be scroll-triggered lazy loading on images or lazy loading a whole comments section. In that way, we won’t force users to download elements that aren’t in the viewport on initial page load. Many users may never scroll down at all, so we really save them (and us) bandwidth and load time.
Scroll triggers are very useful. There are many libraries out there that you can use to implement them, like Greensock’s popular ScrollTrigger plugin. But you don’t have to use a third-party library, particularly for fairly simple ideas. In fact, you can implement it yourself using only a small handful of vanilla JavaScript. That is what we are going to do in this article.
Here’s how we’ll make our scroll-triggered event
Create a function called scrollTrigger we can apply to certain elements
Apply an .active class on an element when it enters the viewport
Animate that .active class with CSS
There are times where adding a .active class is not enough. For example, we might want to execute a custom function instead. That means we should be able to pass a custom function that executes when the element is visible. Like this:
We’ll also attempt to handle scroll triggers for older non-supporting browsers.
But first, the IntersectionObserver API
The main JavaScript feature we’re going to use is the Intersection Observer. This API provides a way to asynchronously observe changes in the intersection of a target element — and it does so more in a more performant way than watching for scroll events. We will use IntersectionObserver to monitor when scrolling reaches the point where certain elements are visible on the page.
Let’s start building the scroll trigger
We want to create a function called scrollTrigger and this function should take a selector as its argument.
function scrollTrigger(selector) {
// Multiple element can have same class/selector,
// so we are using querySelectorAll
let els = document.querySelectorAll(selector)
// The above `querySelectorAll` returns a nodeList,
// so we are converting it to an array
els = Array.from(els)
// Now we are iterating over the elements array
els.forEach(el => {
// `addObserver function` will attach the IntersectionObserver to the element
// We will create this function next
addObserver(el)
})
}
// Example usage
scrollTrigger('.scroll-reveal')
Now let’s create the addObserver function that want to attach to the element using IntersectionObserver:
function scrollTrigger(selector){
let els = document.querySelectorAll(selector)
els = Array.from(els)
els.forEach(el => {
addObserver(el)
})
}
function addObserver(el){
// We are creating a new IntersectionObserver instance
let observer = new IntersectionObserver((entries, observer) => { // This takes a callback function that receives two arguments: the elements list and the observer instance.
entries.forEach(entry => {
// `entry.isIntersecting` will be true if the element is visible
if(entry.isIntersecting) {
entry.target.classList.add('active')
// We are removing the observer from the element after adding the active class
observer.unobserve(entry.target)
}
})
})
// Adding the observer to the element
observer.observe(el)
}
// Example usage
scrollTrigger('.scroll-reveal')
If we do this and scroll to an element with a .scroll-reveal class, an .active class is added to that element. But notice that the active class is added as soon as any small part of the element is visible.
But that might be overkill. Instead, we might want the .active class to be added once a bigger part of the element is visible. Well, thankfully, IntersectionObserver accepts some options for that as its second argument. Let’s apply those to our scrollTrigger function:
// Receiving options as an object
// If the user doesn't pass any options, the default will be `{}`
function scrollTrigger(selector, options = {}) {
let els = document.querySelectorAll(selector)
els = Array.from(els)
els.forEach(el => {
// Passing the options object to the addObserver function
addObserver(el, options)
})
}
// Receiving options passed from the scrollTrigger function
function addObserver(el, options) {
let observer = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if(entry.isIntersecting) {
entry.target.classList.add('active')
observer.unobserve(entry.target)
}
})
}, options) // Passing the options object to the observer
observer.observe(el)
}
// Example usage 1:
// scrollTrigger('.scroll-reveal')
// Example usage 2:
scrollTrigger('.scroll-reveal', {
rootMargin: '-200px'
})
And just like that, our first two agenda items are fulfilled!
Let’s move on to the third item — adding the ability to execute a callback function when we scroll to a targeted element. Specifically, let’s pass the callback function in our options object as cb:
function scrollTrigger(selector, options = {}) {
let els = document.querySelectorAll(selector)
els = Array.from(els)
els.forEach(el => {
addObserver(el, options)
})
}
function addObserver(el, options){
let observer = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if(entry.isIntersecting){
if(options.cb) {
// If we've passed a callback function, we'll call it
options.cb(el)
} else{
// If we haven't, we'll just add the active class
entry.target.classList.add('active')
}
observer.unobserve(entry.target)
}
})
}, options)
observer.observe(el)
}
// Example usage:
scrollTrigger('.loader', {
rootMargin: '-200px',
cb: function(el){
el.innerText = 'Loading...'
// Done loading
setTimeout(() => {
el.innerText = 'Task Complete!'
}, 1000)
}
})
Great! There’s one last thing that we need to take care of: legacy browser support. Certain browsers might lack support for IntersectionObserver, so let’s handle that case in our addObserver function:
function scrollTrigger(selector, options = {}) {
let els = document.querySelectorAll(selector)
els = Array.from(els)
els.forEach(el => {
addObserver(el, options)
})
}
function addObserver(el, options) {
// Check if `IntersectionObserver` is supported
if(!('IntersectionObserver' in window)) {
// Simple fallback
// The animation/callback will be called immediately so
// the scroll animation doesn't happen on unsupported browsers
if(options.cb){
options.cb(el)
} else{
entry.target.classList.add('active')
}
// We don't need to execute the rest of the code
return
}
let observer = new IntersectionObserver((entries, observer) =>; {
entries.forEach(entry => {
if(entry.isIntersecting) {
if(options.cb) {
options.cb(el)
} else{
entry.target.classList.add('active')
}
observer.unobserve(entry.target)
}
})
}, options)
observer.observe(el)
}
// Example usages:
scrollTrigger('.intro-text')
scrollTrigger('.scroll-reveal', {
rootMargin: '-200px',
})
scrollTrigger('.loader', {
rootMargin: '-200px',
cb: function(el){
el.innerText = 'Loading...'
setTimeout(() => {
el.innerText = 'Task Complete!'
}, 1000)
}
})
Here’s that live demo again:
CodePen Embed Fallback
And that’s all for this little journey! I hope you enjoyed it and learned something new in the process.
You know that joke, “Two front-end developers walk into a bar and find they have nothing in common”? It’s funny, yet frustrating, because it’s true.
This article will present three different perspectives on accessibility in web design and development. Three perspectives that could help us bridge the great divide between users and designers/developers. It might help us find the common ground to building a better web and a better future.
Act 1
“I just don’t know how developers don’t think about accessibility.”
Someone once said that to me. Let’s stop and think about it for a minute. Maybe there’s a perspective to be had.
Think about how many things you have to know as a developer to successfully build a website. In any given day, for any given job position in web development, there are the other details of web development that come up. Meaning, it’s more than “just” knowing HTML, CSS, ARIA, and JavaScript. Developers will also learn other things over the course of their careers, based on what they need to do.
This could be package management, workspaces, code generators, collaboration tools, asset loading, asset management, CDN optimizations, bundle optimizations, unit tests, integration tests, visual regression tests, browser integration tests, code reviews, linting, formatting, communication through examples, changelogs, documentation, semantic versioning, security, app deployment, package releases, rollbacks, incremental improvements, incremental testing, continuous deployments, merge management, user experience, user interaction design, typography scales, aspect ratios for responsive design, data management, and… well, the list could go on, but you get the idea.
As a developer, I consider myself to be pretty gosh darn smart for knowing how to do most these things! Stop and consider this: if you think about how many people are in the world, and compare that to how many people in the world can build websites, it’s proportionally a very small percentage. That’s kind of… cool. Incredible, even. On top of that, think about the last time you shipped code and how good that felt. “I figured out a hard thing and made it work! Ahhhhh! I feel amazing!”
That kind of emotional high is pretty great, isn’t it? It makes me smile just to think about it.
Now, imagine that an accessibility subject-matter expert comes along and essentially tells you that not only are you not particularly smart, but you have been doing things wrong for a long time.
Ouch. Suddenly you don’t feel very good. Wrong? Me?? What??? Your adrenaline can even kick in and you start to feel defensive. Time to stick up for yourself… right? Time to dig those heels.
The cognitive dissonance can even be really overwhelming. It feels bad to find out that not only are you not good at the thing you thought you were really good at doing, but you’ve also been saying, “Screw you, who cares about you anyway,” to a whole bunch of people who can’t use the websites you’ve helped build because you (accidentally or otherwise) ignored that they even existed, that you ignored users who needed something more than the cleverness you were delivering for all these years. Ow.
All things considered, it is quite understandable to me that a developer would want to put their fingers in their ears and pretend that none of this has happened at all, that they are still very clever and awesome. That the one “expert” telling you that you did it wrong is just one person. And one person is easy to ignore.
— end scene.
Act 2
“I feel like I don’t matter at all.”
This is a common refrain I hear from people who need assistive technology to use websites, but often find them unusable for any number of reasons. Maybe they can’t read the text because the website’s design has ignored color contrast. Maybe there are nested interactive elements, so they can’t even log in to do things like pay a utility bill or buy essential items on their own. Maybe their favorite singer has finally set up an online shop but the user with assistive technology cannot even navigate the site because, while it might look interactive from a sighted-user’s perspective, all the buttons are divs and are not interactive with a keyboard… at all.
This frustration can boil over and spill out; the brunt of this frustration is often borne by the folks who are trying to deliver more inclusive products. The result is a negative feedback cycle; some tech folks opt out of listening because “it’s rude” (and completely missing the irony of that statement). Other tech folks struggle with the emotional weight that so often accompanies working in accessibility-focused design and development.
The thing is, these users have been ignored for so long that it can feel like they are screaming into a void. Isn’t anyone listening? Doesn’t anyone care? It seems like the only way to even be acknowledged is to demand the treatment that the law affords them! Even then, they often feel ignored and forgotten. Are lawsuits the only recourse?
It increasingly seems that being loud and militant is the only way to be heard, and even then it might be a long time before anything happens.
— end scene.
Act 3
“I know it doesn’t pass color contrast, but I feel like it’s just so restrictive on my creativity as a designer. I don’t like the way this looks, at all.”
I’ve heard this a lot across the span of my career. To some, inclusive design is not the necessary guardrail to ensure that our websites can be used by all, but rather a dampener on their creative freedom.
If you are a designer who thinks this way, please consider this: you’re not designing for yourself. This is not like physical art; while your visual design can be artistic, it’s still on the web. It’s still for the web. Web designers have a higher challenge—their artistic vision needs to be usable by everyone. Challenge yourself to move the conversation into a different space: you just haven’t found the right design yet. It’s a false choice to think that a design can either be beautiful or accessible; don’t fall into that trap.
— end scene.
Let’s re-frame the conversation
These are just three of the perspectives we could consider when it comes to digital accessibility.
We could talk about the project manager that “just wants to ship features” and says that “we can come back to accessibility later.” We could talk about the developer who jokes that “they wouldn’t use the internet if they were blind anyway,” or the one that says they will only pay attention to accessibility “once browsers make them do it.”
We could, but we don’t really need to. We know how these these conversations go, because many of us have lived these experiences. The project never gets retrofitted. The company pays once to develop the product, then pays for an accessibility audit, then pays for the re-write after the audit shows that a retrofit is going to be more costly than building something new. We know the developer who insists they should only be forced to do something if the browser otherwise disallows it, and that they are unlikely to be convinced that the inclusive architecture of their code is not only beneficial, but necessary.
So what should we be talking about, then?
We need to acknowledge that designers and developers need to be learning about accessibility much sooner in their careers. I think of it with this analogy: Imagine you’ve learned a foreign language, but you only learned that language’s slang. Your words are technically correct, but there are a lot of native speakers of that language who will never be able to understand you. JavaScript-first web developers are often technically correct from a JavaScript perspective, but they also frequently create solutions that leave out a whole lotta people in the end.
How do we correct for this? I’m going to be resolute here, as we all must be. We need to make sure that any documentation we produce includes accessible code samples. Designs must contain accessible annotations. Our conference talks must include accessibility. The cool fun toys we make to make our lives easier? They must be accessible, and there must be no excuse for anything less This becomes our new minimum-viable product for anything related to the web.
But what about the code that already exists? What about the thousands of articles already written, talks already given, libraries already produced? How do we get past that? Even as I write this article for CSS-Tricks, I think about all of the articles I’ve read and the disappointment I’ve felt when I knew the end result was inaccessible. Or the really fun code-generating tools that don’t produce accessible code. Or the popular CSS frameworks that fail to consider tab order or color contrast. Do I want all of those people to feel bad, or be punished somehow?
Nope. Not even remotely. Nothing good comes from that kind of thinking. The good comes from the places we already know—compassion and curiosity.
We approach this with compassion and curiosity, because these are sustainable ways to improve. We will never improve if we wallow in the guilt of past actions, berating ourselves or others for ignoring accessibility for all these years. Frankly, we wouldn’t get anything done if we had to somehow pay for past ignorant actions; because yes, we did ignore it. In many ways, we still do ignore it.
Real examples: the Google Developer training teaches a lot of things, but it doesn’t teach anything more than the super basic parts of accessibility. JavaScript frameworks get so caught up in the cleverness and complexity of JavaScript that they completely forget that HTML already exists. Even then, accessibility can still take a back seat. Ember existed for about eight years before adding an accessibility-focused community group (even if they have made a lot of progress since then). React had to have a completely different router solution created. Vue hasn’t even begun to publicly address accessibility in the core framework (although there are community efforts). Accessibility engineers have been begging for inert to be implemented in browsers natively, but it often is underfunded and de-prioritized.
But we are technologists and artists, so our curiosity wins when we read interesting articles about how the accessibility object model and how our code can be translated by operating systems and fed into assistive technology. That’s pretty cool. After all, writing machine code so it can talk to another machine is probably more of what we imagined we’d be doing, right?
The thing is, we can only start to be compassionate toward other people once we are able to be compassionate toward ourselves. Sure, we messed up—but we don’t have to stay ignorant. Think about that time you debugged your code for hours and hours and it ended up being a typo or a missing semicolon. Do you still beat yourself up over that? No, you developed compassion through logical thinking. Think about the junior developer that started to be discouraged, and how you motivated them to keep trying and that we all have good days and bad. That’s compassion.
Here’s the cool part: not only do we have the technology, we are literally the ones that can fix it. We can get up and try to do better tomorrow. We can make some time to read about accessibility, and keep reading about it every day until we know it just as well as we do other things. It will be hard at first, just like the first time we tried… writing tests. Writing CSS. Working with that one API that is forever burned in our memory. But with repetition and practice, we got better. It got easier.
Logically, we know we can learn hard things; we have already learned hard things, time and time again. This is the life and the career we signed up for. This is what gets us out of bed every morning. We love challenges and we love figuring them out. We are totally here for this.
What can we do? Here are some action steps.
Perhaps I have lost some readers by this point. But, if you’ve gotten this far, maybe you’re asking, “Melanie, you’ve convinced me, but what can I do right now?” I will give you two lists to empower you to take action by giving you a place to start.
Compassionately improve yourself:
Start following some folks with disabilities who are on social media with the goal of learning from their experiences. Listen to what they have to say. Don’t argue with them. Don’t tone police them. Listen to what they are trying to tell you. Maybe it won’t always come out in the way you’d prefer, but listen anyway.
Retro-fit your knowledge. Try to start writing your next component with HTML first, then add functionality with JavaScript. Learn what you get for free from HTML and the browser. Take some courses that are focused on accessibility for engineers. Invest in your own improvement for the sake of improving your craft.
Turn on a screen reader. Learn how it works. Figure out the settings—how do you turn on a text-only version? How do you change the voice? How do you make it stop talking, or make it talk faster? How do you browse by headings? How do you get a list of links? What are the keyboard shortcuts?
Bonus Challenge: Try your hand at building some accessibility-related tooling. Check out A11y Automation Tracker, an open source project that intends to track what automation could exist, but just hasn’t been created yet.
Incrementally improve your code
There are critical blockers that stop people from using your website. Don’t stop and feel bad about them; propel yourself into action and make your code even better than it was before.
So here we are, in a brand spanking new year—time for looking forward with fresh ideas and renewed hope for the year ahead. We are kicking off 2022 with a mixed bag and, we hope, something for everyone.
Whether you’re looking for inspiration to update your site or a fresh approach to work for a new client or want to spend a little while browsing around some corners of the internet you might not usually, welcome to the first collection of the year. Enjoy!
Justice Reskill
Justice Reskill offers a learning platform and support for people who have been through the justice system. Information is presented clearly in a positive, uplifting tone, emphasized by a bright color scheme and friendly type.
TBD Post
TBD Post’s site is fuss-free, clean, and pleasant to navigate. Work is well presented, in an organized way, with just the right amount of supplementary information.
Speedy
Speedy is an online business bank, and this is a pretty standard, slick fin-tech site for the most part. The added extra is that the five versions of the site–with the same content in each–have different color accents based on the flag of the specific country listed.
Nuka
This site for Nuka eternal stationery is a beautifully simple single page. The use of handwritten type in places adds an intimacy while emphasizing the nature of the products.
Omono
This site for online business management app Omono presents a lot of information clearly, and with a calmness projected by the use of blues and greys and subtle animation.
Pienso
A combination of bold type, a slightly tweaked red, green, and blue color scheme, and on-scroll animations makes this site for Pienso pop.
Maison Margiela
Maison Margiela fully embraces the digital alternative to a live catwalk with this blend of single video and edited clips.
Marie O’Shepherd
This portfolio site for book designer and art director Marie O’Shepherd takes a minimal approach and allows the work to take center stage.
Angry Ventures
Angry Ventures add personality and humor to their site to draw the user in and entertain, while their actual portfolio is only available on request.
Chapter One
Chapter One’s site has light and dark theme options and some engaging animated graphics.
Vesti il Futuro
Vesti il Futuro for Mani Tese uses comic book-style interactive graphics to raise awareness of issues surrounding the environment and fast fashion.
Gazelle No.1
Some scroll-activated video enlivens this single-page site for Gazelle’s No.1 model.
TROA
This site for creative agency Troa is an excellent example of the effectiveness of a monochrome color scheme, and there are some pleasing transitions too.
BDCC
BDCC’s site has a bold, slightly jumbled feel that works really well. The falling lozenge menu items are a nice feature.
Mekanism
This is a great example of a stylish website for an agency portraying itself as well-established and super polished.
Redbrick
Redbrick’s site has a youthful, vibrant feel with colors that change to match the product branding.
Accounting Box
This site for Accounting Box makes good use of split-screen swapping from a vertical split on desktop to a horizontal split on mobile. The animations are pleasing too.
François-Joseph Graf
The design for François-Joseph Graf’s site does the right thing by getting out of the way to avoid competing with the rather stunning products on show.
Monsta Cats
Monsta Cats is a site dedicated to community focussed NFTs. The site is suitably anarchic and fun to browse.
Bien Fondé
And finally, some customizable good wishes for the year ahead from digital agency Bien Fondé.
Every day design fans submit incredible industry stories to our sister-site, Webdesigner News. Our colleagues sift through it, selecting the very best stories from the design, UX, tech, and development worlds and posting them live on the site.
The best way to keep up with the most important stories for web professionals is to subscribe to Webdesigner News or check out the site regularly. However, in case you missed a day this week, here’s a handy compilation of the top curated stories from the last seven days. Enjoy!
There is a little legwork to do if you plan on using SVG in WordPress. For fair-enough reasons, WordPress doesn’t allow SVG out of the box. SVG is a markup syntax that has lots of power, including the ability to load other resources and run JavaScript. So, if WordPress were to blanket-ly allow SVG by default, users even with quite limited roles could upload SVG and cause problems, like XSS vulnerabilities.
But say that’s not a problem for your site and you just use SVG gosh darn it. First, let’s be clear what we mean by using SVG in WordPress: uploading SVG through the media uploader and using the SVG images within post content and as featured images.
There is nothing stopping you from, say, using SVG in your templates. Meaning inline or SVG files you link up as images in your template from your CSS or whatnot. That’s completely fine and you don’t need to do anything special for that to work in WordPress.
Taking matters into your own hands
What prevents you from using SVG in WordPress is that the Media Library Uploader rejects the file’s MIME type. To allow SVG in WordPress, you really just need this filter. This would go in your functions.php or a functionality plugin:
But the problem after that is that the SVG file usually won’t display correctly in the various places it needs to, like the Media Library’s image previews, the Featured Image widget, and possibly even the classic or Block Editor. I have a snippet of CSS that can be injected to fix this. But — and this is kinda why I’m writing this new post — that doesn’t seem to work for me anymore, which has got me thinking.
Plugins for using SVG in WordPress
I used to think, eh, why bother, it’s so little code to allow this might that I may as well just do it myself with the function. But WordPress, of course, has a way of shifting over time, and since supporting SVG isn’t something WordPress is going to do out of the box, this is actually a great idea for a plugin to handle. That way, the SVG plugin can evolve to handle quirks as WordPress evolves and, theoretically, if enough people use the SVG plugin, it will be maintained.
So, with that, here are a couple of plugin recommendations for using SVG in WordPress.
This is the one I’ve been using lately and it seems to work great for me.
I just install it, activate it, and do nothing else. It does have a settings screen, but I don’t need any of those things. I really like how it asks you if it’s OK to load additional CSS on the front-end (for me, it’s not OK, so I leave it off) — although even better would be for the plugin to show you what it’s going to load so you can add it to your own CSS if you want.
The setting to restrict uploading SVG in WordPress to admins is smart, although if you want to be more serious about SVG safety, you could use this next plugin instead…
This one hasn’t been updated in years, but it goes the extra mile for SVG safety in that it literally sanitizes SVG files as you upload them, and even optimizes them while it adds the SVG in WordPress.
We have fairly tight editorial control over authors and such here on this site, so the security aspects of this SVG plugin aren’t a big worry to me. Plus, I like to be in charge of my own SVG optimization, so this one isn’t as perfect for me, though I’d probably recommend it to a site with less technical expertise at the site owner level.
Looks like there is Easy SVG Support as well, but it doesn’t seem to be as nice as the Support SVG plugin and hasn’t been updated recently, so I can’t recommend that.
What plugins have you successfully tried for using SVG in WordPress? Any recommendations you’d like to add?