Eric Bailey – CSS-Tricks https://css-tricks.com Tips, Tricks, and Techniques on using Cascading Style Sheets. Wed, 02 Mar 2022 19:41:19 +0000 en-US hourly 1 https://wordpress.org/?v=6.5.5 https://i0.wp.com/css-tricks.com/wp-content/uploads/2021/07/star.png?fit=32%2C32&ssl=1 Eric Bailey – CSS-Tricks https://css-tricks.com 32 32 45537868 “Evergreen” Does Not Mean Immediately Available https://css-tricks.com/evergreen-does-not-mean-immediately-available/ https://css-tricks.com/evergreen-does-not-mean-immediately-available/#comments Tue, 01 Feb 2022 15:38:41 +0000 https://css-tricks.com/?p=362169 I have a coworker who is smart, capable, and technologically-literate. Like me, they work on the web full-time.

When they are sharing their screen in a meeting, I find myself disassociating fixating on the red update button in their copy …


“Evergreen” Does Not Mean Immediately Available originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
I have a coworker who is smart, capable, and technologically-literate. Like me, they work on the web full-time.

When they are sharing their screen in a meeting, I find myself disassociating fixating on the red update button in their copy of Chrome.

An angry red button labeled "Update".

Clicking this button would start the process to update Chrome to the latest stable version.

I’ve asked some probing questions about how frequently they reboot, which would also force Chrome to update upon relaunch. That’s the point of an “evergreen” browser, right? It’s easy to make sure you’re always using the latest and greatest version.

It turns out they prefer to wait until they absolutely have to because of the disruption it would cause in their daily workflow. Their behavior makes sense. They are prioritizing the quality of their overall computing experience, rather than catering to the demands of one specific app.

Like me, my coworker also uses a top-of-the-line laptop to get things done. This means that the laptop can go for months without needing a reboot. Ironically, this might be a situation where a craptop is conditionally forced to have a faster browser upgrade path.

Evergreen browsers

Before the advent of evergreen browsers, you would need to go to the manufacturer’s website and manually download and install the update. Prior to that you had to use a CD or floppy disk.

A floppy disk used for installing Netscape Navigator.
Source: Floppy Disk of Netscape Navigator. Toshihiro Oimatsu, CC BY 2.0, via Wikimedia Commons.

By contrast, an evergreen browser is any browser that can automatically update itself. By this, I mean the browser will automatically pull down the code required to add new features and fix bugs once it has been released by the browser’s manufacturer. The update itself occurs with:

  • a prompt shown to the person using the browser that triggers an application restart,
  • a download that happens in the background and gets applied on application restart, or
  • on device restart.

The browsers themselves

Nearly all major browsers are evergreen. This includes Google Chrome, Microsoft Edge, and Mozilla Firefox.

Apple Safari is quasi-evergreen. By this I mean it automatically receives updates, but awkwardly requires them to be done via the macOS operating system update interface, where other system-wide updates are located.

A sub-window floating over macOS’s Software Update preference pane. It shows options for updating macOS Big Sur to version 11.6.2, Command Line Tools for Xcode to version 13.2, Safari to version 15.2, and Safari Technology Preview to version 137, all of which are considered Evergreen software. Screenshot.

If you haven’t been paying attention, the Safari team has been making a ton of improvements to their browser in the past few months—I’d love to see them continue with this trend by making the browser update path decoupled from existing macOS and iOS upgrade workflows.

The situation

With the actual, final, no-seriously-we-mean-it-this-time death of Internet Explorer, evergreen browsers are now the main consideration for desktop and laptop browsers. This is great! It means we can spend a lot less time fretting about who can use what.

Spending less time does not mean spending no time, however.

Delayed effects

Support from all evergreen browsers on caniuse.com does not necessarily mean support exists on the device a person is using—updates that have been pushed out don’t automatically get instantly applied.

Because of these two factors, I advocate for tempering your excitement with some restraint. It can be very tempting to rush and use the new and the shiny. Believe me, I’m not exempt from this urge—CSS is about to go from great to amazing, and the urge to use new features is very real.

Instead, wait a bit. Work with the platform’s ability to create progressively enhanced experiences with CSS and JavaScript.

Leverage the platform

The web is really good at being resilient, provided you work with its grain.

Both CSS and JavaScript have the ability to conditionally serve up experiences for browsers that support new features while providing alternatives for those that don’t.

Instead of looking at the support table for something on caniuse.com and thinking, “I wish more browsers supported this feature so that I could use it!”, you can instead think “I’m going to use this feature today, but treat it as an experimental feature.”

—Jeremy Keith, “Continuous partial browser support”

JavaScript

You can use JavaScript to query whether or not a browser supports a certain feature. For example, the Navigator interface provides a mechanism for querying a user agent’s capabilities.

if (!(“geolocation” in navigator)) {
  // Logic if a user's current geographic location isn't available
} else {
  // Logic that is based on a user's current geographic location
}

In this example, I am inverting a request for support for a browser’s Geolocation interface. Although its syntax is initially a little confusing to parse, it helps emphasize a progressive enhancement approach.

Assume geolocation functionality isn’t supported to start and provide a way to accommodate the person using this browser (say manually typing in a ZIP Code, etc.). With this use case covered, you can then confidently build an experience for browser that support geolocation.

This thinking also extends to all other browser features and capabilities.

CSS

Like most other programming languages, CSS also lets us use if-like statements.

For example, the @supports at rule allows you to create a conditional statement that targets whether or not a browser supports something, and then apply logic to it. Browsers that honor the feature will utilize those styles, and browsers that don’t will ignore them. It is a concise, clever, adaptable solution.

.component {
  /* Base appearance */
}

@supports (grid-template-columns: subgrid;) {
  .component {
    /* Styling and positioning enhancement tweaks if subgrid is supported */
  }
}

For this example, this progressive enhancement approach ensures that a component’s content and functionality is preserved for every browser, but only creates fancy layouts for browsers capable of supporting them.

When can I remove this stuff?

Yes, this approach adds more code, and more code means more complexity and maintenance. But it’s very important code. You might even call it technical debt and you’d be correct. But technical debt can be a good thing, like an investment in the future.

You may want to remove that complexity when it’s no longer needed. Knowing the right time to do that in this age of evergreen browsers is difficult, but I have a couple of suggestions:

Patience is a virtue

In terms of waiting, I’d advise a conservative 6-ish months from release of a new feature before even beginning to think about investigating if you can remove feature detection. This accounts for:

  • Reboots
  • Update procrastinators
  • Update avoiders
  • Hardware refresh cycles
  • Corporate update policies,
  • etc.

I would also say that rough six month timeframe is in terms of a general, global web audience. This guesstimate changes if you cater to a specialized audience. The way to know who you actually serve? Analytics, yes, but also talking to people.

Maybe don’t

Remember: survivor bias is real. Is the brand new feature you’re using preventing someone from using your website or web app? I say this because some people:

There isn’t a single, specific device, browser, and person we cater to when creating a web experience. Websites and web apps need to adapt to a near-infinite combination of these circumstances to be effective. This adaptability is a large part of what makes the web such a successful medium.

Consider doing the hard work to make it easy and never remove feature queries and @supports statements. This creates a robust approach that can gracefully adapt to the past, as well as the future.

The future is uncertain

We’re long past the age of desktop computers. Browsers are showing up in more and more places: phones, tablets, watches, ebook readers, digital cameras, kiosks, televisions, home assistants, vending machines, photo frames, graphing calculators, ATMs, point of sale terminals, exercise equipment, video game consoles, billboards, refrigerators, virtual reality, and cars.

Who knows what devices browsers will be included with in the future, or what capabilities they’ll have? Future-proof (and, er, past-proof) yourself with an approach that accommodates it.


Thank you to to Jim Nielsen for their feedback.


“Evergreen” Does Not Mean Immediately Available originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/evergreen-does-not-mean-immediately-available/feed/ 10 362169
Test Your Product on a Crappy Laptop https://css-tricks.com/test-your-product-on-a-crappy-laptop/ https://css-tricks.com/test-your-product-on-a-crappy-laptop/#comments Tue, 07 Dec 2021 19:01:05 +0000 https://css-tricks.com/?p=357637 There is a huge and ever-widening gap between the devices we use to make the web and the devices most people use to consume it. It’s also no secret that the average size of a website is huge, and …


Test Your Product on a Crappy Laptop originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
There is a huge and ever-widening gap between the devices we use to make the web and the devices most people use to consume it. It’s also no secret that the average size of a website is huge, and it’s only going to get larger.

What can you do about this? Get your hands on a craptop and try to use your website or web app.

Craptops are cheap devices with lower power internals. They oftentimes come with all sorts of third-party apps preinstalled as a way to offset its cost—apps like virus scanners that are resource-intensive and difficult to remove. They’re everywhere, and they’re not going away anytime soon.

As you work your way through your website or web app, take note of:

  • what loads slowly,
  • what loads so slowly that it’s unusable, and
  • what doesn’t even bother to load at all.

After that, formulate a plan about what to do about it.

The industry average

At the time of this post, the most common devices used to read CSS-Tricks are powerful, modern desktops, laptops, tablets, and phones with up-to-date operating systems and plenty of computational power.

Granted, not everyone who makes websites and web apps reads CSS-Tricks, but it is a very popular industry website, and I’m willing to bet its visitors are indicative of the greater whole.

In terms of performance, the qualities we can note from these devices are:

  • powerful processors,
  • generous amounts of RAM,
  • lots of storage space,
  • high-quality displays, and most likely a
  • high-speed internet connection

Unfortunately, these qualities are not always found in the devices people use to access your content.

Survivor bias

British soldiers in World War I were equipped with a Brodie helmet, a steel hat designed to protect its wearer from overhead blasts and shrapnel while conducting trench warfare. After its deployment, field hospitals saw an uptick in soldiers with severe head injuries.

A grizzled British soldier smiling back at the camera, holding a Brodie helmet with a large hole punched in it. Black and white photograph.
Source: History Daily

Because of the rise in injuries, British command considered going back to the drawing board with the helmet’s design. Fortunately, a statistician pointed out that the dramatic rise in hospital cases was because people were surviving injuries that previously would have killed them—before the introduction of steel the British Army used felt or leather as headwear material.

Survivor bias is the logical error that focuses on those who made it past a selection process. In the case of the helmet, it’s whether you’re alive or not. In the case of websites and web apps, it’s if a person can load and use your content.

https://twitter.com/estellevw/status/1027305654501826560

Lies, damned lies, and statistics

People who can’t load your website or web app don’t show up as visitors in your analytics suite. This is straightforward enough.

However, the “use” part of “load and use your content” is the important bit here. There’s a certain percentage of devices who try to access your product that will be able to load enough of it to register a hit, but then bounce because the experience is so terrible it is effectively unusable.

Yes, I know analytics can be more sophisticated than this. But through the lens of survivor bias, is this behavior something your data is accommodating?

Blame

It’s easy to go out and get a cheap craptop and feel bad about a slow website you have no control over. The two real problems here are:

  1. Third-party assets, such as the very analytics and CRM packages you use to determine who is using your product and how they go about it. There’s no real control over the quality or amount of code they add to your site, and setting up the logic to block them loading their own third-party resources is difficult to do.
  2. The people who tell you to add these third-party assets. These people typically aren’t aware of the performance issues caused by the ask, or don’t care because it’s not part of the results they’re judged by.

What can we do about these two issues? Tie abstract, one-off business requests into something more holistic and personal.

Bear witness

I know of organizations who do things like “Testing Tuesdays,” where moderated usability testing is conducted every Tuesday. You could do the same for performance, even thread this idea into existing usability testing plans—slow websites aren’t usable, after all.

The point is to construct a regular cadence of seeing how real people actually use your website or web app, using real world devices. And when I say real world, make sure it’s not just the average version of whatever your analytics reports says.

Then make sure everyone is aware of these sessions. It’s a powerful thing to show a manager someone trying to get what they need, but can’t because of the choices your organization has made.

Craptop duty

There are roughly 260 work days in a year. That’s 260 chances to build some empathy by having someone on your development, design, marketing, or leadership team use the craptop for a day.

You can run Linux from a Windows subsystem to run most development tooling. Most other apps I’m aware of in the web-making space have a Windows installer, or can run from a browser. That should be enough to do what you need to do. And if you can’t, or it’s too slow to get done at the pace you’re accustomed to, well, that’s sort of the point.

Craptop duty, combined with usability testing with a low power device, should hopefully be enough to have those difficult conversations about what your website or web app really needs to load and why.

Don’t tokenize

The final thing I’d like to say is that it’s easy to think that the presence of a lower power device equals the presence of an economically disadvantaged person. That’s not true. Powerful devices can become circumstantially slowed by multiple factors. Wealthy individuals can, and do, use lower-power technology.

Perhaps the most important takeaway is poor people don’t deserve an inferior experience, regardless of what they are trying to do. Performant, intuitive, accessible experiences on the web are for everyone, regardless of device, ability, or circumstance.


Test Your Product on a Crappy Laptop originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/test-your-product-on-a-crappy-laptop/feed/ 10 357637
CSS is a Strongly Typed Language https://css-tricks.com/css-is-a-strongly-typed-language/ https://css-tricks.com/css-is-a-strongly-typed-language/#comments Tue, 13 Apr 2021 14:22:04 +0000 https://css-tricks.com/?p=337648 One of the ways you can classify a programming language is by how strongly or weakly typed it is. Here, “typed” means if variables are known at compile time. An example of this would be a scenario where an integer …


CSS is a Strongly Typed Language originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
One of the ways you can classify a programming language is by how strongly or weakly typed it is. Here, “typed” means if variables are known at compile time. An example of this would be a scenario where an integer (1) is added to a string containing an integer ("1"):

result = 1 + "1";

The string containing an integer could have been unintentionally generated from a complicated suite of logic with lots of moving parts. It could also have been intentionally generated from a single source of truth.

Despite the connotations that the terms “weak” and “strong” imply, a strongly-typed programming language isn’t necessarily better than a weakly-typed one. There may be scenarios where flexibility is needed more than rigidity, and vice-versa. As with many aspects of programming, the answer is dependent on multiple external contexts (i.e “it depends”).

The other interesting bit is there is no formal definition of what constitutes strong or weak typing. This means that perceptions of what is considered a strongly or weakly-typed language differ from person to person, and may change over time.

TypeScript

JavaScript is considered a weakly-typed language, and this flexibility contributed to its early adoption on the web. However, as the web has matured and industrialized, use cases for JavaScript have become more complicated.

Extensions like TypeScript were created to help with this. Think of it as a “plugin” for JavaScript, which grafts strong typing onto the language. This helps programmers navigate complicated setups. An example of this could be a data-intensive single page application used for e-commerce.

TypeScript is currently very popular in the web development industry, and many new projects default to using TypeScript when first setting things up.

Compile time

Compile time is the moment when a programming language is converted into machine code. It is a precursor to runtime, the moment when machine code is performed by the computer.

As with many things on the web, compile time is a bit tricky. A setup that utilizes TypeScript will stitch together component pieces of JavaScript code and compile them into a single JavaScript file for the browser to read and run.

The time when component pieces compile is when they are all combined. TypeScript serves as a kind of overseer, and will yell at you if you try to break the typed conventions you have set up for yourself before combination occurs.

A tooltip that reads, “var content: any. Property ‘content’ does not exist on type ‘PropsWithChildren<Props>’. ts(2339). View Problem (Option F8). No quick fixes available. Tooltip is pointing towards an argument called “content.”
A sample TypeScript error in VS Code.

The stitched-together JavaScript file is then ingested by the browser, which has its own compile time. Browser compile time is highly variable, depending on:

  • The device the browser is on,
  • What other work the browser is doing, and
  • What other work the device’s other programs are doing.

TypeScript isn’t directly used by the browser, but its presence is felt. JavaScript is fragile. TypeScript helps with this fragility by trying to prevent errors upstream in the code editor. This lessens the chance errors occur in the JavaScript read by the browser — errors that would cause JavaScript to stop functioning on the website or web app a person is using.

CSS

CSS is a declarative, domain-specific programming language. It is also strongly typed. For the most part, values in CSS stay declared as authored. If a value is invalid the browser throws the entire property away.

Types in CSS

The list of types in CSS is thorough. They are:

Textual types
  • Globally-scoped keywords:
    • initial
    • inherit
    • unset
    • revert
  • Custom identifies, which are specifically used for things, such as providing a grid-area name
  • Strings, such as, "hello"
  • URLs, such as https://css-tricks.com/
  • Dashed idents (--), which are used to create custom properties (more on this in a bit)
Numeric types
  • Integers, which are decimal numbers 0–9
  • Real numbers, such as 3.14
  • Percentages, such as 25%
  • Dimensions, a number with a unit appended to it such as (100px or 3s)
  • Ratios, such as 16/9
  • flex, a variable length for CSS grid calculation
Quantity types
  • Lengths:
  • Angles, such as 15deg
  • Time, such as 250ms
  • Frequencies, such 16Hz
  • Resolution, such as 96dpi

Dimensions and lengths might seem similar, but dimensions can contain percentages and lengths cannot.

Color types
  • Keywords:
    • Named colors, such as papayawhip
    • transparent
    • currentColor
  • RGB colors:
    • Hexidecimal notation, such as #FF8764
    • RGB/RGBa notation, such as rgba(105, 221, 174, 0.5)
  • HSL/HSLA colors, such as hsl(287, 76%, 50%)
  • System colors, such as ButtonText
Image types
  • Image, which is a URL reference to an image file or gradient
  • color-stop-list, a list of two or more color stops, used for gradient notion
  • linear-color-stop, a color and length expression used to indicate a gradient color stop
  • linear-color-hint, a length percentage used to interpolate color
  • ending-shape, which uses a keyword of either circle or ellipse for radial gradients
2D positioning types
  • Keywords:
    • top
    • right
    • bottom
    • left
    • center
  • A percentage length, such as 25%

Programming in CSS

The bulk of programming in CSS is authoring selectors, then specifying a suite of properties and their requisite values. Collections of selectors give content a visual form, much as how collections of JavaScript logic creates features.

CSS has functions. It can perform calculation, conditional logic, algorithmic expressions, state, and mode-based behavior. It also has custom properties, which are effectively CSS variables that allow values to be updated dynamically. Heck, you can even solve fizzbuzz with CSS.

Like other programming languages, there is also a “meta” layer, with different thoughts and techniques on how to organize, manage and maintain things.

Throwing errors

Unlike other programming languages where code largely exists under the hood, CSS is highly visual. You won’t see warnings or errors in the console if you use an invalid value for a property declaration, but you will get visuals that don’t update the way you anticipated.

The reason for this is that CSS is resilient. When visuals don’t update because of a misconstructed declaration, CSS is prioritizing, ensuring content can be shown at all costs and will render every other valid declaration it possibly can. This is in keeping with the design principles of the language, the principles of the platform, and the overarching goals of the web’s mission.

Proof

Let’s demonstrate how strong typing in CSS keeps the guardrails on in three examples: one with a straightforward property/value declaration, one with calculation, and one with redefining a custom property.

Example 1: Straightforward property/value declaration

See the Pen Basic example by Eric Bailey (@ericwbailey) on CodePen.

For this example, the browser does not understand the banner’s border-style “potato” declaration. Note that the other .banner class selector property/value declarations are honored by the browser and rendered, even though border-style has a type mismatch. This is an example of how resilient CSS is.

The border-style declaration is expecting one of the following textual style types:

  • Globally-scoped keywords, or a
  • Dashed indent for a custom property.

If we update border-style to use a valid, typed value of dotted, the browser will render the border!

Example 2: Calculation

The calc() function in CSS allows us to take two arguments and an operator to return a calculated result. If one of the arguments doesn’t use a valid type, the calculation won’t work.

In this Pen, the p selector’s font-size property is expecting a value with a numeric dimension type (e.g. 1.5rem). However, the calculation function produces an invalid type value for the font-size property. This is because the second argument in the calc() function is a string ("2rem"), and not a numeric dimension type.

Because of this, the paragraph’s font size falls back to the next most applicable parent node — the font-size of 1.5rem declared on the body element.

This is a bit in the weeds, but worth pointing out: Combining two custom properties in a calc() function can cause errors. While both custom properties may be valid on their own, calc() will not accept dashed indent textual types. Think of a scenario where we might try multiplying custom properties that contain mismatched units, e.g. --big: 500px and --small: 1em.

Example 3: Redefined custom property

Like JavaScript variables, custom property values can be redefined. This flexibility allows for things like easily creating dark mode color themes.

In the :root selector of this CodePen, I have set a custom property of --color-cyan, with a value of #953FE3. Then, in the .square class, I have updated the --color-cyan custom property’s value to be top. While top is a valid, typed value, it is not a type that background-color honors.

Notice that the updated custom property is scoped to .square, and does not affect other usages, such as the right-hand border on the phrase “Don’t play to type.” And if you remove the redefined custom property from .square, you’ll see the cyan background color snap back in.

While this is a bit contrived, it serves as an example of how redefining custom properties can get away from you if you’re not careful.

This phenomenon can be found in projects with poor communication, larger CSS codebases, and situations where CSS preprocessors are used to construct custom properties at scale.

Tooling

With the gift of hindsight, I think a lack of console warnings for CSS is a flaw, and has contributed to a lot of the negative perceptions about the language.

Hoping a developer will notice a potentially tiny visual change is too big an ask, and does not meet them where they are for most of their other daily tools. There are a couple of initiatives I’m aware of that try to address this.

First is stylelint, a linter made specifically to deal with CSS and CSS-like preprocessing languages. stylelint can integrate with code editors, task runners, command line tools, and GitHub actions to help keep your CSS under control. This allows it to meet developers where they already are.

A tooltip that reads, “var content: any. Property ‘content’ does not exist on type ‘PropsWithChildren<Props>’. ts(2339). View Problem (Option F8). No quick fixes available. Tooltip is pointing towards an argument called “content.”
stylelint terminal output.

Second is Firefox’s excellent suite of CSS inspection options in its Developer Tools. In particular, I would like to call attention to its ability to identify unused CSS. This is extremely helpful for identifying selectors that may have run afoul of a type mismatch.

Tooltip attached to an unused selector in the Developer panel. The tooltip reads, “vertical-align has no effect on this element since it’s not an inline or table-cell element. Try adding display: inline or display: table-cell. Learn more. Screenshot.”
Firefox Developer edition

Wrapping up

CSS has been strongly typed for as long as it has been a programming language, and as a programming language it has been around for a long time. It’s also done a lot of growing up lately. If you haven’t checked in, there are some new, amazing features available.

As strongly-typed JavaScript becomes more popular, it is my hope that it helps developers become more comfortable with the firm, yet flexible approach of CSS.


Thank you to Miriam Suzanne for her feedback.


CSS is a Strongly Typed Language originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/css-is-a-strongly-typed-language/feed/ 11 337648
Representation Matters https://css-tricks.com/representation-matters/ Tue, 15 Dec 2020 00:05:00 +0000 https://css-tricks.com/?p=330298 This year I had the pleasure of re-launching The Accessibility Project. I spend a lot of time researching and writing about accessibility and inclusive design, so this felt like the cumulation of a lot of that effort. The site …


Representation Matters originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
This year I had the pleasure of re-launching The Accessibility Project. I spend a lot of time researching and writing about accessibility and inclusive design, so this felt like the cumulation of a lot of that effort. The site now uses all sorts of cool web features like CSS Grid, @supports, and media features, aria-current, Service Workers, and Eleventy. But that’s really not the important bit.

The important bit I learned this year is the same thing I learn over and over again: When it comes to disability, representation matters.

In my exploration, the importance of representation is a layered truth I find myself re-internalizing as I learn more about the different communities that make up the accessibility space. I am extraordinarily thankful to be welcomed into these communities, and grateful to be able to participate in them. 

We must, however, acknowledge that it is a lot easier for me to enter into these communities than the other way around. Disabled people frequently face many barriers towards representation in many industries, ours included. Considering that, I thought I’d ask disabled people who work on the web what they’ve learned. Here’s what they told me:

Developer Jennilee Rose comments on increased awareness of accessibility in the framework space:

As an advocate for accessibility in web design/development, something I’ve noticed (not exactly learned per-say, but a trend I’ve seen) is that in probably the last 2-3 years there has been a shift in prioritizing accessibility in JavaScript libraries. I think some of it is that there are devs out there like me who care and are holding devs who create these libraries accountable and helping to create change.

Software Engineer Nadhim Orfali comments on their experience working with design systems, accessibility, and documentation:

After a company-wide shift to Vue, it’s easier and faster for teams to adopt the design system. Due to the release of scoped packages along with CI/CD architecture and intertwined with documentation, the process is more streamlined with most of the accessibility built-in. I’m seeing teams much more aware and interested in all matters relating to accessibility, which can only be a good thing!

User experience designer Francis C. Rupert comments on how quarantine has affected everyone:

In 2020 everyone was struck with a shared Situational Disability by everyone wearing a mask. Hearing loss isn’t necessarily always about volume, but speech discrimination. We collectively lost the ability to distinguish between consonants and vowels, and everyone else sounds garbled through their masks.

Speaking of quarantine, web designer Jen Diaz tells us about some benefits that come with remote work becoming mainstream:

Clients are super-keen to work with remote business partners now that they have little or no choice not to. Which is great — it truly levels the playing field. On a Zoom call, nobody knows that my hands are shaped like lobster claws or that I physically cannot participate in the company bowling league — both things that have raised eyebrows for me at in-office jobs.

Anne Berlin, technical SEO and web manager, also comments on some remote work benefits:

I don’t have to worry about someone coming in with strong fragrance, which can send my brain into haywire. I can control the light level of the room and brightness level of my monitors, and a bit more control over the noise level.

It’s not all good vibes, however. Web developer Olu also chimes in about remote work: 

Quarantine has also shown how adaptable companies can be when their backs are against the wall. It’s funny how disabled people can ask for accommodations for years and then when they have no choice suddenly these accommodations are becoming permanent for everyone. 

Anne also mentions:

Pressure to pass as abled due to ignorance about “invisible” disabilities or lack of proactively inclusive culture for a range of things including cognitive styles, or issues with overstimulation.

Disability is more than physical access. Managing Director Josh Clayton mentions the cognitive fatigue that comes with framework churn:

The continued use of React is concerning. The JavaScript ecosystem is fragmented, with a lot of people doing a lot of work and nobody producing anything new. I don’t mind investing in technology where I feel like I’m getting something. There’s just so much churn, I don’t bother to keep up. I would like to think it’s not sacrificing future employability if I was going to look for a new job, but when it comes to other person’s money, there’s the “newshiny,” or “is this actually the right thing you should be doing right now?”

Developer EJ Mason doesn’t mince words:

What I have learned about the industry is that it is unrepentantly ableist.

While I’m happy to see progress being made on some fronts, we need to understand that doing technical work to make websites accessible is only part of the picture. We need to realize that usable products can be created in exclusionary spaces. Only by including disabled people in the product creation process can we truly improve as an industry.


Thank you to Jennilee Rose, Nadhim Orfali, Francis C. Rupert, Jen Diaz, Anne Berlin, Olu, Josh Clayton, EJ Mason, and everyone else who shared their experiences with me.


Representation Matters originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
330298
Focus management and inert https://css-tricks.com/focus-management-and-inert/ https://css-tricks.com/focus-management-and-inert/#comments Mon, 19 Oct 2020 13:56:27 +0000 https://css-tricks.com/?p=323076 Many forms of assistive technology use keyboard navigation to understand and take action on screen content. One way of navigating is via the Tab key. You may already be familiar with this way of navigating if you use it to …


Focus management and inert originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
Many forms of assistive technology use keyboard navigation to understand and take action on screen content. One way of navigating is via the Tab key. You may already be familiar with this way of navigating if you use it to quickly jump from input to input on a form without having to reach for your mouse or trackpad.

Tab will jump to interactive elements in the order they show up in the DOM. This is one of the reasons why it is so important that the order of your source code matches the visual hierarchy of your design.

The list of interactive elements that are tabbable is:

An interactive element gains focus when:

  • It has been navigated to via the Tab key, 
  • it is clicked on, following an anchor that links to another focusable element,
  • or focus is programmatically set through element.focus() in JavaScript.

Focus is analogous to hovering over an element with your mouse cursor, in that you’re identifying the thing you want to activate. It’s also why visually obvious focus styles are so important.

Focus indication moving through a homepage wireframe. It starts on the logo, moves to products, then services, then careers, blog, contact, and stops on a Learn more button.

Focus management

Focus management is the practice of coordinating what can and cannot receive focus events. It is one of the trickier things to do in front-end development, but it is important for making websites and web apps accessible.

Good practices for focus management

99% of the time, you want to leave focus order alone. I cannot stress this enough. 

Focus will just work for you with no additional effort required, provided you’re using the <button> element for buttons, the anchor element for links, the <input> element for user input, etc.

There are rare cases where you might want to apply focus to something out of focus order, or make something that typically can’t receive focus events be focusable. Here are some guidelines for how to go about it in an accessible, intuitive to navigate way:

Do: learn about the tabindex attribute

tabindex allows an element to be focused. It accepts an integer as a value. Its behavior changes depending on what integer is used.

Don’t: Apply tabindex="0" to things that don’t need it

Interactive elements  that can receive keyboard focus (such as the <button> element) don’t need to have the tabindex attribute applied to them.  

Additionally, you don’t need to declare tabindex on non-interactive elements to ensure that they can be read by assistive technology (in fact, this is a WCAG failure if no role and accessible name is present). Doing so actually creates an unexpected and difficult to navigate experience for a person who uses assistive technology — they have other, expected ways to read this content.

✅ Do: Use tabindex="-1" for focusing with JavaScript

tabindex="-1" is used to create accessible interactive widgets with JavaScript.

A declaration of tabindex="-1" will make an element focusable via JavaScript or click/tap. It will not, however, let it be navigated to via the Tab key.

❌ Don’t: Use a positive integer as a tabindex value

This is a serious antipattern. Using a positive integer will override the expected tab order, and create a confusing and disorienting experience for the person trying to navigate your content. 

One instance of this is bad enough. Multiple declarations is a total nightmare. Seriously: don’t do it.

❌ Don’t: Create a manual focus order

Interactive elements can be tabbed to just by virtue of being used. You don’t need to set a series of tabindex attributes with incrementing values on every interactive element in the order you think the person navigating your site should use. You’ll let the order of the elements in the DOM do this for you instead.

Focus trapping

There may be times where you need to prevent things from being focused. A good example of this is focus trapping, which is the act of conditionally restricting focus events to an element and its children.

Focus trapping is not to be confused with keyboard traps (sometimes referred to as focus traps). Keyboard traps are situations where someone navigating via keyboard cannot escape out of a widget or component because of a nasty loop of poorly-written logic.

A practical example of what you would use focus trapping for would be for a modal:

Focus indication moving through a homepage wireframe and opening a modal to demonstrate focus trapping. Inside the modal are tab stops for the modal container, a video play button, a cancel button, a purchase button, and a close button. After the modal is closed focus is returned to the button that triggered the modal.

Why is it important?

Keeping focus within a modal communicates its bounds, and helps inform what is and is not modal content — it is analogous to how a sighted person can see how a modal “floats” over other website or web app content. This is important information if: 

  • You have low or no vision and rely on screen reader announcements to help communicate the shift in interaction mode.
  • You have low vision and a magnified display, where focusing outside of the bounds of the modal may be confusing and disorienting.
  • You navigate solely via keyboard and could otherwise tab out of the modal and get lost on the underlying page or view trying to get back into the modal.

How do you do it?

Reliably managing focus is a complicated affair. You need to use JavaScript to:

  1. Determine the container elements of all focusable elements on the current page or view.
  2. Identify the bounds of the trapped content, including the first and last focusable item.
  3. Remove both interactivity and discoverability from anything identified as focusable that isn’t within that set of trapped content.
  4. Move focus into the trapped content.
  5. Listen for events that signals dismissing the trapped content (save, cancel, dismissal/hitting the Esc key, etc.).
  6. Dismiss the trapped content area when triggered by a pertinent event.
  7. Restore previously removed interactivity. 
  8. Move focus back to the interactive element that triggered the trapped content. 

Why do we do it?

I’m not going to lie: this is all tricky and time-consuming to do. However, focus management and a sensible, usable focus order is a Web Content Accessibility Guideline. It’s important enough that it’s considered part of an international, legally-binding standard about usability.

Tabbable and discoverable

There’s a bit of a trick to removing both discoverability and interactivity. 

Screen readers have an interaction mode that allows them to explore the page or view via a virtual cursor. The virtual cursor also lets the person using the screen reader discover non-interactive parts of the page (headings, lists, etc.). Unlike using Tab and focus styles, the virtual cursor is only available to people using a screen reader.

When you are managing focus, you may want to restrict the ability for the virtual cursor to discover content. For our modal example, this means preventing someone from accidentally “breaking out” of the bounds of the modal when they’re reading it.

Discoverability can be suppressed via a judicious application of aria-hidden="true". However, interactivity is a little more nuanced.

Enter inert

The inert attribute is a global HTML attribute that would make removing, then restoring the ability of interactive elements to be discovered and focused a lot easier. Here’s an example of how it would work:

<body>
  <div 
    aria-labelledby="modal-title"
    class="c-modal" 
    id="modal" 
    role="dialog" 
    tabindex="-1">
    <div role="document">
      <h2 id="modal-title">Save changes?</h2>
      <p>The changes you have made will be lost if you do not save them.<p>
      <button type="button">Save</button>
      <button type="button">Discard</button>
    </div>
  </div>
  <main inert>
    <!-- ... -->
  </main>
</body>

I am deliberately avoiding using the <dialog> element for the modal due to its many assistive technology support issues.

inert has been declared on the <main> element following a save confirmation modal. What this means that all content contained within <main> cannot receive focus nor be clicked. 

Focus is restricted to inside of the modal. When the modal is dismissed, inert can be removed from the <main> element. This way of handling focus trapping is far easier compared to existing techniques.

Remember: A dismissal event can be caused by the two buttons inside our modal example, but also by pressing Esc on your keyboard. Some modals also let you click outside of the modal area to dismiss, as well.

Support for inert

The latest versions of Edge, Chrome, and Opera all support inert when experimental web platform features are enabled. Firefox support will also be landing soon! The one outlier is both desktop and mobile versions of Safari.

I’d love to see Apple implement native support for inert. While a polyfill is available, it has non-trivial support issues for all the major screen readers. Not great! 

In addition, I’d like to call attention to this note from the inert polyfill project’s README:

The polyfill will be expensive, performance-wise, compared to a native inert implementation, because it requires a fair amount of tree-walking. 

Tree-walking means the JavaScript in the polyfill will potentially require a lot of computational power to work, and therefore slow down the end-user experience. 

For lower power devices, such as budget Android smartphones, older laptops, and more powerful devices doing computationally-intensive tasks (such as running multiple Electron apps), this might mean freezing or crashing occurs. Native browser support means this sort of behavior is a lot less taxing on the device, as it has access to parts of the browser that JavaScript doesn’t. 

Safari

Personally, I am disappointed by Apple’s lack of support for inert. While I understand that adding new features to a browser is incredibly complicated and difficult work, inert seems like a feature Apple would have supported much earlier.

macOS and iOS have historically had great support for accessibility, and assistive technology-friendly features are a common part of their marketing campaigns. Supporting inert seems like a natural extension of Apple’s mission, as the feature itself would do a ton for making accessible web experiences easier to develop.

Frustratingly, Apple is also tight-lipped about what it is working on, and when we can generally expect to see it. Because of this, the future of inert is an open question.

Igalia

Igalia is a company that works on browser features. They currently have an experiment where the public can vote on what features they’d like to see. The reasoning for this initiative is outside the scope of this article, but you can read more about it on Smashing Magazine.

One feature Igalia is considering is adding WebKit support for inert. If you have been looking for a way to help improve accessibility on the web, but have been unsure of how to start, I encourage you to pledge. $5, $10, $25. It doesn’t have to be a huge amount, every little bit adds up.

Unfortunately, inert did not win the Open Prioritization experiment. This means that we are back to not knowing if Apple is working on it, or when we can expect to see it showing up in Safari Technology Preview.

iOS 15.4 will be shipping with support for the inert attribute disabled. This is amazing news, as it signals Apple is working on it.

Wrapping up

Managing focus requires some skill and care, but is very much worth doing. The inert attribute can go a long way to making this easier to do.

Technologies like inert also represents one of the greatest strengths of the web platform: the ability to pave the cowpaths of emergent behavior and codify it into something easy and effective.

Further reading


Thank you to Adrian Roselli and Sarah Higley for their feedback.


Focus management and inert originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/focus-management-and-inert/feed/ 7 https://css-tricks.com/wp-content/uploads/2020/10/focus-navigation.mp4 Focus management and inert | CSS-Tricks nonadult 323076
A Complete Guide to CSS Functions https://css-tricks.com/complete-guide-to-css-functions/ https://css-tricks.com/complete-guide-to-css-functions/#comments Mon, 04 May 2020 15:14:37 +0000 https://css-tricks.com/?p=307668 Like any other programming language, CSS has functions. They can be inserted where you’d place a value, or in some cases, accompanying another value declaration.


A Complete Guide to CSS Functions originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>

Introduction

Like any other programming language, CSS has functions. They can be inserted where you’d place a value, or in some cases, accompanying another value declaration. Some CSS functions even let you nest other functions within them!

More

In programming, functions are a named portion of code that performs a specific task. An example of this could be a function written in JavaScript called sayWoof():

function sayWoof() {
  console.log("Woof!");
}

We can use this function later in our code, after we have defined our desired behavior. For this example, any time you type sayWoof() in your website or web app’s JavaScript it will print “Woof!” into the browser’s console.

Functions can also use arguments, which are slots for things like numbers or bits of text that you can feed into the function’s logic to have it modify them. It works like this in JavaScript:

function countDogs(amount) {
  console.log("There are " + amount + " dogs!");
}

Here, we have a function called countDogs() that has an argument called amount. When a number is provided for amount, it will take that number and add it to a pre-specified sentence. This lets us create sentences that tell us how many dogs we’ve counted.

countDogs(3); // There are 3 dogs!
countDogs(276); // There are 276 dogs!
countDogs("many"); // There are many dogs!

Some programming languages come with baked-in functions to help prevent you from having to reinvent the wheel for every new project. Typically, these functions are built to help make working with the main strengths and features of the language easier. 

Take libraries, for example. Libraries are collections of opinionated code made to help make development faster and easier, effectively just curated function collections — think FitVids.js for creating flexible video elements.

Basics of CSS Functions

Anatomy of a CSS declaration. Inside of a selector class called .selector there is a declaration of background-image: url(‘parchment.jpg’); Arrows label the property (background-image), the function (url), and the argument (parchment.jpg).

Unlike other programming languages, we cannot create our own functions in CSS, per se. That kind of logic is reserved for CSS selectors, which allow you to create powerful conditional styling rules

As opposed to other programming languages — where the output of a function typically invisibly affects other logic down the line — the output of CSS functions are visual in nature. This output is used to control both layout and presentation of content. For example: 

.has-orange-glow {
  filter: drop-shadow(0.25rem 0 0.75rem #ef9035);
}

The CSS filter function drop-shadow() uses the arguments we provide it to create an orange outer glow effect on whatever it is applied to.

In the following demo, I have a JavaScript function named toggleOrangeGlow that toggles the application of the class .has-orange-glow on the CSS-Tricks logo. Combining this with a CSS transition, we’re able to create a cool glowing effect:

You may be familiar with some CSS functions, but the language has a surprisingly expansive list! 

Much like any other technology on the web, different CSS functions have different levels of browser support. Make sure you research and test to ensure your experience works for everyone, and use things like @supports to provide quality alternate experiences.

Common CSS Functions

url()

.el {
  background: url(/images/image.jpg);
}
Using url()

url() allows you to link to other resources to load them. This can include images, fonts, and even other stylesheets. For performance reasons, it’s good practice to limit the things you load via url(), as each declaration is an additional HTTP request.

attr()

/* <div data-example="foo"> */
div {
  content: attr(data-example);
}
Using attr()

This function allows us to reach into HTML, snag an attribute’s content, and feed it to the CSS content property. You’ll commonly see attr() used in print stylesheets, where it is used to show the URL of a link after its text. Another great application of this function is using it to show the alt description of an image if it fails to load.

calc()

.el {
  width: calc(100vw - 80px);
}
Using calc()

If there’s one function you should spend some time experimenting with, it’s calc(). We have a complete guide just on calc().

This function takes two arguments and calculates a result from the operator (+, -, *, /) you supply it, provided those arguments are numbers with or without an accompanying unit.

Unlike CSS preprocessors such as Sass, calc() can mix units, meaning you can do things like subtract 6rem from 100%. calc() is also updated on the fly, so if that 100% represents a width, it’ll still work if that width changes. calc() can also accept CSS Custom Properties as arguments, allowing you an incredible degree of flexibility

lang()

p:lang(en) {
  quotes: "\201C" "\201D" "\2018" "\2019" "\201C" "\201D" "\2018" "\2019";
}
Using lang()

Including a lang attribute in your HTML is a really important thing to do. When present in your HTML, you’re able to use the lang() function to target the presence of the attribute’s value and conditionally apply styling based on it. 

One common use for this selector is to set language-specific quotes, which is great for things like internationalization. 

Clever designers and developers might also use it as a hook for styling translated versions of their sites, where cultural and/or language considerations mean there’s different perceptions about things like negative space.

:not()

h3:not(:first-child) {
  margin-top: 0;
}
Using not()

This pseudo-class selector will select anything that isn’t what you specify. For example, you could target anything that isn’t an image with body:not(img). While this example is dangerously powerful, scoping :not() to more focused selectors such as BEM’s block class can give you a great deal of versatility. 

Currently, :not() supports only one selector for its argument, but support for multiple comma-separated arguments (e.g. div:not(.this, .that)) is being worked on!

CSS Custom Properties

There is only one function specific to CSS custom properties, but it makes the whole thing tick!

The var() function is used to reference a custom property declared earlier in the document. 

html {
  --color: orange;
}

p {
  color: var(--color);
}

It is incredibly powerful when combined with calc().

html {
  --scale: 1.2;
  --size: 0.8rem;
}

.size-2 {
  font-size: calc(var(--size) * var(--scale));
}
.size-2 {
  font-size: calc(var(--size) * var(--scale) * var(--scale));
}
More on using var()

Another example of this is declaring a custom property called --ratio: 1.618; in the root of the document, then invoking it later in our CSS to control line-height, like line-height: var(--ratio);.

Here, var() is a set of instructions that tells the browser, “Go find the argument called --ratio declared earlier in the document, take its value, and apply it here.” 

Remember! calc() lets us dynamically adjust things on the fly, including the argument you supply via var().

This allows us to create things like modular scale systems directly in CSS with just a few lines of code. If you change the value of --ratio, the whole modular scale system will update to match.

In the following CodePen demo, I’ve done exactly just that. Change the value of --scale in the Pen’s CSS to a different number to see what I mean:

It’s also worth mentioning that JavaScript’s setProperty method can update custom properties in real time. This allows us to quickly and efficiently make dynamic changes to things that previously might have required a lot of complicated code to achieve. 

Color Functions

Another common place you see CSS functions is when working with color.

rgb() and rgba()

.el {
  color: rgb(255, 0, 0);
  color: rgba(255, 0, 0, 0.5);
  color: rgb(255 0 0 / 0.5);
}
Using rgb() and rgba()

These functions allow you to use numbers to describe the red (r), green (g), blue (b), and alpha (a) levels of a color. For example, a red color with a hex value of #fb1010 could also be described as rgba(251, 16, 16, 1). The red value, 251, is far higher than the green and blue values (16 and 16), as the color is mostly comprised of red information. 

The alpha value of 1 means that it is fully opaque, and won’t show anything behind what the color is applied to. If we change the alpha value to be 0.5, the color will be 50% transparent. If you use an rgb() function instead of rgba(), you don’t have to supply an alpha value. This used to mean you couldn’t supply an alpha value, but that function will take one now whether you use the old comma-syntax or the new slash-syntax.

hsl() and hsla()

.el {
  background: hsl(100, 100%, 50%);
  background: hsla(100, 100%, 50%, 0.5);
  background: hsl(100 100% 50% / 0.5);
}
Using hsl() and hsla()

Similar to rgb() and rgba(), hsl() and hsla() are functions that allow you to describe color. Instead of using red, green, and blue, they use hue (h), saturation (s), and lightness (l). 

I prefer using hsla() over rgba() because its model of describing color works really well with systematized color systems. Each of the color level values for these functions can be CSS Custom Properties, allowing you to create powerful, dynamic code.

New Color Functions

In the upcoming CSS Color Module Level 4 spec, we can ignore the a portion of rgba() and hsla(), as well as the commas. Now, spaces are used to separate the rgb and hsl arguments, with an optional / to indicate an alpha level.

We’ll also start seeing new functions like lab() and lch() that will use this new format

Pseudo Class Selector Functions

These selectors use specialized argument notation that specifies patterns of what to select. This allows you to do things like select every other element, every fifth element, every third element after the seventh element, etc.

Pseudo class selectors are incredibly versatile, yet often overlooked and under-appreciated. Many times, a thoughtful application of a few of these selectors can do the work of one or more node packages. 

:nth-child()

.el:nth-child(3n) {
  background-color: #eee;
}

nth-child() allows you to target one or more of the elements present in a group of elements that are on the same level in the Document Object Model (DOM) tree.

In the right hands, :nth-child() is incredibly powerful. You can even solve fizzbuzz with it! If you’re looking for a good way to get started, Chris has a collection useful pseudo selector recipes.

:nth-last-child()

.el:nth-last-child(2) {
  opacity: 0.75;
}
.el:last-child {
  opacity: 0.5;
}

This pseudo class selector targets elements in a group of one or more elements that are on the same level in the DOM. It starts counting from the last element in the group and works backwards through the list of available DOM nodes.

Demo

:nth-of-type()

h2:nth-of-type(odd) {
  text-indent: 3rem;
}

:nth-of-type() matches a specified collection of elements of a given type. For example, a declaration of img:nth-of-type(5) would target the fifth image on a page.

Demo

:nth-last-of-type()

section:nth-last-of-type(3) {
  background-color: darkorchid;
}

This pseudo class selector can target an element in a group of elements of a similar type. Much like :nth-last-child(), it starts counting from the last element in the group. Unlike :nth-last-child, it will skip elements that don’t apply as it works backwards. 

Demo

Animation Functions

Animation is an important part of adding that certain je ne sais quoi to your website or web app. Just remember to put your users’ needs first and honor their animation preferences.

Creating animations also requires controlling the state of things over time, so functions are a natural fit for making that happen.

cubic-bezier()

.el {
  transition-timing-function: 
    cubic-bezier(0.17, 0.67, 0.83, 0.67);
}

Instead of keyword values like ease, ease-in-out, or linear, you can use cubic-bezier() to create a custom timing function for your animation. While you can read about the math that powers cubic beziers, I think it’s much more fun to play around with making one instead.

A custom cubic bezier curve created on cubic-bezier.com. There are also options to preview and compare your curve with CSS’s ease, linear, ease-in, ease-out, and ease-in-out transitions.
Lea Verou’s cubic-bezier.com.

path()

.clip-me {
  clip-path: path('M0.5,1 C0.5,1,0,0.7,0,0.3 A0.25,0.25,1,1,1,0.5,0.3 A0.25,0.25,1,1,1,1,0.3 C1,0.7,0.5,1,0.5,1 Z');
}
.move-me {
  offset-path: path("M56.06,227 ...");
}

This function is paired with the offset-path property (or eventually, the clip-path property). It allows you to “draw” a SVG path that other elements can be animated to follow.

Demo

Both Michelle Barker and Dan Wilson have published excellent articles that go into more detail about this approach to animation.

steps()

.el {
  animation: 2s infinite alternate steps(10);
}

This relatively new function allows you to set the easing timing across an animation, which allows for a greater degree of control over what part of the animation occurs when. Dan Wilson has another excellent writeup of how it fits into the existing animation easing landscape. 

Sizing & Scaling (Transform) Functions

One common thing we do with animation is stretch and squash stuff. The following functions allow you to do exactly that. There is a catch, however: These CSS functions are a special subset, in that they can only work with the transform property.

scaleX(), scaleY(), scaleZ(), scale3d(), and scale()

.double {
  transform: scale(2);
}

Scaling functions let you increase or decrease the size of something along one or more axes. If you use scale3d() you can even do this in three dimensions!

translateX(), translateY(), translateZ(), translate3d(), and translate()

.center {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

Translate functions let you reposition an element along one or more axes. Much like scale functions, you can also extend this manipulation into three dimensions.

perspective()

.cube {
  transform: perspective(50em) rotateY(50deg)
}

This function lets you adjust the appearance of an object to make it look like it is projecting up and out from its background.

rotateX(), rotateY(), rotateZ(), rotate3d(), and rotate()

.avatar {
  transform: rotate(25deg);
}

Rotate functions let you swivel an element along one or more axes, much like grasping a ball and turning it around in your hand.

skewX(), skewY(), and skew()

.header {
  transform: skew(25deg, 15deg);
}

Skew functions are a little different from scaling and rotation functions in that they apply a distortion effect relative to a single point. The amount of distortion is proportionate to the angle and distance declared, meaning that the further the effect continues in a direction the more pronounced it will be. 

Jorge Moreno also did us all a favor and made a great tool called CSS Transform Functions Visualizer. It allows you to adjust sizing and scaling in real time to better understand how all these functions work together:

As responsible web professionals, we should be mindful of our users and the fact that they may not be using new or powerful hardware to view our content. Large and complicated animations may slow down the experience, or even cause the browser to crash in extreme scenarios.

To prevent this, we can use techniques like will-change to prepare the browser for what’s in store, and the update media feature to remove animation on devices that do not support a fast refresh rate. 

Filter Functions

CSS filter functions are another special subset of CSS functions, in that they can only work with the filter property. Filters are special effects applied to an element, mimicking functionality of graphics editing programs such as Photoshop.

You can do some really wild things with CSS filter functions, stuff like recreating the effects you can apply to your posts on Instagram!

brightness()

.avatar:hover {
  filter: brightness(150%);
}

This function adjusts how, um, bright something appears. Setting it to a low level will make it appear as if it has had a shadow cast over it. Setting it to a high level will blow it out, like an over-exposed photo.

Demo

blur()

.ghost {
  filter: blur(50%);
}

If you’re familiar with Photoshop’s Gaussian Blur filter, you know how blur() works. The more of this you apply, the more indistinct the thing you apply it to will look.

Demo

contrast()

.wow {
  filter: contrast(200%);
}

contrast() will adjust the degree of difference between the lightest and darkest parts of what is applied to.

Demo

grayscale()

.no-color {
  filter: grayscale(100%);
}

grayscale() removes the color information from what it is applied to. Remember that this isn’t an all-or-nothing affair! You can apply a partial grayscale effect to make something look weathered or washed out.

An interesting application of grayscale() could be lightly applying it to images when dark mode is enabled, to slightly diminish the overall vibrancy of color in a situation where the user may want less eye strain.

Demo

invert()

While invert() can be used to make something look like a photo negative, my favorite technique is to use it in a inverted colors media query to invert inverted images and video:

@media (inverted-colors: inverted) {
  img,
  video {
    filter: invert(100%);
  }
}

This ensures that image and video content looks the way it should, regardless of a user’s expressed browsing mode preferences. 

opacity()

.filter-visibility {
  filter: opacity(0);
}

This function controls how much of the background is visible through the element (and child elements) the function is applied to. 

Demo

An element that has 0% opacity will be completely transparent, although it will still be present in the DOM. If you need to remove an object completely, use other techniques such as the hidden attribute.

saturate()

.full-color {
  filter: saturate(100%);
}

Applying this filter can enhance, or decrease the intensity of the color of what it is applied to. Enhancing an image’s saturation is a common technique photographers use to fix underexposed photos.

Demo

sepia()

.is-old-timey {
  filter: sepia(1);
}

There are fancier ways to describe this, but realistically it’s a function that makes something look like it’s an old-timey photograph.

Demo

drop-shadow()

.fit-shape-shadow {
  filter: drop-shadow(3rem 0 0.5rem #e486da);
}

A drop shadow is a visual effect applied to an object that makes it appear like it is hovering off of the page. There’s a bit of a trick here, in that CSS also allows you to apply drop shadow effects to text and elements. It’s also distinct from the box-shadow property is that it applies drop shadows to the shape of an element rather than the actual box of an element.

Skilled designers and developers can take advantage of this to create complicated visual effects.

Demo

hue-rotate()

.change-color {
  filter: hue-rotate(180deg);
}

When a class with a declaration containing hue-rotate() is applied to an element, each pixel used to draw that element will have it’s hue valued shifted by the amount you specify. hue-rotate()‘s effect is applied to each and every pixel it is applied to, so all colors will update relative to their hue value’s starting point.

This can create a really psychedelic effect when applied to things that contain a lot of color information, such as photos.

Demo

SVG filters

filter() also lets us import SVGs filters to use to create specialized visual effects. The topic is too complicated to really do it justice in this article — if you’re looking for a good starting point, I recommend “The Art Of SVG Filters And Why It Is Awesome” by Dirk Weber.

The word “West!” rendered in a Wild West-style font, with layered teal drop shadows giving it a 3D effect. Behind it is a purple starburst pattern. Screenshot.
This effect was created by skillful application of SVG filter effects.

Comparison Functions

The idea with these functions is that we can compare multiple values and apply (or, represent, as the spec says) of the values when they’re evaluated.

clamp()

.page-wrap {
  width: clamp(320px, 80%, 1200px);
}
body {
  font-size: clamp(12px, 1rem + 2vw, 18px);
}

When providing minimum, maximum, and preferred values as arguments, clamp() will honor the preferred value so long as it does not exceed the minimum and maximum boundaries. 

clamp() will allow us to author things like components whose size will scale along with the size of the viewport, but won’t shrink or grow past a specific size. This will be especially useful for creating CSS locks, where you can ensure a responsive type size will not get so small that it can’t be read.

max() and min()

.minimum-of-these {
  width: max(500px, 50%);
}
.maximum-of-these {
  width: min(320px, 90%);
}

These functions allow you to select either the maximum or minimum value from a range of values you provide. Much like clamp(), these functions allow us to make things responsive up until a certain point. 

Logical Combinations

The spec files these functions under a “Logical Combinations” heading, but it might be easier to think of them as functions for matching selectors.

:is() and :where()

:is() has had a bit of an identity crisis. Previously referred to as both matches() and vendor prefixed as :-webkit-any/:-moz-any, it now enjoys a standardized, agreed-upon name. It is a pseudo class selector that accepts a range of selectors as its argument. 

This allows an author to group and target a wide range of selectors in an efficient way. :where() is much like :is(), only it has a specificity of zero, while the specificity of :is() is set to the highest specificity in the provided selector list. 

:is(section, article, aside, nav) :is(h1, h2, h3, h4, h5, h6) {
  color: #BADA55;
}

/* ... which is equivalent to: */
section h1, section h2, section h3, section h4, section h5, section h6, 
article h1, article h2, article h3, article h4, article h5, article h6, 
aside h1, aside h2, aside h3, aside h4, aside h5, aside h6, 
nav h1, nav h2, nav h3, nav h4, nav h5, nav h6 {
  color: #BADA55;
}

:is() and :where() allow us a good deal of flexibility about how we select things to style, especially for situations where you may not have as much control over the web site or web app’s stylesheet (e.g. third-party integrations, ads, etc.).

Gradient Functions

Gradients are created when you transition one color to one or more other colors. They are workhorses of modern user interfaces — skilled designers and developers use them to lend an air of polish and sophistication to their work.

Gradient functions allow you to specify a whole range of properties, including:

  • Color values,
  • The position on the gradient area where that color comes in,
  • What angle the gradient is positioned at.

And yes, you guessed it: the colors we use in a gradient can be described using CSS color functions!

linear-gradient() and repeating-linear-gradient()

Linear gradients apply the color transformation in a straight line, from one point to another — this line can be set at an angle as well. In cases where there’s more area than gradient, using repeating-linear-gradient() will, er, repeat the gradient you described until all the available area has been filled.

Demo

radial-gradient() and repeating-radial-gradient()

Radial gradients are a lot like linear gradients, only instead of a straight line, color transformations radiate outward from a center point. They’re oftentimes used to create a semitransparent screen to help separate a modal from the background it is placed over.

Demo

conic-gradient() and repeating-conical-gradient

Conic gradients are different from radial gradients in that the color rotates around a circle. Because of this, we can do neat things like create donut charts. Unfortunately, support for conic gradients continues to be poor, so use them with caution.

A teal and red donut chart set to 36%. To the right of the chart is a range slider, also set to 36%. Screenshot.
An adjustable conic gradient donut chart made by Ana Tudor

Grid Functions

CSS Grid is a relatively new feature of the language. It allows us to efficiently create adaptive, robust layouts for multiple screen sizes. 

It’s worth acknowledging our roots. Before Grid, layout in CSS was largely a series of codified hacks to work with a language originally designed to format academic documents. Grid’s introduction is further acknowledgement that the language’s intent has changed. 

Modern CSS is an efficient, fault-tolerant language for controlling presentation and layout across a wide range of device form factors. Equipped with Grid and other properties like flexbox, we’re able to create layouts that would have been impossible to create in earlier iterations of CSS. 

Grid introduces the following CSS functions to help you use it.

fit-content()

This function “clamps” the size of grid rows or columns, letting you specify a maximum size a grid track can expand to. fit-content() accepts a range of values, but most notable among them are min-content and max-content. These values allow you to tie your layout to the content it contains. Impressive stuff!

Demo

minmax()

minmax() allows you to set the minimum and maximum desired heights and widths of your grid rows and columns. This function can also use min-content and max-content, giving us a great deal of power and flexibility.

Demo

repeat()

You can loop through patterns of grid column and rows using repeat(). This is great for two scenarios: 

  1. When you do know how many rows or columns you need, but typing them out would be laborious. A good example of this would be constructing the grid for a calendar.
  2. When you don’t know how many rows or columns you need. Here, you can specify a template that the browser will honor as it propagates content into your layout.
Demo

Shape Functions

Like filter() and transform(), shape CSS functions only work with one property: clip-path. This property is used to mask portions of something, allowing you to create all sorts of cool effects.

circle()

This function creates a circular shape for your mask, allowing you to specify its radius and position.

Demo

ellipse()

Like circle(), ellipse() will draw a rounded shape, only instead of a perfect circle, ellipse() lets you construct an oblong mask.

Demo

polygon()

With polygon(), you are able to specify an arbitrary number of points, allowing you to draw complicated shapes. polygon() also takes an optional fill-rule argument, which specifies which part of the shape is the inside part.

Demo

inset()

This function will mask out a rectangle inside of the element you apply it to.

Demo

Miscellaneous Functions

These are the un-categorizable CSS functions, things that don’t fit neatly elsewhere.

element()

Ever pointed a camera at its own video feed? That’s sort of what element() does. It allows you to specify the ID of another element to create an “image” of what that element looks like. You can then apply other CSS to that image, including stuff like CSS filters!

It might take a bit to wrap your head around the concept — and it has some support concerns — but element() is a potentially very powerful in the right hands.

Preethi Sam‘s “Using the Little-Known CSS element() Function to Create a Minimap Navigator” demonstrates how to use it to create a code minimap and is an excellent read.

Here, she’s created a minimap for reading through a longform article:

image-set()

.responsive-background {
  background-image: 
    image-set("image.png" 1x,
              "image-2x.png" 2x,
              "image-print.png" 600dpi
    );
}

This function allows you to specify a list of images for the browser to select for a background image, based on what it knows about the capabilities of its display and its connection speed. It is analogous to what you would do with the srcset property.

::slotted()

::slotted(.marker) {
  background: lightyellow;
}

This is a pseudo-element selector used to target elements that have been placed into a slot inside a HTML template. ::slotted() is intended to be used when working with Web Components, which are custom, developer-defined HTML elements.

Not Ready for Prime Time

Like any other living programming language, CSS includes features and functionality that are actively being worked on. 

These functions can sometimes be previewed using browsers that have access to the bleeding edge. Firefox Nightly and Chrome Canary are two such browsers. Other features and functionality are so new that they only exist in what is being actively discussed by the W3C.

annotation()

This function enables Alternate Annotation Forms, characters reserved for marking up things like notation and annotation. These characters typically will be outlined with a circle, square, or diamond shape.

Not many typefaces contain Alternate Annotation Forms, so it’s good to check to see if the typeface you’re using includes them before trying to get annotation() to work. Tools such as Wakamai Fondue can help with that.

he numbers 1 and 2 enclosed in hollow and solid-filled circles. Following them are the letters B and R enclosed in hollow and solid-filled squares. Screenshot.Stylistic Alternates.
Examples of annotation glyphs from Jonathan Harrell’s post, “Better Typography with Font Variants”

counter() and counters()

When you create an ordered list in HTML, the browser will automatically generate numbers for you and place them before your list item content. These pieces of browser-generated list content are called counters. 

By using a combination of the ::marker pseudo-element selector, the content property, and the counter() function, we can control the content and presentation of the counters on an ordered list. For browsers that don’t support counter() or counters() yet, you still get a decent experience due to the browser automatically falling back to its generated content:

For situations where you have nested ordered lists, the counters() function allows a child ordered list to access its parent. This allows us to control their content and presentation. If you want to learn more about the power of ::marker, counter(), and counters(), you can read “CSS Lists, Markers, And Counters” by Rachel Andrew.

cross-fade()

This function will allow you to blend one background image into one or more other background images. Its proposed syntax is similar to gradient functions, where you can specify the stops where images start and end.

dir()

This function allows you to flip the orientation of a language’s reading order. For English, that means a left-to-right (ltr) reading order gets turned into right-to-left (rtl). Only Firefox currently has support for dir(), but you can achieve the same effect in Chromium-based browsers by using an attribute selector such as [dir="rtl"].

Demo

env()

body {
  padding: 
    env(safe-area-inset-top) 
    env(safe-area-inset-right) 
    env(safe-area-inset-bottom) 
    env(safe-area-inset-left);
}

env(), short for environment, allows you to create conditional logic that is triggered if the device’s User Agent matches up. It was popularized by the iPhone X as a method to work with its notch

That being said, device sniffing is a fallacious affair — you shouldn’t consider env() a way to cheat it. Instead, use it as intended: to make sure your design works for devices that impose unique hardware constraints on the viewport.

has()

has() is a relational pseudo-class that will target an element that contains another element, provided there is at least one match in the HTML source. An example of this is be a:has(> img), which tells the browser to target any link that contains an image. 

A diagram showing how the CSS selector a:has(> img) targets only links that contain images in a collection of links that contain either images or paragraphs.

Interestingly, has() is currently being proposed as CSS you can only write in JavaScript. If I were to wager a guess as to why this is, it is to scope the selector for performance reasons. With this approach has() is triggered only after the browser has been told to process conditional logic, and therefore query the state of things.

image()

.help::before {
  content: image("try.webp", "try.svg", "try.gif");
}

This function will let you insert either a static image (referenced with url(), or draw one dynamically via gradients and element()

Trigonometry functions

These functions will allow us to perform more advanced mathematical operations

  • Sine: sin()
  • Cosine: cos()
  • Tangent: tan()
  • Arccosine: acos()
  • Arcsine: asin()
  • Arctangent: atan()
  • Arctangent: atan2()
  • Square root: sqrt()
  • The square root of the sum of squares of its arguments: hypot()
  • Power: pow()

I’m especially excited to see what people who are more clever than I am will do with these functions, especially for things like animation!

:host() and :host-context()

To be honest, I’m a little hazy on the specifics of the jargon and mechanics that power the Shadow DOM. Here’s how the MDN describes host():

The :host() CSS pseudo-class function selects the shadow host of the shadow DOM containing the CSS it is used inside (so you can select a custom element from inside its shadow DOM) — but only if the selector given as the function’s parameter matches the shadow host.

And here’s what they have to say about :host-context():

The :host-context() CSS pseudo-class function selects the shadow host of the shadow DOM containing the CSS it is used inside (so you can select a custom element from inside its shadow DOM) — but only if the selector given as the function’s parameter matches the shadow host’s ancestor(s) in the place it sits inside the DOM hierarchy.

:nth-col() and :nth-last-col()

These pseudo-classes will allow you to select one or a specified series columns in a CSS grid to apply styling to them. A good mental model for how these functions will work is how CSS pseudo class selectors operate. Unlike pseudo class selectors, :nth-col() and :nth-last-col() should be able to target implicit grid columns.

symbols()

This function allows you to specify a list of different kinds of characters to use for list bullets. Much like annotation(), you’ll want to make sure the typeface you use contains a glyph you want to use as a symbol before trying to get symbols() to work.

Deprecated Functions

Sometimes things just don’t work out the way you think they will. While deprecated CSS functions may still render in the browser for legacy support reasons, it isn’t recommended you use them going forward.

matrix() and matrix3d()

These functions were turned into more discrete sizing and scaling functions.

rect()

This function was part of the deprecated clip property. Use the clip-path property and its values instead.

target-counter(), target-counters(), and target-text()

These functions were intended to help work with fragment URLs for paged (printed) media. You can read more about them on the W3C’s CSS Generated Content for Paged Media Module documentation

Typography

The web is typography, so it makes sense to give your type the care and attention it deserves. While CSS provides some functions specifically designed to unlock the potential of your website or webapp’s chosen typefaces, it is advised to not use the following functions to access these advanced features. 

Instead, use lower-level syntax via font-feature-settings. You can figure out if the font you’re using supports these features by using a  tool such as Wakamai Fondue.

character-variant(), styleset(), and stylistic()

Many typefaces made by professional foundries include alternate treatments for certain letters, or combinations of letters. One example use case is providing different variations of commonly-used letters for typefaces designed to look like handwriting, to help make it appear more natural-looking.

Two examples of the sentence, “Easy Sunday morning & my fox. The first sentence does not have Stylistic Alternates enabled. The second sentence does, with the alternate characters (a, “un”, “m, “rn” g, &, m, f, and x) highlighted in green. Screenshot.
Stylistic Alternates example by Tunghsiao Liu’s “OpenType Features in CSS”

Utilizing these functions activates these special alternate characters, provided they are present in the font’s glyph set

Unfortunately, it is not a standardized offering. Different typefaces will have different ranges of support, based on what the typographer chose to include. It would be wise to check to see if the font you’re using supports these special features before writing any code.

format()

When you are importing a font via the url() function, the format() function is an optional hint that lets you manually specify the font’s file format. If this hint is provided, the browser won’t download the font if it does not recognize the specified file format.

@font-face {
  font-family: 'MyWebFont';
  src: url('mywebfont.woff2') format('woff2'), /* Cutting edge browsers */
       url('mywebfont.woff') format('woff'), /* Most modern Browsers */
       url('mywebfont.ttf') format('truetype'); /* Older Safari, Android, iOS */
}

leader()

You know when you’re reading a menu at a restaurant and there’s a series of periods that help you figure out what price is attached to what menu item? Those are leaders. 

The W3C had plans for them with its CSS Generated Content for Paged Media Module, but it unfortunately seems like leader() never quite managed to take off. Fortunately, the W3C also provides an example of how to accomplish this effect using a clever application of the content property.

local()

local() allows you to specify a font installed locally, meaning it is present on the device. Local fonts either ship with the device, or can be manually installed. 

Betting on someone installing a font so things look the way you want them to is very risky! Because of this, it is recommended you don’t specify a local font that needs to be manually installed. Your site won’t look the way it is intended to, even moreso if you don’t specify a fallback font.

@font-face {
  font-family: 'FeltTipPen';
  src: local('Felt Tip Pen Web'), /* Full font name */
       local('FeltTipPen-Regular'); /* Postscript name */
}

ornaments()

Special dingbat characters can be enabled using this function. Be careful, as not all dingbat characters are properly coded in a way that will work well if a user does something like change the font, or use a specialized browsing mode.

swash()

Swashes are alternate visual treatments for letters that give them an extra-fancy flourish. They’re commonly found in italic and cursive-style typefaces.

An example of a swash being applied to a script-style typeface. There’s two versions of the phrase, “Fred And Ginger”. The first version doesn’t have swashes activated. The second example does. In the second example, the letter F, and, and the letter G are highlighted to demonstrate them being activated. Screenshot.
Swash example by Tunghsiao Liu’s “OpenType Features in CSS”

Why so many?

CSS is maligned as frequently as it is misunderstood. The guiding thought to understanding why all these functions are made available to us is knowing that CSS isn’t prescriptive — not every website has to look like a Microsoft Word document. 

The technologies that power the web are designed in such a way that someone with enough interest can build whatever they want. It’s a powerful, revolutionary concept, a large part of why the web became so ubiquitous.


A Complete Guide to CSS Functions originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/complete-guide-to-css-functions/feed/ 13 307668
SVG, Favicons, and All the Fun Things We Can Do With Them https://css-tricks.com/svg-favicons-and-all-the-fun-things-we-can-do-with-them/ https://css-tricks.com/svg-favicons-and-all-the-fun-things-we-can-do-with-them/#comments Fri, 24 Apr 2020 14:58:29 +0000 https://css-tricks.com/?p=306644 Favicons are the little icons you see in your browser tab. They help you understand which site is which when you’re scanning through your browser’s bookmarks and open tabs. They’re a neat part of internet history that are capable of …


SVG, Favicons, and All the Fun Things We Can Do With Them originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
Favicons are the little icons you see in your browser tab. They help you understand which site is which when you’re scanning through your browser’s bookmarks and open tabs. They’re a neat part of internet history that are capable of performing some cool tricks.

One very new trick is the ability to use SVG as a favicon. It’s something that most modern browsers support, with more support on the way.

Here’s the code for how to add favicons to your site. Place this in your website’s <head>:

<link rel="icon" href="/favicon.ico" sizes="any">
<link rel="icon" href="/favicon.svg" type="image/svg+xml">
<link rel="manifest" href="/manifest.webmanifest">

And place this code in your site’s web app manifest:

{
  "icons": [
    { "src": "/icon-192.png", "type": "image/png", "sizes": "192x192" },
    { "src": "/icon-512.png", "type": "image/png", "sizes": "512x512" }
  ]
}

Browsers that do support SVG favicons will override the first link element declaration and honor the second instead. Browsers that do not support SVG favicons but do support web app manifests will use the higher-resolution images. All other browsers fall back to using the favicon.ico file. This ensures that all browsers that support favicons can enjoy the experience. 

You may also notice the alternate attribute value for our rel declaration in the second line. This programmatically communicates to the browser that the favicon with a file format that uses .ico is specifically used as an alternate presentation.

Following the favicons is a line of code that loads another SVG image, one called safari-pinned-tab.svg. This is to support Safari’s pinned tab functionality, which existed before other browsers had SVG favicon support. There’s additional files you can add here to enhance your site for different apps and services, but more on that in a bit.

Here’s more detail on the current level of SVG favicon support:

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

Desktop

ChromeFirefoxIEEdgeSafari
8041No80No

Mobile / Tablet

Android ChromeAndroid FirefoxAndroidiOS Safari
126NoNoNo

Why SVG?

You may be questioning why this is needed. The .ico file format has been around forever and can support images up to 256×256 pixels in size. Here are three answers for you.

Ease of authoring

It’s a pain to make .ico files. The file is a proprietary format used by Microsoft, meaning you’ll need specialized tools to make them. SVG is an open standard, meaning you can use them without any further tooling or platform lock-in.

Future-proofing

Retina? 5k? 6k? When we use a resolution-agnostic SVG file for a favicon, we guarantee that our favicons look crisp on future devices, regardless of how large their displays get

Performance

SVGs are usually very small files, especially when compared to their raster image counterparts — even more-so if you optimize them beforehand. By only using a 16×16 pixel favicon as a fallback for browsers that don’t support SVG, we provide a combination that enjoys a high degree of support with a smaller file size to boot. 

This might seem a bit extreme, but when it comes to web performance, every byte counts!

Tricks

Another cool thing about SVG is we can embed CSS directly in it. This means we can do fun things like dynamically adjust them with JavaScript, provided the SVG is declared inline and not embedded using an img element.

<svg  version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
  <style>
    path { fill: #272019; }
  </style>
  <!-- etc. -->
</svg>

Since SVG favicons are embedded using the link element, they can’t really be modified using JavaScript. We can, however, use things like emoji and media queries.

Emoji

Lea Verou had a genius idea about using emoji inside of SVG’s text element to make a quick favicon with a transparent background that holds up at small sizes.

In response, Chris Coyier whipped up a neat little demo that lets you play around with the concept.

Dark Mode support

Both Thomas Steiner and Mathias Bynens independently stumbled across the idea that you can use the prefers-color-scheme media query to provide support for dark mode. This work is built off of Jake Archibald’s exploration of SVG and media queries.

<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg">
  <style>
    path { fill: #000000; }
    @media (prefers-color-scheme: dark) {
      path { fill: #ffffff; }
    }
  </style>
  <path d="M111.904 52.937a1.95 1.95 0 00-1.555-1.314l-30.835-4.502-13.786-28.136c-.653-1.313-2.803-1.313-3.456 0L48.486 47.121l-30.835 4.502a1.95 1.95 0 00-1.555 1.314 1.952 1.952 0 00.48 1.99l22.33 21.894-5.28 30.918c-.115.715.173 1.45.768 1.894a1.904 1.904 0 002.016.135L64 95.178l27.59 14.59c.269.155.576.232.883.232a1.98 1.98 0 001.133-.367 1.974 1.974 0 00.768-1.894l-5.28-30.918 22.33-21.893c.518-.522.71-1.276.48-1.99z" fill-rule="nonzero"/>
</svg>

For supporting browsers, this code means our star-shaped SVG favicon will change its fill color from black to white when dark mode is activated. Pretty neat!

Other media queries

Dark mode support got me thinking: if SVGs can support prefers-color-scheme, what other things can we do with them? While the support for Level 5 Media Queries may not be there yet, here’s some ideas to consider:

Mockup of four SVG favicon treatments. The first treatment is a pink star with a tab title of, “SVG Favicon.” The second treatment is a hot pink star with a tab title of, “Light Level SVG Favicon.” The third treatment is a light pink star with a tab title of, “Inverted Colors SVG Favicon.” The fourth treatment is a black pink star with a tab title of, “High Contrast Mode SVG Favicon.” The tabs are screen captures from Microsoft Edge, with the browser chrome updating to match each specialized mode.
A mockup of how these media query-based adjustments could work.

Keep it crisp

Another important aspect of good favicon design is making sure they look good in the small browser tab area. The secret to this is making the paths of the vector image line up to the pixel grid, the guide a computer uses to turn SVG math into the bitmap we see on a screen. 

Here’s a simplified example using a square shape:

A crisp orange square on a white background. There is also a faint grid of gray horizontal and vertical lines that represent the pixel grid. Screenshot from Figma.

When the vector points of the square align to the pixel grid of the artboard, the antialiasing effect a computer uses to smooth out the shapes isn’t needed. When the vector points aren’t aligned, we get a “smearing” effect:

A blurred orange square on a white background. There is also a faint grid of gray horizontal and vertical lines that represent the pixel grid. Screenshot from Figma.

A vector point’s position can be adjusted on the pixel grid by using a vector editing program such as Figma, Sketch, Inkscape, or Illustrator. These programs export SVGs as well. To adjust a vector point’s location, select each node with a precision selection tool and drag it into position.

Some more complicated icons may need to be simplified, in order to look good at such a small size. If you’re looking for a good primer on this, Jeremy Frank wrote a really good two-part article over at Vidget.

Go the extra mile

In addition to favicons, there are a bunch of different (and unfortunately proprietary) ways to use icons to enhance its experience. These include things like the aforementioned pinned tab icon for Safari¹, chat app unfurls, a pinned Windows start menu tile, social media previews, and homescreen launchers.

If you’re looking for a great place to get started with these kinds of enhancements, I really like realfavicongenerator.net.

Icon output from realfavicongenerator.net arranged in a grid using CSS-Trick’s logo. There are two rows of five icons: android-chrome-192x192.png, android-chrome-384x384.png, apple-touch-icon.png, favicon-16x16.png, favicon-32x32.png, mstile-150x150.png, safari-pinned-tab.svg, favicon.ico, browserconfig.xml, and site.webmanifest.
It’s a lot, but it guarantees robust support.

A funny thing about the history of the favicon: Internet Explorer was the first browser to support them and they were snuck in at the 11th hour by a developer named Bharat Shyam:

As the story goes, late one night, Shyam was working on his new favicon feature. He called over junior project manager Ray Sun to take a look.

Shyam commented, “This is good, right? Check it in?”, requesting permission to check the code into the Internet Explorer codebase so it could be released in the next version. Sun didn’t think too much of it, the feature was cool and would clearly give IE an edge. So he told Shyam to go ahead and add it. And just like that, the favicon made its way into Internet Explorer 5, which would go on to become one of the largest browser releases the web has ever seen.

The next day, Sun was reprimanded by his manager for letting the feature get by so quickly. As it turns out, Shyam had specifically waited until later in the day, knowing that a less experienced Program Manager would give him a pass. But by then, the code had been merged in. Incidentally, you’d be surprised just how many relatively major browser features have snuck their way into releases like this.

From How We Got the Favicon by Jay Hoffmann

I’m happy to see the platform throw a little love at favicons. They’ve long been one of my favorite little design details, and I’m excited that they’re becoming more reactive to user’s needs. If you have a moment, why not sneak a SVG favicon into your project the same way Bharat Shyam did way back in 1999. 


¹ I haven’t been able to determine if Safari is going to implement SVG favicon support, but I hope they do. Has anyone heard anything?


SVG, Favicons, and All the Fun Things We Can Do With Them originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/svg-favicons-and-all-the-fun-things-we-can-do-with-them/feed/ 9 306644
What the Web Still Is https://css-tricks.com/what-the-web-still-is/ Thu, 21 Nov 2019 18:51:26 +0000 https://css-tricks.com/?p=298289 Being a pessimist is an easy thing to fall back on, and I’m trying to be better about it. As we close the year out, I thought it would be a good exercise to take stock of the state of …


What the Web Still Is originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
Being a pessimist is an easy thing to fall back on, and I’m trying to be better about it. As we close the year out, I thought it would be a good exercise to take stock of the state of the web and count our blessings.

Versatile

We don’t use the internet to do just one thing. With more than two decades of globally interconnected computers, the web allows us to use it for all manner of activity.

This includes platforms, processes, and products that existed before the web came into being, and also previously unimagined concepts and behaviors. Thanks to the web, we can all order takeout the same way we can all watch two women repair a space station in realtime.

Decentralized

There is still no one single arbiter you need to petition to sign off on the validity of your idea, or one accepted path for going about to make it happen. Any website can link out to, or be linked to, without having to pay a tax or file pre-approval paperwork.

While we have seen a consolidation of the services needed to run more sophisticated web apps, you can still put your ideas out for the entire world to see with nothing more than a static HTML page. This fact was, and still is, historically unprecedented.

Resilient

The internet has been called the most hostile environment to develop for. Someone who works on the web has to consider multiple browsers, the operating systems they are installed on, and all the popular release versions of both. They also need to consider screen size and quality, variable network conditions, different form factors and input modes, third party scripts, etc. This is to say nothing about serving an unknown amount of unknown users, each with their own thoughts, feelings, goals, abilities, motivations, proficiencies, and device modifications.

If you do it right, you can build a website or a web app so that it can survive a lot of damage before it is rendered completely inoperable. Frankly, the fact that the web works at all is nothing short of miraculous.

The failsafes, guardrails, redundancies, and other considerations built into the platform from the packet level on up allow this to happen. Honoring them honors the thought, care, and planning that went into the web’s foundational principles.

Responsive

Most websites now make use of media queries to ensure their content reads and works well across a staggeringly large amount of devices. This efficient technology choice is fault-tolerant, has a low barrier of entry, and neatly side-steps the myriad problems you get with approaches such as device-sniffing and/or conditionally serving massive piles of JavaScript.

Responsive Design was, and still is revolutionary. It was the right answer, at the right place and time. It elegantly handled the compounding problem of viewport fragmentation as the web transformed from something new and novel into something that is woven into our everyday lives.

Adaptable

In addition to being responsive, the web works across a huge range of form factors, device capabilities, and specialized browsing modes. The post you are currently reading can show up on a laptop, a phone, a Kindle, a TV, a gas station pump, a video game console, a refrigerator, a car, a billboard, an oscilloscope—heck, even a space shuttle (if you’re reading this from space, please, please, please let me know).

It will work with a reading mode that helps a person focus, dark and high contrast modes that will help a person see, and any number of specialized browser extensions that help people get what they need. I have a friend who inverts her entire display to help prevent triggering migraines, and the web just rolls with it. How great is that?

Web content can be read, translated, spoken aloud, copied, clipped, piped into your terminal, forked, remixed, scraped by a robot, output as Braille, and even played as music. You can increase the size of its text, change its font and color, and block parts you don’t want to deal with—all in the service of making it easier for you to consume. That is revolutionary when compared to the media that came before it.

Furthermore, thanks to things like Progressive Web Apps and Web Platform Features, the web now blends seamlessly into desktops and home screens. These features allow web content to behave like traditional apps and are treated as first-class citizens by the operating systems that support them. You don’t even necessarily need to be online for them to work!

Accessible

The current landscape of accessibility compliance is a depressing state of affairs. WebAIM’s Million report, and subsequent update, highlights this with a sobering level of detail.

Out of the top one million websites sampled, ~98% of home pages had programmatically detectable Web Content Accessibility Guideline (WCAG) errors. This represents a complete, categorical failure of our industry on every conceivable level, from developers and designers, to framework maintainers, all the way up to those who help steer the future of the platform.

And yet.

In that last stubborn two percent lives a promise of the web. Web accessibility—the ability for someone to use a website or web app regardless of their ability or circumstance—grants autonomy. It represents a rare space where a disabled individual may operate free from the immense amount of bias, misunderstanding, and outright hate that is pervasive throughout much of society. This autonomy represents not only freedom for social activities but also employment opportunities for a population that is routinely discriminated against.

There is a ton of work to do, and we do not have the luxury of defeatism. I’m actually optimistic about digital accessibility’s future. Things like Inclusive Design have shifted the conversation away from remediation into a more holistic, proactive approach to product design.

Accessibility, long viewed as an unglamorous topic, has started to appear as a mainstream, top-level theme in conference and workshop circuits, as well as popular industry blogs. Sophisticated automated accessibility checkers can help prevent you from shipping inaccessible code. Design systems are helping to normalize the practice at scale. And most importantly, accessibility practitioners are speaking openly about ableism.

Inexpensive

While the average size of a website continues to rise, the fact remains that you can achieve an incredible amount of functionality with a small amount of code. That’s an important thing to keep in mind.

It has never been more affordable to use the web. In the United States, you can buy an internet-ready smartphone for ~$40. Emerging markets are adopting feature phones such as the JioPhone (~$15 USD) at an incredible rate. This means that access to the world’s information is available to more people—people who traditionally may have never been able to have such a privilege.

Think about it: owning a desktop computer represented having enough steady income to be able to support permanent housing, as well as consistent power and phone service. This created an implicit barrier to entry during the web’s infancy.

The weakening of this barrier opens up unimaginable amounts of opportunity, and is an excellent reminder that the web really is for everyone. With that in mind, it remains vital to keep our payload sizes down. What might be a reflexive CMD + R for you might be an entire week’s worth of data for someone else.

Diverse

There are more browsers available than I have fingers and toes to count on. This is a good thing. Like any other category of software, each browser is an app that does the same general thing in the same general way, but with specific design decisions made to prioritize different needs and goals.

My favorite browser, Firefox, puts a lot of its attention towards maintaining the privacy and security of its users. Both Edge and Safari are bundled with their respective operating systems, and have interfaces geared towards helping the widest range of users browse web content. Browsers like Vivaldi are geared towards tinkerers, people who like a highly customized browsing experience. Samsung Internet is an alternative browser for Android devices that can integrate with their proprietary hardware. KaiOS and UC browsers provide access to millions of feature phones, helping them to have smartphone-esque functionality. Chrome helps you receive more personalized ads efficiently debug JavaScript.

Browser engine diversity is important as well, although the ecosystem has been getting disturbingly small as of late. The healthy competition multiple engines generates translates directly to the experience becoming better for the most important people in the room: Those who rely on the web to live their everyday lives.

Speaking of people, let’s discuss the web’s quality of diversity and how it applies to them: Our industry, like many others, has historically been plagued by ills such as misogyny, racism, homophobia, transphobia, and classism. However, the fact remains that the ability to solve problems in the digital space represents a rare form of leverage that allows minoritized groups to have upward economic mobility.

If you can’t be motivated by human decency, it’s no secret that more diverse teams perform better. We’ve made good strides in the past few years towards better representation, but there’s still a lot of work to be done.

Listen to, and signal boost the triumphs, frustrations, and fears of the underrepresented in our industry. Internalize their observations and challenge your preconceived notions and biases. Advocate for their right to be in this space. Educate yourself on our industry’s history. Support things like codes of conduct, which do the hard work of modeling and codifying expectations for behavior. All of this helps to push against a toxic status quo and makes the industry better for everyone.

Standardized

The web is built by consensus, enabling a radical kind of functionality. This interoperability—the ability for different computer systems to be able to exchange information—is built from a set of standards we have all collectively agreed on.

Chances are good that a web document written two decades ago will still work with the latest version of any major browser. Any web document written by someone else—even someone on the opposite side of the globe—will also work. It will also continue to work on browsers and devices that have yet to be invented. I challenge you to name another file format that supports this level of functionality that has an equivalent lifespan.

This futureproofing by way of standardization also allows for a solid foundation of support for whatever comes next. Remember the principle of versatile: It is important to remember that these standards are also not prescriptive. We’re free to take these building blocks use arrange them in a near-infinite number of ways.

Open

Furthermore, this consensus is transparent. While the process may seem slow sometimes, it is worth highlighting the fact that the process is highly transparent. Anyone who is invested may follow, and contribute to web standards, warts and all.

It’s this openness that helps to prevent things like hidden agendas, privatization, lock-in, and disproportionate influence from consolidating power. Open-source software and protocols and, most importantly, large-scale cooperation also sustain the web platform’s long-term growth and health. Think of web technologies that didn’t make it: Flash, Silverlight, ActiveX, etc. All closed, for-profit, brittle, and private.

It also helps to disincentive more abstract threats, things like adversarial interoperability and failure to disclose vulnerabilities. These kinds of hazards are a good thing to remember any time you find yourself frustrated with the platform.


Make no mistake: I feel a lot of what makes the web great is actively being dismantled, either inadvertently or deliberately. But as I mentioned earlier, cynicism is easy. My wish for next year? That all the qualities mentioned here are still present. My New Year’s resolution? To help ensure it.


What the Web Still Is originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
298289
Revisiting prefers-reduced-motion, the reduced motion media query https://css-tricks.com/revisiting-prefers-reduced-motion/ https://css-tricks.com/revisiting-prefers-reduced-motion/#comments Tue, 30 Apr 2019 15:13:19 +0000 http://css-tricks.com/?p=286790 Two years ago, I wrote about prefers-reduced-motion, a media query introduced into Safari 10.1 to help people with vestibular and seizure disorders use the web. The article provided some background about the media query, why it was needed, and …


Revisiting prefers-reduced-motion, the reduced motion media query originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
Two years ago, I wrote about prefers-reduced-motion, a media query introduced into Safari 10.1 to help people with vestibular and seizure disorders use the web. The article provided some background about the media query, why it was needed, and how to work with it to avoid creating disability-triggering visual effects.

The article was informed by other people’s excellent work, namely Orde Saunders’ post about user queries, and Val Head’s article on web animation motion sensitivity.

We’re now four months into 2019, and it makes me happy to report that we have support for the feature in all major desktop browsers! Safari was first, with Firefox being a close second. Chrome was a little late to the party, but introduced it as of version 74.

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

Desktop

ChromeFirefoxIEEdgeSafari
7463No7910.1

Mobile / Tablet

Android ChromeAndroid FirefoxAndroidiOS Safari
12612712610.3

While Microsoft Edge does not have support for prefers-reduced-motion, it will become Chrome under the hood soon. If there’s one good thing to come from this situation, it’s that Edge’s other excellent accessibility features will (hopefully) have a good chance of being back-ported into Chrome.

The prefers-reduced-motion setting in MacOS.

Awareness

While I’m happy to see some websites and web apps using the media query, I find that it’s rare to encounter it outside of places maintained by people who are active in CSS and accessibility spaces. In a way, this makes sense. While prefers-reduced-motion is relatively new, CSS features and functionality as a whole are often overlooked and undervalued. Accessibility even more so.

It’s tough to blame someone for not using a feature they don’t know exists, especially if it’s relatively new, and especially in an industry as fast-paced as ours. The deck is also stacked in terms of what the industry prioritizes as marketable, and therefore what developers pay attention to. And yet, prefers-reduced-motion is a library-agnostic feature that ties into Operating System-level functionality. I’m pretty sure that means it’ll have some significant staying power in terms of reward for time spent for skill acquisition.

Speaking of rewards, I think it’s also worth pointing out the true value prefers-reduced-motion represents: Not attracting buzzword-hungry recruiters on LinkedIn, but improving the quality of life for the people who benefit from the effect it creates. Using this media query could spare someone from having to unnecessarily endure a tremendous amount of pain for simply having the curiosity to click on a link or scroll down a page.

The people affected

When it comes to disability, many people just assume “blind people.” The reality is that disabilities are a complicated and nuanced topic, one that is surprisingly pervasive, deeply personal, and full of unfortunate misconceptions. It’s also highly variable. Different people are affected by different disability conditions in different ways — extending to a wide gamut of permanent, temporary, environmental, and situational concerns. Multiple, compounding conditions can (and do) affect individuals, and sometimes what helps one person might hinder another. It’s a difficult, but very vital thing to keep in mind.

If you have a vestibular disorder or have certain kinds of migraine or seizure triggers, navigating the web can be a lot like walking through a minefield — you’re perpetually one click away from activating an unannounced animation. And that’s just for casual browsing.

If you use the web for work, you might have no choice but to endure a web app that contains triggering animations multiple times a week, or even per day or hour. In addition to not having the autonomy to modify your work device, you may also not have the option to quickly and easily change jobs — a privilege easily forgotten when you’re a specialized knowledge worker.

It’s a fallacy to assume that a person is aware of their vestibular disorder, or what triggers it. In fact, sometimes the initial triggering experience exacerbates your sensitivity and makes other parts of a design difficult to use. Facundo Corradini shares his experience with this phenomenon in his article, “Accessibility for Vestibular Disorders: How My Temporary Disability Changed My Perspective.”

Not all assistive technology users are power users, so it’s another fallacy to assume that a person with a vestibular disorder is aware of, or has the access rights to enable a motion-reducing Operating System setting or install a browser extension.

Think of someone working in a large corporation who has to use a provisioned computer with locked-down capabilities. Or someone who isn’t fully aware of what of their tablet is capable of doing past browsing social media, watching video, and messaging their family and friends. Or a cheap and/or unorthodox device that will never support prefers-reduced-motion feature — some people purchase discontinued devices such as the Windows Phone specifically because their deprecation makes them affordable.

Do these people deserve to be hurt because of their circumstances? Of course not.

Considering what’s harmful

You can tie harm into value, the same way you can with delight. Animation intended to nudge a person towards a signup could also drive them away. This kind of exit metric is more difficult to quantify, but it definitely happens. Sometimes the harm is even intentional, and therefore an easier datapoint to capture — what you do with that information is a whole other issue.

If enough harm happens to enough people, it affects that certain something we know as branding. This effect doesn’t even need to be tied to a disability condition. Too much animation, applied to the wrong things in the wrong way will drive people away, even if they can’t precisely articulate why.

You also don’t know who might be on the receiving end, or what circumstances they’re experiencing the moment they load your website or web app. We can’t — and shouldn’t — know this kind of information, either. It could be a prospective customer, the employee at a venture capitalist firm tasked with evaluating your startup, or maybe even your new boss.

We also don’t need to qualify their relationship to us to determine if their situation is worth considering — isn’t it enough to just be proactively kind?

Animation is progressive enhancement

We also need to acknowledge that not every device that can access the web can also render animation, or render animation smoothly. When animation is used on a low-power or low quality device that “technically” supports it, the overall user experience suffers. Some people even deliberately seek this experience out as a feature.

Devices may also be set to specialized browsing modes to allow people to access your content in alternate ways. This concept is known as being robust, and is one of the four high-level principles that govern the guidelines outlining how to craft accessible experiences.

Animation might not always look the way you intend it in these modes. One example would be when the viewport is zoomed and the animation isn’t built using relative units. There’s a non-trivial chance important parts might be pushed out of the viewport, leaving the animation appearing as a random collection of flickering bits. Another example of a specialized browsing mode might be Reader Mode, where the animation may not appear at all.

Taking it to code

Considering all this, I’m wondering if there are opportunities to help web professionals become more aware of, and therefore more considerate of the downsides of poorly conceived and implemented animation.

Maybe we proactively incorporate a media query high up in the cascade to disable all animation for those who desire it, and for those who have devices that can’t support it. This can be accomplished by targeting anything where someone has expressed a desire for a low-to-no-animation experience, or any device that has a slow screen refresh rate.

The first part of the query, targeting low-to-no-animation, is done via prefers-reduced-motion. The second, targeting a screen with a low refresh rate, uses update. update is a new media feature that allows us to “query the ability of the output device to modify the appearance of content once it has been rendered.”

@media screen and
  (prefers-reduced-motion: reduce), 
  (update: slow) {
  * {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important; /* Hat tip Nick/cssremedy (https://css-tricks.com/revisiting-prefers-reduced-motion-the-reduced-motion-media-query/#comment-1700170) */
    transition-duration: 0.001ms !important;
  }
}

This code forces all animation that utilizes a declaration of animation-duration or transition-duration to conclude at a rate that is imperceptible to the human eye. It will work when a person has requested a reduced motion experience, or the device has a screen with a slow refresh rate, say e-ink or a cheap smartphone.

Retaining the animation and transition duration also ensures that any functionality that is tied to CSS-based animation will activate successfully (unlike using a declaration of animation: none), while still preventing a disability condition trigger or creating rendering lag.

This declaration is authored with the intent of introducing some intentional friction into our reset styles. Granted, it’s not a perfect solution, but it does drive at a few things:

  1. Increasing the chances of developers becoming aware of the two media features, by way of making them present in the cascade of every inspected element.
  2. Providing a moment to consider why and how animation will be introduced into a website or web app, and what the experience should be like for those who can’t or don’t want to experience it.
  3. Encouraging developers who are less familiar with CSS to think of the cascade in terms of components and nudge them towards making more easily maintainable stylesheets.

Animation isn’t unnecessary

In addition to vestibular disorders and photosensitive conditions, there’s another important aspect of accessibility we must consider: cognitive disabilities.

Cognitive disabilities

As a concern, the category is wide and often difficult to quantify, but no less important than any other accessibility discipline. It is also far more prevalent. To expand on this some, the World Health Organization reports an estimated 300 million people worldwide are affected by depression, a temporary or permanent, environmental and/or biological condition that can significantly impair your ability to interact with your environment. This includes interfering with your ability to understand the world around you.

Animation can be a great tool to help combat some forms of cognitive disability by using it to break down complicated concepts, or communicate the relationship between seemingly disparate objects. Val Head’s article on A List Apart highlights some other very well-researched benefits, including helping to increase problem-solving ability, recall, and skill acquisition, as well as reducing cognitive load and your susceptibility to change blindness.

Reduce isn’t necessarily remove

We may not need to throw the baby out with the bathwater when it comes to using animation. Remember, it’s prefers-reduced-motion, not prefers-no-motion.

If we embrace the cascade, we can work with the animation reset code described earlier on a per-component basis. If the meaning of a component is diminished by removing its animation altogether, we could slow down and simplify the component’s animation to the point where the concept can be communicated without potentially being an accessibility trigger.

If you’re feeling clever, you might even be able to use CSS Custom Properties to help achieve this in an efficient way. If you’re feeling extra clever, you could also use these Custom Properties for a site-wide animation preferences widget.

In the following code sample, we’re defining default properties for our animation and transition durations, then modifying them based on the context they’re declared in:

/* Set default durations */
:root {
  --animation-duration: 250ms; 
  --transition-duration: 250ms; 
}

/* Contextually shorten duration length */
@media screen and (prefers-reduced-motion: reduce), (update: slow) {
  :root {
    --animation-duration: 0.001ms !important; 
    --transition-duration: 0.001ms !important;
  }
}

@media screen and (prefers-reduced-motion: reduce), (update: slow) {
  /* Remove duration for all unknown animation when a user requests a reduced animation experience */
  * {
    animation-duration: var(--animation-duration);
    animation-iteration-count: 1 !important;
    transition-duration: var(--animation-duration);
  }
}

/* Update the duration when animation is critical to understanding and the device can support it */
@media screen and (prefers-reduced-motion: reduce), (update: fast) {
  .c-educational-concept {
    /* Set a new animation duration scoped to this component */
    --animation-duration: 6000ms !important; 
    ...
    animation-name: educational-concept;
    /* Use the scoped animation duration */
    animation-duration: var(--animation-duration); 
  }
}

However, trying to test the effectiveness of this slowed-down animation puts us in a bit of a pickle: there’s no real magic number we can write a test against.

We need to have a wide representation of people who are susceptible to animation-based disability triggers to sign off on it being safe, which unfortunately involves subjecting them to something that may potentially not be. That’s a huge ask.

A better approach is to ask about what kinds of animation have been triggers for them in the past, then see if what they describe matches what we’ve made. This approach also puts the onus on yourself, and not the person with a disability, to do the work to provide accommodation.

If you’re having trouble finding people, ask your friends, family, and coworkers — I’m sure there’s more people out there than you think. And if you need a good starting point for creating safer animation, I once again urge you to read Val’s article on A List Apart.

Neurodivergence

There’s a lot to unpack here, and I’m not the most qualified person to talk about it. Here’s what my friend Shell Little, an Accessibility Specialist at Wells Fargo DS4B, has to say about it:

Web animation as it relates to Neurodivergence (ND) can be a fantastic tool to guide users to solidify meaning and push understanding. The big issue is the same animation that can assist one group of ND users can create a barrier for another. As mentioned by Eric, Neurodivergence is a massive group of people with a vast range of abilities and covers a wide variety of cognitive disabilities including but not limited to ADHD, autism, dyslexia, epilepsy, dyscalculia, obsessive-compulsive disorder, dyspraxia, and Tourette syndrome.

When speaking about motion on the web it’s important we think specifically about attention-related disabilities, autism, and sensory processing disorders that are also closely linked to both. These groups of people, who coincidentally includes me, are especially sensitive to motion as it relates to understanding information and interacting with the web as a whole. Animations can easily overwhelm, distract, and frustrate users who are sensitive to motion and from personal experience, it can even do all three at once.

Because so many people are affected by motion and animation on the web the W3C’s WCAG have a criterion named Pause, Stop, Hide that is specifically written to guide content creators on how to best create accessible animations. My main issues with this guideline are, it only applies to animations that last longer than 5 seconds and motion that is deemed essential is exempt from the standard. That means a ton of animations that can create barriers such as distraction, dizziness, and even harm are out there in the wild.

It makes sense, as Eric mentioned, that we can’t get rid of all animation. Techniques such as spinners let users know the page is still working on the task it was given, and micro-interactions help show progression. But depending on someone’s brain, the things that are helpful at lunch can be a barrier later that night. Someone’s preferences and needs shift throughout their day, and that’s the beauty of prefers-reduced-motion. It has the potential to be what fills the gaps left by Pause, Stop, Hide and allow users to decide when they do or do not want to have motion. That right there is priceless to someone like me.

As someone with an attention-related disability, an interaction I have found to be exceedingly frustrating is autoplay. Many media sharing sites have auto-playing content such as videos, gifs, and ads but because they can be paused, they pass the WCAG standard. That doesn’t mean they aren’t a huge barrier for me as I can’t read any text around them when they are playing. This causes me to have to pause every single moving item I run into. This not only significantly slows me down, and eats away at my limited spoons, but it also derails my task flow and train of thought. Now, it is true some sites — such as Twitter and LinkedIn — have settings to turn autoplay off, but this isn’t true for all sites. This would be a perfect place for prefers-reduced-motion.

In a world where I would be able to determine when and if I want videos to start playing at me, I would be able to get more done with less cognitive strain. prefers-reduced-motion is freedom for me and the millions of people whose brains work like mine. In sum, the absolute best thing we can do for our users who are sensitive to motion is to put a system in place that empowers them to decide when and where animation should be displayed to them. Let the user decide because they will always know their access needs better than we do.

Thanks, Shell!

I don’t hate fun, I just don’t want to hurt people

On my own time, I’m fortunate enough to be able to enjoy animation. I appreciate the large amounts of time and attention involved with making something come alive on the screen, and I’ve definitely put my fair share of time ooh-ing and aah-ing over other people’s amazing work in CodePen. I’ve also watched enough DC Animated Universe to be able to instantly recognize Kevin Conroy’s voice — if you’re looking for even deeper nerd cred, Masaaki Yuasa is a seriously underrated animator.

However, I try to not overly rely on animation as a web professional. There’s a number of factors as to why:

  1. First is simply pushing on awareness of the concerns outlined earlier, as many are unaware they exist. Animation has such a crowd-pleasing gee-whiz factor to it that it’s often quickly accepted into a product without a second thought.
  2. Second is mitigating risk. Not adhering to the Web Content Accessibility Guidelines (WCAG) — including provisions for animation — means your inaccessible website or web app becomes a legal liability. There is now legal precedent for the websites and web apps of private companies being sued, so it’s a powerful metric to weigh your choices against.
  3. Third is user experience. With that gee-whiz factor, people tend to forget that being forced to repeatedly view that super-slick animation over and over again will eventually become a tedious chore. There’s a reason why we no longer make 90s-style loading screens (content warning: high-contrast strobing and flickering, Flash, mimes). If you need a more contemporary example, consider why Netflix lets us skip TV show intros.
  4. Fourth is understanding the lay of the land. While prefers-reduced-motion is getting more support, the majority of it is on desktop browsers, and not mobile. We’re not exactly a desktop-first world anymore, especially if you’re in an underserved community or emerging market. A mobile form factor also may exacerbate vestibular issues. Moving around while using your device means you may lose a fixed reference point, unlike sitting at a desk and staring at a monitor — this kind of trigger is similar to why some of us can get seasick.
  5. The fifth factor is a bit of a subset of the fourth. Animation eats device data and battery, and it’s important to remember that it’s the world wide web, not the wealthy Western web. The person using your service may not have consistent and reliable access to income or power, so you want to get to know your audience before spending their money for them.

The ask

Not everyone who could benefit from prefers-reduced-motion cares about accessibility-related content, so I’d love to see the media query start showing up in the code of more popular sites. The only real way to do this is to spread awareness. Not only of the media query, but more importantly, understanding the nuance involved with using animation responsibly.

CSS-Tricks is a popular website for the frontend industry, and I’m going to take advantage of that. If you feel comfortable sharing, what I would love is to describe what kinds of animation have been problematic for you, in either the comments or on Twitter.

The idea here is we can help build a reference of what kinds of things to be on the lookout for animation-wise. Hopefully, with time and a little luck, we can all help make the web better for everyone.


Thanks to Scott O’Hara, Zach Leatherman, Shell Little, and Geoff Graham for reviewing this article.


Revisiting prefers-reduced-motion, the reduced motion media query originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/revisiting-prefers-reduced-motion/feed/ 6 286790
Reader Mode: The Button to Beat https://css-tricks.com/reader-mode-the-button-to-beat/ https://css-tricks.com/reader-mode-the-button-to-beat/#comments Mon, 07 Jan 2019 14:57:57 +0000 http://css-tricks.com/?p=280754 As a young nerd, I loved to immerse myself in digital worlds, learning the ins and outs of the rules someone else had created for me (intentionally or not). But the older and crankier I get, the more I find …


Reader Mode: The Button to Beat originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
As a young nerd, I loved to immerse myself in digital worlds, learning the ins and outs of the rules someone else had created for me (intentionally or not). But the older and crankier I get, the more I find myself losing patience when navigating these “delightful” experiences.

This fascination was great for my eventual career as a designer, but unfortunately, it was also like teaching someone kerning—once you learn how to quantify a bad user experience, you can’t go back.

These days, I’m an impatient grump who doesn’t want to take work home. I just want to get in, get what I need, and get out. If there’s any delight I’m experiencing, it’s lost on me because I had such an effortless and annoyance-free time that it simply doesn’t stand out.

One of the features I find myself turning to over and over again is Safari’s Reader Mode. I read a lot of news, and with that comes a lot of bullshit. I now tap the cryptic little icon almost reflexively, confident that I’ll be transported to a land where I can focus on what matters most to me: content.

An iPhone screenshot highlighting the Reader Mode button located in the top-right corner of the screen.

Tapping this button transports me to a land free of newsletter signup modals, surveys, pop-ups, pop-unders, flashing ad banners, automatically-playing video, app install prompts, breaking news alerts, passive-aggressive interstitials, and faux notification permission banners. It slices through the undesirable and unnecessary with ease; the Alexander the Great to the Gordian Knot that is poor user interface design.

Firefox also offers this reading mode. So does Edge. I find myself using it more and more on my laptop with every passing day—especially for reading long-form articles, like this piece. I’d be very surprised to see Chrome institute one natively, as Google is ultimately in the advertising business.

I’m not going to talk about how to best craft your content for Reader Mode. Mandy Michael already covered this in her article, Building websites for Safari Reader Mode and other reading apps. She’s great, and it is a must-read piece.

Building with accessible HTML standards is not a dead-end skill. Far from it. If you spend the effort to craft your experiences with a mind to semantics from the start, your content will be able to adapt to specialized reading modes, as well as whatever the future holds with little to no additional effort. Today’s Reader Mode could be tomorrow’s smart bathroom mirror.

Spending the effort is an important point: Good design isn’t about forcing someone to walk a tightrope across your carefully manicured lawn. Nor is it a puzzle box casually tossed to the user, hoping they’ll unlock it to reveal a hidden treasure. Good design is about doing the hard work to accommodate the different ways people access a solution to an identified problem.

For reading articles, the core problem is turning my ignorance about an issue into understanding (the funding model for this is a whole other complicated concern). The more obstructions you throw in my way to achieve this goal, the more I am inclined to leave and get my understanding elsewhere—all I’ll remember is how poor a time I had while trying to access your content. What is the value of an ad impression if it ultimately leads to that user never returning?

But this isn’t a website about digital media strategy, nor is it one about user conversion. This is a website about CSS and front-end development. What we’re going to discuss is how to keep people like me from hitting that button by relying on this nifty programming language the W3C so wisely gave us. Because if you don’t, all that other stuff—your newsletter signup boxes, your comments, your related articles, your engagement—will be cut away.

Inclusivity

What you want to do first is cast a wide net. The more people you can proactively accommodate from the outset, the more people you don’t unintentionally alienate. Our design choices should be invisible—we’re not trying to say, “this is for you.” That should be self-evident. What we’re trying to avoid are scenarios where someone encounters something that communicates, “this is for someone else.”

It’s not too difficult, provided you know what to look out for. Carie Fisher outlines the bulk of it in her brilliant post, Designing Accessible Content: Typography, Font Styling, and Structure.

Priority

A basic paragraph style is the wellspring from which all your other type decisions should flow. It’s probably the most common and frequently invoked content type a website has, so it’s important to treat it with the care and respect it deserves. The web is typography, after all.

Heydon Pickering wrote about styling paragraphs way back when in 2011 with his post, The Perfect Paragraph. And here’s the thing: eight years later, this is all still solid advice (sheesh, I’ve been doing this for awhile). When you make design decisions that work with the grain of the web platform, you gain the confidence that you’re creating resilient, robust, and accessible solutions that last.

The neat part about this is that it frees up time to do other things, say reading about gender bias and the undervaluing of HTML and CSS. If anything, do it for me. I am honestly not sure I can handle another case of 2,000 lines of JavaScript used to recreate position: absolute;.

Circumstance

Form

Even though responsive design is nearly a decade old at this point(!), we still seem to ignore a lot of the wisdom Ethan Marcotte so nicely teaches us for free. He’s a smart guy, you should pay attention to what he has to say.

After a complete lack of breakpoints, perhaps the biggest offender I still come across with regards to responsive design is the assumption that a small viewport means teeny-tiny type. Typically, the opposite is true. Small devices are made to be worn or carried, meaning that we move them in physical space to get them into a comfortable reading position. This is the opposite of a larger, more stationary device, such as a monitor, where we move our body to accommodate it instead.

A comfortable reading position means not forcing someone to hold a phone two centimeters away from their face. Ergonomics aren’t likely to change, but devices will. Because of that, you should craft your breakpoint names to be abstract. I personally like names that keep usability in mind, so something along the lines of, “wrist, palm, lap, desk, wall.” It helps keep the user’s circumstance top-of-mind, and moves you away from associating only certain kinds of content as being viable on certain kinds of devices.

These ergonomically-derived designs can be achieved with the help from people like Rachel Andrew, whose in-depth explorations of CSS grid help us understand the power behind a real CSS layout system. Sass experts like Miriam Suzanne then teach us how to use True to codify these layouts and reliably integrate them into our larger Sass systems.

You also want to avoid fallacious device sniffing approaches, or making gross assumptions about a user’s circumstances and capabilities. Just let me increase and decrease that type size. Reader Mode lets me, so I’m going to get there one way or another.

Connection

The other thing you need to think about is how that ideal paragraph design actually gets served to a device. A big part of that involves loading our fonts, and ensuring that the loading process prioritizes user experience.

Text

Text downloads quickly; a lot faster than other exotic kinds of content. Browsers will render it gleefully, as it is historically the most important part of the payload. This means that the Reader Mode button is going to show up a lot faster than that distracting auto-playing video of talking heads so thoughtfully jammed into the bottom right-hand corner of my viewport.

And what if we’re on a slow, intermittent, and/or metered connection? Top-of-the-line MacBooks still have to use hotel wifi, just like everyone else.

You want to keep the page from jumping around when our paragraph font loads. This prevents the terrible experience of forcing me to scroll around to rediscover my place as things shift into place. It also helps prevent me from mis-clicking, taking me away from what I want to read because I had the audacity to interact with the page before the bitcoin miners are deployed (thankfully, good people like Laura Kalbag can help us with that one).

The temptation to hit that Reader Mode button is strong, because when I see the main text of the page show up, I know I can easily and reliably avoid all these potential issues.

Helen V. Holmes wrote Type is Your Right!, a beautiful article that effortlessly blends typographic history, capability, and performance. Notably, she discusses how to manage the Flash of Invisible Text (FOIT) and Flash of Unstyled Text (FOUT) to best corral all the aforementioned issues. In response, Monica Dinculescu made Font style matcher, a fantastic tool that lets you bend, stretch, squish, squash, and torture type in ways that would make your stodgy typography professor faint, all in the service of preventing layout jank.

Images

You can (and should) make all sorts of clever optimizations to ensure we’re delivering our images as efficiently as possible. But what happens while I’m waiting for those images to show up? What if they never do?

Since you’re a responsible, inclusive web professional, you’ve already made sure to include alternative text descriptions for our image content. Ire Aderinokun teaches us that you can take that one step further and style broken images. Now even the content that isn’t working as intended looks good. No brittle, overwrought JavaScript here—just good, old fashioned progressive enhancement.

The other type of image you want to consider are icons. There’s lots of reasons to not use icon fonts. Adding one more reason to toss on the pile: icon fonts may not hold up in Reader Mode, as they are constructed using text glyphs. When Reader Mode passes over a page, it may convert the glyph to use the font you specify. This could make for a disastrous experience, especially if the icon is used to communicate critical functionality (e.g. “Press the Home button (☒) to return to the main menu.”).

To avoid this issue, Sara Soueidan teaches us how to convert those icon fonts to SVG . But you know what? She’s so much more than just a SVG expert. She’s an incredible UX developer, and you’d do well to read up on what she’s written. I, for one, have learned a ton.

Control

To help make my reading experience as comfortable as possible, Reader Mode allows me to adjust things like the typeface, the text and background colors, the font size and line height, and the number of words per line. This is great. I’ll frequently toggle back and forth between light and dark backgrounds depending on the time of day.

I also wear glasses, and I know that the older I get, the worst my vision will be. Thanks to Jennifer Aldrich’s writing, I know that this is the norm. After all, we’re all just temporarily abled. I might also need something like Windows High Contrast Mode one day. Thanks to Amelia Bellamy-Royds, I now know how to make my content be the best it can be when viewed in that mode.

The web is flexible. Working on it means getting over your ego and learning to let go. That means accepting that the medium will never be pixel perfect. It means embracing technology like relative units, and more importantly, philosophies like Intrinsic Web Design. That’s brought to us by Jen Simmons, a tireless and passionate advocate for web standards.


I’d love to read your website. I’d love for your harmonious typography to quietly usher me into a flow state, making me forget I was even browsing your site at all.


Reader Mode: The Button to Beat originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/reader-mode-the-button-to-beat/feed/ 6 280754
The possibilities of the color-adjust property https://css-tricks.com/the-possibilities-of-the-color-adjust-property/ https://css-tricks.com/the-possibilities-of-the-color-adjust-property/#comments Tue, 14 Aug 2018 16:22:24 +0000 http://css-tricks.com/?p=274705 The color-adjust property has been renamed to print-color-adjust.

The Open Web continues to show up in places we would have never originally expected to find it: our phones, televisions, watches, books, video game consoles, fast food menus, gas pumps, …


The possibilities of the color-adjust property originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
The color-adjust property has been renamed to print-color-adjust.

The Open Web continues to show up in places we would have never originally expected to find it: our phones, televisions, watches, books, video game consoles, fast food menus, gas pumps, elevators, cars—even our refrigerators.

By not making too many or too strict assumptions about how the web should be used, it remains flexible and adaptable. These qualities have allowed it to outperform closed technologies like Flash and Silverlight.

With the web’s growth comes new features to better accommodate its new form factors and use cases. One feature I’m excited about is the color-adjust property, proposed in CSS Color Module Level 4. It is an acknowledgement that the web will continue to show up on devices that have less-than-stellar displays.

There are two values for color-adjust: economy and exact. A value of exact tells the browser it shouldn’t make adjustments to the colors declared in the stylesheet:

.card { 
  background-color: #98b3c7;
  border-bottom: 0.25rem solid #7c92a3;
  color: #f3f3f3;
  color-adjust: exact;
  ...
}

The color-adjust: exact; declaration in this example forces the browser to render all colors as accurately as possible on anything with a class of card applied to it. Accurate meaning being as close as possible based on the host device’s best ability.

The description for the economy value in the specification reads as, “The user agent should make adjustments to the page’s styling as it deems necessary and prudent for the output device.” It places trust in the browser’s hands, allowing it to make adjustments to color values as it sees fit.

Best ability

Handing control over to a browser might seem a little scary at first. As an industry, we’re really great at bikeshedding the heck out of color systems. And that’s a great thing! The use of color, including proper contrast ratios, is an incredibly important aspect of design, and can oftentimes make or break a product.

But we need to understand that our platonically ideal design might not be able to be experienced in the real world as intended. Not everyone owns a device that outputs to a Retina display with a luxurious DCI-P3 color space; nor do they always have perfect vision or ideal lighting conditions. In these kinds of circumstances, it’s better to bend, not break.

We now live in a Mobile, Small, Portrait, Slow, Interlace, Monochrome, Coarse, Non-Hover, First world. Limited color displays aren’t as rare as you think, and are probably only going to get more commonplace as time goes on. I’d especially like to call attention to the rise of internet use by low income populations and emerging markets. With that comes cheaper devices with lower-quality displays.

Browser support

At the time of this article’s publishing, color-adjust has been supported since Firefox 48 (and Android Firefox 60):

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

Desktop

ChromeFirefoxIEEdgeSafari
19*48No79*6*

Mobile / Tablet

Android ChromeAndroid FirefoxAndroidiOS Safari
126127126*15.4

Chrome and Safari, both WebKit browsers, require a vendor-prefixed declaration of -webkit-print-color-adjust. Curiously, -webkit-print signals that their implementation of this property is only intended for print. While the W3C documentation does mention use cases for printing, it is phrased in such a way as to not be limited to it.

People still print webpages! Paper doesn’t require a data plan, nor does its connection drop when you go underground. Just yesterday, I saw someone on the train who was using a collection of printed sites to study for their next exam. And here’s your galaxy brain moment: printed pages are just limited color displays.

I’d also be remiss if I didn’t mention situations where print styles are missing or poorly-authored, potentially forcing a printer to waste ink in an attempt to do what the stylesheet asks of it. Printer ink is hideously expensive—minding this does your (or your IT department’s) budget a solid.

Potential uses

Before we get any further, I want to state the following is all personal theorizing based off the phrasing in the W3C specification—targeting, but not limited to printing.

I think color-adjust could be one of those properties that could find a home explicitly declared in the body selector, where it can best take advantage of the Cascade:

body {
  color-adjust: economy;
  ...
}

This declaration says, “Every time I declare color in this website, use the values I specify. If you can’t, that’s cool—do what you think is best.” That’s a lot better than the browser trying to literally interpret styling instructions at all cost, potentially rendering the page as completely illegible.

You could declare color-adjust in a more specific way, say nested in a @supports at-rule inside of a print media query, but that’s unnecessary extra work. It would fail to accommodate things like High Contrast Mode and the upcoming color gamut media feature. Better to embrace the unknown and cast a wide net.

I’m also very curious to see how color-adjust could work in conjunction with other browser capabilities, say the Ambient Light Sensor API (RIP Battery Status API). It’d be neat if there were opportunities to experiment with other specialized display modes—macOS’ Night Shift, Increased Contrast, Grayscale, and Reduce Transparency options all come to mind.

A note about accessibility

I’m wondering if software (browser preference toggle or extension, bookmarklet, etc.) could be written to override what the device’s hardware reports itself as being. Much like User Agent spoofing, it could “trick” a browser into thinking it has a limited color display, using economy to force better contrast between text and background color. This would be a lot like some browser’s reading modes, only page layout would be better preserved.

That being said, I don’t think color-adjust is a silver bullet for all color-related accessibility concerns. We can’t always know the device and context our websites and web apps will show up in, including what colors color-adjust would ultimately render as. Because of this, it’s still important to mind your color contrast ratios.

Bending, not breaking

color-adjust feels like a natural extension of Jen Simmons’ Intrinsic Web Design: fluid and squishy UI, proportional sizing, media queries as needed, and simple declarations that do the heavy lifting.

The beauty of the CSS Cascade means you can gracefully create intent, then adjust as needed. color-adjust‘s documentation specifically mentions a situation where it could be useful to ensure a table’s zebra striping is is retained when printed to make it easier to read. Such a tweak can be scoped to a single selector, without having to spend time undoing it for every other component.

body {
  color-adjust: economy;
  ...
}

tr {
  color-adjust: exact;
}

The beauty of CSS’ fault tolerance means browsers that don’t understand this declaration will ignore it and continue parsing the rest of of the stylesheet. Browsers that do support it can take advantage of it, without any complicated build tool configuration or dangerous User Agent sniffing.

It is important to make our web sites and web apps design adapt to the user’s environment and circumstances, and not the other way around. Good user experiences meet the user where they are, not where we hope they’ll be.


The possibilities of the color-adjust property originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/the-possibilities-of-the-color-adjust-property/feed/ 2 274705
Focusing on Focus Styles https://css-tricks.com/focusing-on-focus-styles/ https://css-tricks.com/focusing-on-focus-styles/#comments Thu, 29 Mar 2018 17:14:42 +0000 http://css-tricks.com/?p=268452 Not everyone uses a mouse to browse the internet. If you’re reading this post on a smartphone, this is obvious! What’s also worth pointing out is that there are other forms of input that people use to get things done. …


Focusing on Focus Styles originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
Not everyone uses a mouse to browse the internet. If you’re reading this post on a smartphone, this is obvious! What’s also worth pointing out is that there are other forms of input that people use to get things done. With these forms of input comes the need for focus styles.

People

People are complicated. We don’t necessarily perform the same behaviors consistently, nor do we always make decisions that make sense from an outsider’s perspective. Sometimes we even do something just to… do something. We get bored easily: tinkering, poking, and prodding things to customize them to better suit our needs, regardless of their original intent.

People are also mortal. We can get sick and injured. Sometimes both at once. Sometimes it’s for a little while, sometimes it’s permanent. Regardless, it means that sometimes we’re unable to do things we want or need to do in the way we’re used to.

People also live in the world. Sometimes we’re put into an environment where external factors conspire to prevent us from doing something the way that we’re accustomed to doing it. Ever been stuck at your parents’ house during the holidays and had to use their ancient-yet-still-serviceable desktop computer? It’s like that.

Input

Both mouse and touch input provide an indicator for interaction. For touch, it is obvious: Your finger acts as the bridge that connects your mind to the item on the screen it wants to activate. For mice, a cursor serves as a proxy for your finger.

However, these aren’t the only forms of input available to us. Keyboards are ubiquitous and can do just about anything a mouse or touch input can accomplish, provided you know all the right keys to press in the right order. Sometimes it’s even easier and faster than using a mouse!

Think about the last time you were using Cut, Copy, Paste, and Save functionality. Maybe it was the last time you were working on a spreadsheet? Were you switching between mouse and keyboard input to get things done as efficiently as possible? You probably didn’t give that behavior a second thought, but it’s a great example of switching input on the fly to best accomplish a goal. Heck, maybe you even took some “me time” during this thankless task to poke the Like button on Facebook on your smartphone.

If you have trouble using your hands, other options are available: Wands, sticks, switches, sip and puff devices, voice recognition, and eye tracking technology can all create input in a digital system. These devices will identify a content area and activate it. This is similar to how you can hit the tab key on a keyboard and the next cell in a spreadsheet will be highlighted, indicating that it has been moved to and is ready to be edited.

In this video, video editor and accessibility consultant Christopher Hills demonstrates the capabilities of Switch Control, software that helps people experiencing motor control impairments use hardware switches to operate their computing devices.

It’s worth pointing out that you could be relying on this technology one day, even if it’s only for a little bit. Maybe you broke both of your arms in an unfortunate mountain biking accident, and want to order some self-pity takeout while you recuperate. Maybe you’re driving and want to text your family safely. Or maybe you’ll just get old. It’s not difficult to think of other examples, it’s just not a concept people like to dwell on.

If it’s interactive, it needs a focus style

We can’t always know who is visiting our websites and web apps, why they’re visiting, what they’re going to do when they get there, what conditions they are experiencing, what emotions they’re feeling, or what input they may use. Analytics might provide some insight, but does not paint a full picture. It’d be foolish to have the tail wag the dog and optimize the entire experience based on this snapshot of limited information.

It’s also important to know that not everyone who uses assistive technology wants to be identified as an assistive technology user. Nor should they be forced to disclose this. Power users—people who leverage keyboard shortcuts, specialized software, and browser extensions—may appear to navigate like a user of assistive technology, yet may not be experiencing any disability conditions. Again, people are complicated!

What we can do is preemptively provide an experience that works for everyone, regardless of ability or circumstance.

Identify and activate

:focus

With these alternate forms of input, how do we identify something to show it can be activated? Fortunately, CSS has this problem handled—we use the :focus and :active selectors.

The grammar is straightforward. Want to outline a link in orange when a user focuses on it? Here’s how to describe it:

a:focus {
  outline: 3px solid orange;
}

This outline will appear when someone navigates to the link, be it by clicking or tapping, tabbing to it via keyboard input, or using switch input to highlight it.

A common misconception is that the focus style can only use the outline property. It’s worth noting that :focus is a selector like any other, meaning that it accepts the full range of CSS properties. I like to play with background color, underlining, and other techniques that don’t adjust the component’s current size, so as to not shift page layout when the selector is activated.

Then say we want to remove the link’s underline when activated to communicate a shift in state. Remember: links use underlines!

a:active {
  text-decoration: none;
}

It’s important to make sure the state changes, from resting to focused to activated, are distinct. This means that each transition should be unique when compared to the component’s other states, allowing the user to understand that a change has occurred.

We also want to make sure these state changes don’t rely on color alone, to best accommodate people experiencing color blindness and/or low vision. Here’s how a color-only state change might look to a person with Deuteranopia, commonly known as Red-Green colorblindness:

I purposely removed the underline and the browser’s native focus ring from the link in the video to better illustrate the issue of discoverability. When trying to tab around the page to determine what is interactive, it isn’t immediately obvious that there is a link present. If colorblindness is also a factor, the state change when hovered won’t be apparent—this is even more apparent with the addition of cataracts.

:focus-within

:focus-within—a focus-related pseudo class selector with a very Zen-sounding name—can apply styling to a parent element when one of its children receives focus. The focus event bubbles out until it encounters a CSS rule asking it to apply its styling instructions.

A common use case for this selector would be to apply styling to an entire form when one of its input elements receives focus. In the example below, I’m scaling up the size of the entire form slightly, unless the user has expressed a desire for a reduced animation experience:

See the Pen :focus-within Demo by Eric Bailey (@ericwbailey) on CodePen.

The selector is still relatively new, so I’m sure we’ll get more clever applications as time goes on.

Politics

People also have opinions. Unfortunately, sometimes these opinions are uninformed. Outside the practice of accessibility there’s the prevalent notion that focus styles are “ugly” and many designers and developers remove them for the sake of perceived aesthetics. Sometimes they’re not even aware they’re propagating someone else’s opinion—many CSS resets include a blanket removal of focus styles and are incorporated as a foundational project dependency with no questions asked.

This decision excludes people. Websites and web apps aren’t close-cropped trophies to be displayed without context on a dribbble profile, nor are they static screenshots on a slick corporate sales deck. They exist to be read and acted upon, and there’s rules that help ensure that the largest possible amount of people can do exactly that.

:focus-visible

The fact of the matter is that sometimes people will insist on removing focus styles, and have enough clout to force their cohorts to carry out their vision. This flies in the face of rules that stipulate that focus mechanisms must be visible for websites to be truly accessible. To get around this, we have the :focus-visible pseudo-selector.

:focus-visible pseudo-selector styling kicks in when the browser determines that a focus event occurred, and User Agent heuristics inform it that non-pointer input is being used. That’s a fancy way of saying it shows focus styling when activated via input via other than mouse cursor or finger tap.

The video of this CodePen demonstrates how different styling is applied based on the kind of input the link receives. When a link is hovered and clicked on via mouse input, its underline is removed and shifts down slightly. When tabbed to via keyboard input, :focus-visible applies a stark background color to the link instead.

Chromium has recently announced its intent to implement :focus-visible. Although browser support is currently extremely limited, a polyfill is available. Both it and :focus-within are in the Selectors Level 4 Editor’s Draft, and therefore likely to have native support in the major browsers sooner than later.

You may know :focus-visible by its other name, :-moz-focusring. This vendor prefixed pseudo-selector is Mozilla’s implementation of the idea, predating the :focus-visible proposal by seven years. Unlike other vendor prefixed CSS, we’re not going to have to worry about autoprefixing support! Firefox honors a :focus-visible declaration as well as :-moz-focusring, ensuring there will be parity for our selector names between the two browsers.

One step forward, one step back

Browser support is a bit of a rub—the web is more than just Chrome and Firefox. While the polyfill may provide support where there is none natively, it’s extra data to download, extra complexity to maintain, and extra fragility added to your payload.

There’s also the fact that devices are far less binary about their input types than they used to be. The Surface, Microsoft’s flagship computer, offers keyboard, trackpad, stylus, camera, voice, and touch capability out of the box. WebAIM’s 2017 Screen Reader Survey revealed that mobile devices may be augmented by keyboard input more than you may think. Heuristics are nice, but like analytics, may not paint a complete picture.

Another point to consider is that focus styles can be desirable for mouse users. Their presence is a clear and unambiguous indication of interactivity, which is a great affordance for people with low vision conditions, cognitive concerns, and people who are less technologically adept. Extraordinarily technologically adept people, ones who grok that screen readers and keyboard shortcuts are essentially Vim for a GUI, will want the focus state to be apparent as they use the keyboard to dance across the screen.

Part of building a robust, resilient web involves building a strong core experience that works in every browser. The vanilla :focus selector enjoys both wide and deep support to the degree that it’s a safe bet that even exotic browsers will honor it.

The world is full of things that some people may see as ugly, while others find them to be beautiful. Personally, I don’t see focus styles as an eyesore. As a designer, I think that it’s a foundational part of creating a mature design system. As a developer, describing state is just business as usual. As a person, I enjoy helping to keep the web open and accessible, as it was intended to be.


If you’d like to learn more about the subject, UX Designer Caitlin Geier has a great writeup on focus indicators.


Focusing on Focus Styles originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/focusing-on-focus-styles/feed/ 7 268452
Building a Good Download… Button? https://css-tricks.com/building-good-download-button/ https://css-tricks.com/building-good-download-button/#comments Wed, 31 Jan 2018 14:42:03 +0000 http://css-tricks.com/?p=265869 The semantics inherent in HTML elements tell us what we’re supposed to use them for. Need a heading? You’ll want a heading element. Want a paragraph? Our trusty friend <p> is here, loyal as ever. Want a download? Well, you’re …


Building a Good Download… Button? originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
The semantics inherent in HTML elements tell us what we’re supposed to use them for. Need a heading? You’ll want a heading element. Want a paragraph? Our trusty friend <p> is here, loyal as ever. Want a download? Well, you’re going to want… hmm.

What best describes a download? Is it a triggered action, and therefore should be in the domain of the <button> element? Or is it a destination, and therefore best described using an <a> element?

Buttons Do Things, Links Go Places

There seems to be a lot of confusion over when to use buttons and when to use links. Much like tabs versus spaces or pullover hoodies versus zip-ups, this debate might rage without end.

However, the W3C provides us with an important clue as to who is right: the download attribute.

The What Now?

The internet as we know it couldn’t exist without links. They form the Semantic Web, the terribly wonderful, wonderfully terrible tangled ball of information that enables you to read this article at this very moment.

Like all other elements, anchor links can be modified by HTML’s global attributes. Anchor link elements also possess a number of unique attributes that help control how they connect to other documents and files.

One of those attributes is called download. It tells the browser that the destination of the link should be saved to your device instead of visiting it. You’re still “navigating” to the file, only instead of viewing it, you’re snagging a copy for your own use.

Any kind of file can be a download! This even includes HTML, something the browser would typically display. The presence of the attribute is effectively a human-authored flag that tells the browser to skip trying to render something it has retrieved and just store it instead:

<a download href="recipe.html">
  Download recipe
</a>

This raises a very important point: we can’t know every user’s reason for why they’re visiting our website, but we can use the tools made available to us to help guide them along their way. If that means storing an HTML document for use offline, we’re empowered to help make the experience as easy as possible.

Other Evidence

Still not convinced? Here’s some more food for thought:

Progressive Enhancement

JavaScript is more brittle than we care to admit. <a> elements function even if JavaScript breaks. Using anchors for your download means that a person can access what they need, even in suboptimal situations.

A robust solution is always the most desirable—in a time of crisis, it might even save a life. This might sound hyperbolic, but having a stable copy of something that works offline could make all the difference in a time of need.

Semantics and Accessibility

My friend Scott, who is paid to know these kinds of things, tells us:

The debate about whether a button or link should be used to download a file is a bit silly, as the whole purpose of a link has always been to download content. HTML is a file, and like all other files, it needs to be retrieved from a server and downloaded before it can be presented to a user.

The difference between a Photoshop file, HTML, and other understood media files, is that a browser automatically displays the latter two. If one were to link to a Photoshop .psd file, the browser would initiate a document change to render the file, likely be all like, “lol wut?” and then just initiate the OS download prompt.

The confusion seems to come from developers getting super literal with the “links go places, buttons perform actions.” Yes, that is true, but links don’t actually go anywhere. They retrieve information and download it. Buttons perform actions, but they don’t inherently “get” documents. While they can be used to get data, it’s often to change state of a current document, not to retrieve and render a new one. They can get data, in regards to the functionality of forms, but it continues to be within the context of updating a web document, not downloading an individual file.

Long story short, the download attribute is unique to anchor links for a reason. download augments the inherent functionality of the link retrieving data. It side steps the attempt to render the file in the browser and instead says, “You know what? I’m just going to save this for later…”

Thanks, Scott!

Designing a Good Download Link

The default experience of downloading a file can be jarring—it typically isn’t part of our normal browsing behavior. The user has to shift their mental model from flitting from page-to-page and filling out forms to navigating a file system and extracting compressed archives. For less technologically-savvy individuals, it can be a disorienting and frustrating context shift.

As responsible designers and developers, we want to make the experience of interacting with a download link as good as it possibly can be. As we can’t modify how the browser’s download behavior itself operates, we should make the surrounding user experience as transparent and streamlined as possible.

Tell Me What’s in Store

Give the user as much information as you can to help inform them on what’s about to happen. Anticipating and answering the following questions can help:

What?

Verb plus noun is the winning combination. Describe what the link does and what it gets you:

<a download href="downloads/fonts.zip">
  Download Fonts
</a>

By itself, the verb Download would only signal what behavior will be triggered when the link is activated. Including the noun Fonts is great for removing ambiguity about what you’ll be getting.

In cases where there’s multiple download links on a page, the presence of the noun will help users navigating via screen reader. Here’s what it would sound like if you were browsing a page that had eight noun-less download links:

Do you know which one of those eight links gets you what you want? No? That’s not great. Similarly, the presence of the download attribute on an <a> element won’t be announced by screen readers, so the verb is equally vital. It’s important to provide context!

Remember that obvious always wins. While it is possible to make your compliance checks happy by using a visually hidden CSS class to hide the noun portion of your download, it places extra cognitive burden on your users. A hidden noun also sacrifices functionality like the browser’s search-on-page capability.

How Long?

KB, MB, GB, TB. We’re not talking about Kobe Beef, Mega Bloks, Ginkgo Biloba, or Tuberculosis. We’re talking about the size of the download, and consequently how long it will take for the download to finish.

Know your audience. A file with a size of 128 KB will download much faster than a file with a size of 2 GB, yet its number is drastically larger. Unless your audience has familiarity with the terminology used to describe file size, they may not understand what they’re getting themselves into if you only tell them the size of the payload.

For larger files, the wait time can be especially problematic. A standard download is an all-or-nothing affair—interruptions can corrupt them and render them useless. Worse, it can waste valuable data on a metered data plan, an unfortunately all-too-relevant concern.

It is also incredibly difficult to accurately ascertain someone’s current connection speed. While the Network Information API looks promising, current browser support isn’t so hot.

There is hidden nuance living in the gap between reported and actual connection. A high speed 5G connection could drop the second someone enters a tunnel or walks to a spot in their house where coverage isn’t good. This isn’t even beginning to cover the complexities involved with throttling, an unfortunately all-too-real concern.

To address these issues, apply a little micro-copy:

See the Pen Download movie by Eric Bailey (@ericwbailey) on CodePen.

Your user is going to know the particulars of their connection quality better than you ever will. Now they have what they need to make an informed decision, with a little intentional ambiguity to temper expectations.

But what about progress bars?

Progress bars are UI elements that show how close a computational task is to completion. For UX designers, they’re a staple (and an opportunity to play around with perceived performance). However, I’m wary of employing them when it comes to downloads.

At best, they’re redundant. Browsers already supply UI to indicate how the download is progressing. At worst, they’re a confusing liability. Adding them introduces unnecessary implementation and maintenance complications—especially when combined with the issues in determining connection speed and quality outlined earlier.

Why?

Sell the user on why they should care. Will it remove frustration by fixing an existing problem? Will it increase enjoyment by adding a new feature? Will it reassure by making things more secure? While not every download needs the “why?” question answered, it is good to have for payloads with a complicated or esoteric purpose.

If I am downloading router firmware, I may not understand (or care about) the nitty-gritty of what the update does behind the scenes. However, some high-level communication about why I need to undertake the endeavor will go a long way.

See the Pen Describe what the download does by Eric Bailey (@ericwbailey) on CodePen.

What Next?

Instructions on what to do after the download has completed could be useful. Again, knowing your audience is key.

With our router example, it is entirely possible that less technically-savvy individuals will find themselves on the product support page. It’s also highly possible that they’re in a distressed emotional state when they arrive. After a download has been initiated, step-by-step information on how to install the new firmware, as well as links to relevant support resources could go a long way to alleviating negative feelings.

This is practical empathy. Anticipating the user’s needs and emotional state and preemptively offering solutions has a direct effect on things like reducing expensive support calls. These savings means organizational resources can be reallocated to other important endeavors.

Taking it to Code

Signal That it’s Different

Links use underlines.

A good practice from both a user experience and an accessibility perspective is to create a distinction between internal and external links. This means creating an indicator that a link does something other than take you to another place on your website or webapp. For links that go off-site, a common practice is to use an arrow breaking out of a box. For downloads, a downward-facing arrow is the de facto standard.

Examples of icons for downloads (top) and external links (bottom). Courtesy of Noun Project.

Some may feel that the presence of the download attribute is redundant when applied to links the browser already knows to store. I disagree.

In addition to being an unambiguous semantic marker in the HTML, the download attribute can serve as a simple and elegant styling hook. CSS attribute selectors—code that lets us create styling based on the qualities that help describe HTML elements—allow us to target any link that is a download and style it without having to attach a special class:

a[download] {
  color: hsla(216, 70%, 53%, 1);
  text-decoration: underline;
}

a[download]::before {
  content: url('../icons/icon-download.svg');
  height: 1em;
  position: relative;
  top: 0.75em;
  right: 0.5em;
  width: 1em;
}

a[download]:hover,
a[download]:focus {
  text-decoration: none;
}

Combined with the text describing the download, the presence of the icon clearly communicates that when you activate this link, download behavior will follow. It also provides extra target area, great for touch devices.

Targeting both the presence of the download attribute and the file extension at the end of the string in the href attribute allows us to get even fancier. We can take advantage of the cascade to set up a consistent treatment for all icons, but change the icon itself on a per-filetype basis. This is great for situations where there are multiple kinds of things you can download on a single page:

See the Pen Download icons by Eric Bailey (@ericwbailey) on CodePen.

I maintain a list of common filetypes, if you’re looking for a starting point. Remember to only include the selectors you need, so as to not create unnecessary bloat in your production CSS. If your website or webapp features many icons and/or a lot of fancy state management, consider using a SVG icon system instead. It will improve performance—just remember to make it accessible!

Name the Payload

The download attribute can accept an optional value, allowing the author to create a custom, human-friendly name for the downloaded file. In this example, we’re changing the name of a podcast episode to something that makes sense when downloaded to the user’s device, while maintaining something that makes sense to the podcast’s producer:

<a 
  download="Pod-People-Podcast-Episode-12-Feed-Me-Seymour.mp3"
  href="https://www.dropbox.com/s/txf5933cwxhv1so6/12-final-v5-RADIO-EDIT.m4a?dl=0">
  Download Episode 12
</a>

For complicated sites, this attribute allows us to create downloads that make sense to the person requesting them, while also taking advantage of features like CDNs and dynamically-generated files. Not a lot of complicated backend sorcery here, just a little template logic:

<a 
  href="https://s3-us-west-2.amazonaws.com/ky22o6s6g8be80bak577b17e34bb93cex3.pdf"
  download="{{ user.name | slugify }}-{{ 'now' | date: "%Y" }}-tax-return.pdf">
  Download your {{ 'now' | date: "%Y" }} Tax Return
</a>

Material Honesty

Keeping content looking and behaving like the HTML elements used to describe it is great for reinforcing external consistency. Externally consistent content is great for ensuring people can, and will use your website or webapp. Use is great for engagement, a metric that makes business-types happy.

And yet, link-y buttons and button-y links are everywhere.

We can lay blame for this semantic drift squarely at the feet of trend. Designers and developers eager to try the latest and greatest invite ambiguity in with outstretched arms. Leadership chases perceived value to stay relevant.

It doesn’t have to be this way. Websites can be both beautiful and accessible. Semantics and current frameworks/aesthetics aren’t mutually exclusive. Take a little time to review the fundamentals—you just might discover something simple that helps everyone get what they need with just a little bit less fuss.


Building a Good Download… Button? originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/building-good-download-button/feed/ 11 265869
ARIA is Spackle, Not Rebar https://css-tricks.com/aria-spackle-not-rebar/ https://css-tricks.com/aria-spackle-not-rebar/#comments Wed, 08 Nov 2017 15:05:51 +0000 http://css-tricks.com/?p=262085 Much like their physical counterparts, the materials we use to build websites have purpose. To use them without understanding their strengths and limitations is irresponsible. Nobody wants to live in an poorly-built house. So why are poorly-built websites acceptable?

In …


ARIA is Spackle, Not Rebar originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
Much like their physical counterparts, the materials we use to build websites have purpose. To use them without understanding their strengths and limitations is irresponsible. Nobody wants to live in an poorly-built house. So why are poorly-built websites acceptable?

In this post, I’m going to address WAI-ARIA, and how misusing it can do more harm than good.

Materials as technology

In construction, spackle is used to fix minor defects on interiors. It is a thick paste that dries into a solid surface that can be sanded smooth and painted over. Most renters become acquainted with it when attempting to get their damage deposit back.

Rebar is a lattice of steel rods used to reinforce concrete. Every modern building uses it—chances are good you’ll see it walking past any decent-sized construction site.

Technology as materials

HTML is the rebar-reinforced concrete of the web. To stretch the metaphor, CSS is the interior and exterior decoration, and JavaScript is the wiring and plumbing.

Every tag in HTML has what is known as native semantics. The act of writing an HTML element programmatically communicates to the browser what that tag represents. Writing a button tag explicitly tells the browser, “This is a button. It does buttony things.”

The reason this is so important is that assistive technology hooks into native semantics and uses it to create an interface for navigation. A page not described semantically is a lot like a building without rooms or windows: People navigating via a screen reader have to wander around aimlessly in the dark and hope they stumble onto what they need.

ARIA stands for Accessible Rich Internet Applications and is a relatively new specification developed to help assistive technology better communicate with dynamic, JavaScript-controlled content. It is intended to supplement existing semantic attributes by providing enhanced interactivity and context to screen readers and other assistive technology.

Using spackle to build walls

A concerning trend I’ve seen recently is the blind, mass-application of ARIA. It feels like an attempt by developers to conduct accessibility compliance via buckshot—throw enough of something at a target trusting that you’ll eventually hit it.

Unfortunately, there is a very real danger to this approach. Misapplied ARIA has the potential to do more harm than good.

The semantics inherent in ARIA means that when applied improperly it can create a discordant, contradictory mess when read via screen reader. Instead of hearing, “This is a button. It does buttony things.”, people begin to hear things along the lines of, “This is nothing, but also a button. But it’s also a deactivated checkbox that is disabled and it needs to shout that constantly.”

If you can use a native HTML element or attribute with the semantics and behavior you require already built in, instead of re-purposing an element and adding an ARIA role, state or property to make it accessible, then do so.
First rule of ARIA use

In addition, ARIA is a new technology. This means that browser support and behavior is varied. While I am optimistic that in the future the major browsers will have complete and unified support, the current landscape has gaps and bugs.

Another important consideration is who actually uses the technology. Compliance isn’t some purely academic vanity metric we’re striving for. We’re building robust systems for real people that allow them to get what they want or need with as little complication as possible. Many people who use assistive technology are reluctant to upgrade for fear of breaking functionality. Ever get irritated when your favorite program redesigns and you have to re-learn how to use it? Yeah.

The power of the Web is in its universality. Access by everyone regardless of disability is an essential aspect.
– Tim Berners-Lee

It feels disingenuous to see the benefits of the DRY principal of massive JavaScript frameworks also slather redundant and misapplied attributes in their markup. The web is accessible by default. For better or for worse, we are free to do what we want to it after that.

The fix

This isn’t to say we should completely avoid using ARIA. When applied with skill and precision, it can turn a confusing or frustrating user experience into an intuitive and effortless one, with far fewer brittle hacks and workarounds.

A little goes a long way. Before considering other options, start with markup that semantically describes the content it is wrapping. Test extensively, and only apply ARIA if deficiencies between HTML’s native semantics and JavaScript’s interactions arise.

Development teams will appreciate the advantage of terse code that’s easier to maintain. Savvy developers will use a CSS-Trick™ and leverage CSS attribute selectors to create systems where visual presentation is tied to semantic meaning.

input:invalid,
[aria-invalid] {
  border: 4px dotted #f64100;
}

Examples

Here are a few of the more common patterns I’ve seen recently, and why they are problematic. This doesn’t mean these are the only kinds of errors that exist, but it’s a good primer on recognizing what not to do:

<li role="listitem">Hold the Bluetooth button on the speaker for three seconds to make the speaker discoverable</li>

The role is redundant. The native semantics of the li element already describe it as a list item.

<p role="command">Type CTRL+P to print</p>

command is an Abstract Role. They are only used in ARIA to help describe its taxonomy. Just because an ARIA attribute seems like it is applicable doesn’t mean it necessarily is. Additionally, the kbd tag could be used on “CTRL” and “P” to more accurately describe the keyboard command.

<div role="button" class="button">Link to device specifications</div>

Failing to use a button tag runs the risk of not accommodating all the different ways a user can interact with a button and how the browser responds. In addition, the a tag should be used for links.

<body aria-live="assertive" aria-atomic="true">

Usually the intent behind something like this is to expose updates to the screen reader user. Unfortunately, when scoped to the body tag, any page change—including all JS-related updates—are announced immediately. A setting of assertive on aria-live also means that each update interrupts whatever it is the user is currently doing. This is a disastrous experience, especially for single page apps.

<div aria-checked="true"></div>

You can style a native checkbox element to look like whatever you want it to. Better support! Less work!

<div role="link" tabindex="40">
  Link text
</div>

Yes, it’s actual production code. Where to begin? First, never use a tabindex value greater than 0. Secondly, the title attribute probably does not do what you think it does. Third, the anchor tag should have a destination—links take you places, after all. Fourth, the role of link assigned to a div wrapping an a element is entirely superfluous.

<h2 class="h3" role="heading" aria-level="1">How to make a perfect soufflé every time</h2>

Credit is where credit’s due: Nicolas Steenhout outlines the issues for this one.

Do better

Much like content, markup shouldn’t be an afterthought when building a website. I believe most people are genuinely trying to do their best most of the time, but wielding a technology without knowing its implications is dangerous and irresponsible.

I’m usually more of a honey-instead-of-vinegar kind of person when I try to get people to practice accessibility, but not here. This isn’t a soft sell about the benefits of developing and designing with an accessible, inclusive mindset. It’s a post about doing your job.

Every decision a team makes affects a site’s accessibility.
Laura Kalbag

Get better at authoring

Learn about the available HTML tags, what they describe, and how to best use them. Same goes for ARIA. Give your page template semantics the same care and attention you give your JavaScript during code reviews.

Get better at testing

There’s little excuse to not incorporate a screen reader into your testing and QA process. NVDA is free. macOS, Windows, iOS and Android all come with screen readers built in. Some nice people have even written guides to help you learn how to use them.

Automated accessibility testing is a huge boon, but it also isn’t a silver bullet. It won’t report on what it doesn’t know to report, meaning it’s up to a human to manually determine if navigating through the website makes sense. This isn’t any different than other usability testing endeavors.

Build better buildings

Universal Design teaches us that websites, like buildings, can be both beautiful and accessible. If you’re looking for a place to start, here are some resources:


ARIA is Spackle, Not Rebar originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/aria-spackle-not-rebar/feed/ 3 262085
Keeping track of letter-spacing, some guidelines https://css-tricks.com/keeping-track-letter-spacing-guidelines/ https://css-tricks.com/keeping-track-letter-spacing-guidelines/#comments Wed, 04 Oct 2017 14:55:17 +0000 http://css-tricks.com/?p=260620 Considering that written words are the foundation of any interface, it makes sense to give your website’s typography first-class treatment. When setting type, the details really do matter. How big? How small? How much line height? How much letter-spacing? …


Keeping track of letter-spacing, some guidelines originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
Considering that written words are the foundation of any interface, it makes sense to give your website’s typography first-class treatment. When setting type, the details really do matter. How big? How small? How much line height? How much letter-spacing? All of these choices affect the legibility of your text and can vary widely from typeface to typeface. It stands to reason that the more attention paid to the legibility of your text, the more effectively you convey a message.

In this post, I’m going to dive deep into a seemingly simple typesetting topic—effective use of letter-spacing—and how it relates to web typography.

Some history

Letter-spacing, or character spacing, is the area between all letters in a line of text. Manipulation of this space is intended to increase or decrease the visual density of a line or block of text.

When working in print, typographers also refer to it as tracking. It is not to be confused with kerning, which refers to the manipulation of space between two individual letters. Kerning is not usually practiced on the web.

See the Pen.

Historically, manipulating letter-spacing was a technique frequently used when laying out newspapers. The pressure of quick deadlines meant that reporters didn’t have the luxury of being able to rewrite sentences to better fit the physical space allotted for them on the page. To work around this, designers would insert spacing between the letters—first by hand and then later digitally—so that a line of type would better fill the allotted space.

On the web where available space is potentially infinite, letter-spacing is usually employed for its other prominent historical use case: creating a distinct aesthetic effect for content such as titles and headlines, pull quotes, and banners.

While fine typographic control on the web is only a recent development, the ability to perform letter-spacing has been around since CSS1. Naturally, the name of this property is called letter-spacing.

letter-spacing accepts various kinds of lengths as a value. Unlike its physical counterpart, it can be set to a negative measurement, which moves the letters closer together instead of further apart. When setting print type, no competent typesetter would have cut chunks out of their lead type to achieve this effect. However, when your letters are virtual, you can do whatever you want with them!

Stealing Sheep

In researching the history of letter-spacing, you’re likely to run across a famous quote by type designer Frederic Goudy. The—ahem—clean version is, “Anyone who would letter-space lower case would steal sheep.” Essentially, Goudy is saying that manipulating type without knowing the rules is bad.

Some have taken this quote at face value and sworn to never apply letter-spacing to content containing any amount of lower case text. While I would never presume to be as skilled or as knowledgeable about typography as Goudy, I would caution against the pitfalls of dogmatism.

There are situations where it would be advantageous to apply letter-spacing to large sections of text, so long as it is in the service of optimizing legibility. For example, a judicious application of letter-spacing applied to legal copy or agate provides a much-needed assist in a situation where the reader is navigating small, dense, jargon-filled content.

Much like practicing good typography, writing great CSS is all about minding the details—even a single property can contain a great deal of hidden complexity. Understanding the history, capabilities, and limitations of the technology allows for the creation of robust, beautiful solutions that everyone can use, regardless of device or ability.

If you would like to manipulate the letter-spacing of text on your website, here are some guidelines on how to do it well and avoid making mistakes.

Use letter-spacing, not spacing characters

In print, creating space between each letter in a line of metal or movable type historically involved inserting small pieces of metal between each letter. However, on the web you want to avoid adding any extra glyphs—such as spacing characters—between each typed letter. If you need to achieve the visual effect of letter-spaced type, use the letter-spacing property. This one might seem obvious, but you’d be surprised!

Maintainability

If spacing characters are used, future styling changes will be more difficult to make and maintain. Every typeface has different widths. It is harder to predict or control how potential redesigns might behave, especially when making typesetting decisions for larger sites with a lot of varied content.

See the Pen.

If you find this is an emergent behavior amongst multiple site authors, you should investigate codifying it by updating site styles to reflect this desired aesthetic. This may also necessitate talking to designers to update style guides and other relevant branding documents.

Accessibility

If letters are separated by spacing characters, some screen readers will read each letter individually instead of the whole word. In this scenario, usability is sacrificed for the sake of authoring ergonomics—browsing becomes labored and people get unnecessarily excluded from using your site.

Imagine for a moment that your eyesight isn’t as great as it is now. Your experience on the web would be a lot like this:

This issue won’t trigger automated accessibility checks, so it’s important to audit manually. Like two spaces after a period, this practice is a bad habit, so further violations can usually be found on a per-author basis.

Non-unitless values

The letter-spacing property uses a non-unitless value to determine how far apart letters are spaced. While CSS offers a range of units to choose from, there are some values to be avoided:

Pixels and other absolute units

Much like manually inserting spaces to create a letter-spacing effect, absolute units such as pixels also make it difficult to predict what might happen when you inevitably update or change any type styles or faces. Unlike relative units, these static units will only scale proportionately to themselves when zoomed. Some older browsers won’t scale them at all.

In terms of maintainability, static units are also problematic. What might work well defined in pixels for one typeface might not look great for another, as different typefaces have different widths for their glyphs. If you ever change your brand’s typeface, updating precisely measured pixel values across your entire site becomes a large chore.

Relative units

The size of a relative unit is determined by measuring it against the size of something else. For example, viewport units size things relative to the browser’s height and width—something styled with a width: 5vw; will have a width of 5% of the width of the browser (admittedly an oversimplification, this isn’t a post about the nuances of browser UI).

For letter-spacing English and other Romance languages, the em unit is what you’re going to want to use.

Historically, ems were measured by the width of a capital M—typically the widest character in the alphabet—or later, the height of all the metal type in the font’s set. In web typography, ems are potentially based off of a stack of things:

  1. The browser’s default font size (typically 16px, but not always).
  2. A user-specified default font size.
  3. The font size declared on the root of the page (typically applied to the <body> tag).
  4. The font size declared on a containing parent element.
  5. The font size declared by a style.
  6. The font size set by a special operating mode such as browser zoom or extension, OS preferences, etc.

In addition to the nerdish pride you’ll feel paying homage to the great typographers of generations past, em-based letter-spacing will always be relative to the font size you’ve declared. This gives the assurance that things will always be properly and proportionately scaled.

rems, ems younger sibling, operate in a similar way. The main difference is that they are always proportional to the root font size (but are still affected by things like special browser operating modes).

While the ease of using rems for letter-spacing might seem attractive, I hope you’ll consider Progressive Enhancement. The same older browsers you’d worry about choking on pixel scaling probably won’t have rem support. Save your future self the hassle of the inevitable bug fix and use ems in the first place.

Accessibility

Armed with the knowledge that you can gracefully and resiliently adjust letter-spacing, there’s one last thing to consider: While glyphs that are jammed too close together are obviously difficult to read, text that has been letter-spaced too far apart also has a negative impact on legibility.

When the distance between glyphs is too great, words start to look like individual letters. This can potentially affect a wide range of your audience, including people with dyslexia, people new to the language, people with low vision, etc.

See the Pen.

Like with the manually manipulated spacing issue discussed earlier, this issue potentially won’t be caught by an automated accessibility check. Unfortunately, there is no magic formula for determining how far is too far for spacing characters apart. Since different typefaces have different character widths, it is important to take a minute to review and determine if your lines of text are both readable and legible when manipulating the letter-spacing.

Use text-transform

It is common to see type set in all capital letters also use letter-spacing. This is to lessen the visual “weight” of the page as a whole, so the eye isn’t unnecessarily distracted while reading through it.

The text-transform property controls how text gets capitalized. There’s a subtlety to this, in that the transform happens on the rendered page, and not in the source HTML. So, a string of text authored as, “The quick brown fox jumped over the lazy dog.” and styled with text-transform: uppercase; will be rendered as “The quick brown fox jumped over the lazy dog.

Choosing the right amount of letter-spacing to go with text via text-transform is more an art than a science, and there are some hidden complexities and bad behaviors to be aware of:

Accessibility

If you’re picking up on a pattern here, it’s that you want to let CSS do what it was designed to do: control the look of the page without affecting the underlying semantics of the HTML markup.

If you use a series of hand-typed capital letters to create the effect, it will be treated in much the same way as using typed spaces—some older screen readers will read each letter individually. While this is fine for most acronyms, content capitalized solely for the sake of aesthetics should have this transformation performed via styles.

And again, if this manual effort is a pattern amongst your site authors, investigate codifying the behavior and swap in text-transform instructions. Not only will you be doing your users a solid, but you’re also being a good coworker by saving them a little hassle and effort.

Reading comprehension is another factor to consider. We read written language by anticipating patterns of letters that will be in words, then going back to verify. Large areas of text set in all caps makes it difficult to predict these patterns, which reduces both the speed of reading and interpretation.

User experience

Micro-interactions are frequently overlooked and undervalued when sprinting to get a project out the door, but go a long way in creating favorable and memorable experiences. One such micro-interaction is proper use of text-transform.

When copying text, certain browsers honor the content in the source, and ignores any text transforms applied to it. If we copied our “The quick brown fox” example above in Firefox or Edge and pasted it, we would see the text is not set in all uppercase.

Some may argue that styled presentation takes priority, but I view browsers that don’t support this preservation of author intent as being incorrect. If you do not have the time, resources, autonomy, or technical know-how to convert this text back to its authored case it becomes non-trivial to reformat. In situations where this content must be manually migrated into other systems, it unnecessarily introduces the potential for errors.

Feeling fancy?

Still with me? Here’s your reward! With the confidence that we’re now letter-spacing our type properly, we’re going to dig into some of the fun stuff:

Special units

No, we’re not talking about Seal Team 6. If you spent some time on the MDN page discussing the various units available to work with, you might have noticed a few interesting measurements in the subsection called Font-relative lengths:

  • ex, which represents the font’s x-height.
  • cap, which represents the height of the font’s capital letters.
  • ch, which represents the width of the font’s zero (0) glyph.

If you want to really double-down on your typography, you can use:

  • ex for letter-spaced type set to use small caps (more on this in a bit).
  • cap for letter-spaced type transformed to all uppercase.
  • ch for letter-spaced monospace fonts.

While the support for these units varies, CSS’ @supports allows us to confidently write these declarations while providing fallbacks for non-compliant browsers.

.heading-primary {
  color: #4a4a4a;
  font-family: "ff-tisa-web-pro", "Tisa Pro", "FF Tisa Pro", "Georgia", serif;
  font-size: 2em;
  letter-spacing: 0.25em; /* Fallback if the `cap` unit isn't supported  */
  line-height: 1.2;
  text-transform: uppercase;
}
@supports (letter-spacing: 0.25cap) {
  .heading-primary {
    letter-spacing: 0.25cap; /* Quarter the font's capital letter height */
  }
}

OpenType features

The history of typography is full of special treatments for specific use cases where the default presentation may not have been sufficient to convey meaning effectively. Some treatments were to help reinforce visual tone, while others were more pragmatic—aiding the ease of interpretation of the text.

See the Pen.

OpenType embraces this history and allows the savvy typographer to use these specialty treatments, provided the font supports them. For digital typography, most companies that sell professional typefaces will tell you what is available.

Adobe Typekit buries what features are available in the info icon located next to the “OpenType Features” checkbox in their Kit Editor. Thisarmy’s Google OpenType Feature Preview allows you to browse through Google Font’s library and toggle available features.

Unfortunately, a lot of other free font hosts do not. In order to determine if the typeface you’ve selected has the specific glyphs needed to support these features, you can test it in the browser. If you have a copy installed on your computer, you can also view the font’s character map (Character Map for Windows, Font Book for Mac).

These two programs allow you to view every glyph included in a typeface—hidden treasure awaits!

Most OpenType features will automatically swap in if enabled and the specific character combinations are typed out. Thanks to some clever engineers, this substitution will not affect things like searching, translating, or pasting/changing to a font that lacks support.

If your font does have support for OpenType features, here are some considerations to have in mind when letter-spacing:

Ligatures

Common and discretionary ligatures are special glyphs that combine two characters commonly found next to each other. Historically, they were used to address common kerning issues, and also to save the lead type for use elsewhere.

With regards to letter-spacing, you’ll want to make sure ligatures are disabled to prevent something like this from happening:

You might also be considering using a styled span tag to approximate a ligature and kern two characters closer together. This is a clever idea, but can be problematic when read by a screen reader:

Swashes and Alternates: Titling, contextual, stylistic, historical

These special features typically adjust the presentation of the font to adjust the tone, or to make special flourishes and commonly repeated characters more distinct. These features are less common, but most professional typefaces will contain at least one treatment.

Much like ligatures, the presentation of letter-spaced type can affect these features. It’s good to test how it will look on a wide variety of content before pushing styles live—lorem ipsum might not catch it.

Small caps

A lot of word processing programs allow you to create faux small capitals the same way they allow you to create faux bold and italic styles. The trouble with these faux styles is they are inferior counterfeits. Real bold, italic, and small cap styles are specifically designed to use the same proportions and metrics the rest of the typeface uses. Faux styles are a one-size-fits-all solution and are about as elegant-looking as a cow falling down the stairs.

While CSS does have a font-variant: small-caps; declaration, it really shouldn’t be used unless the font includes actual OpenType small cap glyphs. Much like word processor faux small caps, CSS-created faux small caps are a distorted photocopy of the real thing.

If your typeface does support small caps, chances are good that the typographer who designed it baked the ideal amount of letter-spacing into their glyphs. Because of this, you may not need to manually letter-space and can rely on their good judgment.

Case-sensitive forms

This feature renders glyphs that are designed to look good when set next to anything set in all caps. Thanks to things like hashtags (#) and at symbols (@), we’re enjoying a Renaissance of non-alphanumeric characters being placed alongside regular content. If your font supports them and you’re using letter-spaced all caps styles somewhere, I say include ’em!

CSS custom properties, preprocessors and utility classes

One of the aims of a mature website is to have a codebase that is easy to understand and maintain. CSS Custom Properties and CSS preprocessors such as Sass or PostCSS offer features like variables that allow developers to codify things like measurements that are repeated throughout the source code.

For letter-spacing, variables can be a great way to ensure that developers don’t have to guesstimate what the value is. A system containing pre-defined and easy-to-understand measurements such as $tracking-tight / $tracking-slight / $tracking-loose let people working on the site not waste time deliberating on what best matches the design. Designers would be wise to use the same naming convention the developers do for these agreed-upon measurements.

Utility classes—a CSS methodology that “applies a single rule or a very simple, universal pattern”—can also take advantage of this formalizing of measurements. By taking these pre-defined groupings of declarations in your design system and turning them into single-purpose classes, you can add a lot of flexibility and modularity to how elements on your site are described:

<section class="c-card">
  <h3 class="u-heading-secondary u-tracking-slight u-all-caps">
    Our services
  </h3>
  …
</section>

This can be especially handy if your organization has a large site with a lot of different components and varying levels of access to the site source code. Authors who only have access to a post authoring environment—including a HTML/Markdown view—will be more inclined to stay within established styles if they are made aware of them and they allow for the flexibility they need.

Conclusion

Typography is part of everyone’s reading experience, yet something that most do not think about very much. By better understanding its history, strengths, and weaknesses, we are able to craft clear and effective reading experiences for everyone.


Keeping track of letter-spacing, some guidelines originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/keeping-track-letter-spacing-guidelines/feed/ 4 260620