Tag: Take

Why Don’t Developers Take Accessibility Seriously?

You know that joke, “Two front-end developers walk into a bar and find they have nothing in common”? It’s funny, yet frustrating, because it’s true.

This article will present three different perspectives on accessibility in web design and development. Three perspectives that could help us bridge the great divide between users and designers/developers. It might help us find the common ground to building a better web and a better future.

The corner of a white and blue building in focus, with white on the left and blue on the right representing the divide between developers when it comes to accessibility practices.
Photo by Alexander Naglestad on Unsplash

Act 1

“I just don’t know how developers don’t think about accessibility.”

Someone once said that to me. Let’s stop and think about it for a minute. Maybe there’s a perspective to be had.

Think about how many things you have to know as a developer to successfully build a website. In any given day, for any given job position in web development, there are the other details of web development that come up. Meaning, it’s more than “just” knowing HTML, CSS, ARIA, and JavaScript. Developers will also learn other things over the course of their careers, based on what they need to do.

This could be package management, workspaces, code generators, collaboration tools, asset loading, asset management, CDN optimizations, bundle optimizations, unit tests, integration tests, visual regression tests, browser integration tests, code reviews, linting, formatting, communication through examples, changelogs, documentation, semantic versioning, security, app deployment, package releases, rollbacks, incremental improvements, incremental testing, continuous deployments, merge management, user experience, user interaction design, typography scales, aspect ratios for responsive design, data management, and… well, the list could go on, but you get the idea.

As a developer, I consider myself to be pretty gosh darn smart for knowing how to do most these things! Stop and consider this: if you think about how many people are in the world, and compare that to how many people in the world can build websites, it’s proportionally a very small percentage. That’s kind of… cool. Incredible, even. On top of that, think about the last time you shipped code and how good that felt. “I figured out a hard thing and made it work! Ahhhhh! I feel amazing!”

That kind of emotional high is pretty great, isn’t it? It makes me smile just to think about it.

Now, imagine that an accessibility subject-matter expert comes along and essentially tells you that not only are you not particularly smart, but you have been doing things wrong for a long time.

Ouch. Suddenly you don’t feel very good. Wrong? Me?? What??? Your adrenaline can even kick in and you start to feel defensive. Time to stick up for yourself… right? Time to dig those heels.

The cognitive dissonance can even be really overwhelming. It feels bad to find out that not only are you not good at the thing you thought you were really good at doing, but you’ve also been saying, “Screw you, who cares about you anyway,” to a whole bunch of people who can’t use the websites you’ve helped build because you (accidentally or otherwise) ignored that they even existed, that you ignored users who needed something more than the cleverness you were delivering for all these years. Ow.

All things considered, it is quite understandable to me that a developer would want to put their fingers in their ears and pretend that none of this has happened at all, that they are still very clever and awesome. That the one “expert” telling you that you did it wrong is just one person. And one person is easy to ignore.

end scene.

Act 2

“I feel like I don’t matter at all.”

This is a common refrain I hear from people who need assistive technology to use websites, but often find them unusable for any number of reasons. Maybe they can’t read the text because the website’s design has ignored color contrast. Maybe there are nested interactive elements, so they can’t even log in to do things like pay a utility bill or buy essential items on their own. Maybe their favorite singer has finally set up an online shop but the user with assistive technology cannot even navigate the site because, while it might look interactive from a sighted-user’s perspective, all the buttons are divs and are not interactive with a keyboard… at all.

This frustration can boil over and spill out; the brunt of this frustration is often borne by the folks who are trying to deliver more inclusive products. The result is a negative feedback cycle; some tech folks opt out of listening because “it’s rude” (and completely missing the irony of that statement). Other tech folks struggle with the emotional weight that so often accompanies working in accessibility-focused design and development.

The thing is, these users have been ignored for so long that it can feel like they are screaming into a void. Isn’t anyone listening? Doesn’t anyone care? It seems like the only way to even be acknowledged is to demand the treatment that the law affords them! Even then, they often feel ignored and forgotten. Are lawsuits the only recourse?

It increasingly seems that being loud and militant is the only way to be heard, and even then it might be a long time before anything happens.

end scene.

Act 3

“I know it doesn’t pass color contrast, but I feel like it’s just so restrictive on my creativity as a designer. I don’t like the way this looks, at all.”

I’ve heard this a lot across the span of my career. To some, inclusive design is not the necessary guardrail to ensure that our websites can be used by all, but rather a dampener on their creative freedom.

If you are a designer who thinks this way, please consider this: you’re not designing for yourself. This is not like physical art; while your visual design can be artistic, it’s still on the web. It’s still for the web. Web designers have a higher challenge—their artistic vision needs to be usable by everyone. Challenge yourself to move the conversation into a different space: you just haven’t found the right design yet. It’s a false choice to think that a design can either be beautiful or accessible; don’t fall into that trap.

end scene.

Let’s re-frame the conversation

These are just three of the perspectives we could consider when it comes to digital accessibility.

We could talk about the project manager that “just wants to ship features” and says that “we can come back to accessibility later.” We could talk about the developer who jokes that “they wouldn’t use the internet if they were blind anyway,” or the one that says they will only pay attention to accessibility “once browsers make them do it.”

We could, but we don’t really need to. We know how these these conversations go, because many of us have lived these experiences. The project never gets retrofitted. The company pays once to develop the product, then pays for an accessibility audit, then pays for the re-write after the audit shows that a retrofit is going to be more costly than building something new. We know the developer who insists they should only be forced to do something if the browser otherwise disallows it, and that they are unlikely to be convinced that the inclusive architecture of their code is not only beneficial, but necessary.

So what should we be talking about, then?

We need to acknowledge that designers and developers need to be learning about accessibility much sooner in their careers. I think of it with this analogy: Imagine you’ve learned a foreign language, but you only learned that language’s slang. Your words are technically correct, but there are a lot of native speakers of that language who will never be able to understand you. JavaScript-first web developers are often technically correct from a JavaScript perspective, but they also frequently create solutions that leave out a whole lotta people in the end.

How do we correct for this? I’m going to be resolute here, as we all must be. We need to make sure that any documentation we produce includes accessible code samples. Designs must contain accessible annotations. Our conference talks must include accessibility. The cool fun toys we make to make our lives easier? They must be accessible, and there must be no excuse for anything less This becomes our new minimum-viable product for anything related to the web.

But what about the code that already exists? What about the thousands of articles already written, talks already given, libraries already produced? How do we get past that? Even as I write this article for CSS-Tricks, I think about all of the articles I’ve read and the disappointment I’ve felt when I knew the end result was inaccessible. Or the really fun code-generating tools that don’t produce accessible code. Or the popular CSS frameworks that fail to consider tab order or color contrast. Do I want all of those people to feel bad, or be punished somehow?

Nope. Not even remotely. Nothing good comes from that kind of thinking. The good comes from the places we already know—compassion and curiosity.

We approach this with compassion and curiosity, because these are sustainable ways to improve. We will never improve if we wallow in the guilt of past actions, berating ourselves or others for ignoring accessibility for all these years. Frankly, we wouldn’t get anything done if we had to somehow pay for past ignorant actions; because yes, we did ignore it. In many ways, we still do ignore it.

Real examples: the Google Developer training teaches a lot of things, but it doesn’t teach anything more than the super basic parts of accessibility. JavaScript frameworks get so caught up in the cleverness and complexity of JavaScript that they completely forget that HTML already exists. Even then, accessibility can still take a back seat. Ember existed for about eight years before adding an accessibility-focused community group (even if they have made a lot of progress since then). React had to have a completely different router solution created. Vue hasn’t even begun to publicly address accessibility in the core framework (although there are community efforts). Accessibility engineers have been begging for inert to be implemented in browsers natively, but it often is underfunded and de-prioritized.

But we are technologists and artists, so our curiosity wins when we read interesting articles about how the accessibility object model and how our code can be translated by operating systems and fed into assistive technology. That’s pretty cool. After all, writing machine code so it can talk to another machine is probably more of what we imagined we’d be doing, right?

The thing is, we can only start to be compassionate toward other people once we are able to be compassionate toward ourselves. Sure, we messed up—but we don’t have to stay ignorant. Think about that time you debugged your code for hours and hours and it ended up being a typo or a missing semicolon. Do you still beat yourself up over that? No, you developed compassion through logical thinking. Think about the junior developer that started to be discouraged, and how you motivated them to keep trying and that we all have good days and bad. That’s compassion.

Here’s the cool part: not only do we have the technology, we are literally the ones that can fix it. We can get up and try to do better tomorrow. We can make some time to read about accessibility, and keep reading about it every day until we know it just as well as we do other things. It will be hard at first, just like the first time we tried… writing tests. Writing CSS. Working with that one API that is forever burned in our memory. But with repetition and practice, we got better. It got easier.

Logically, we know we can learn hard things; we have already learned hard things, time and time again. This is the life and the career we signed up for. This is what gets us out of bed every morning. We love challenges and we love figuring them out. We are totally here for this.

What can we do? Here are some action steps.

Perhaps I have lost some readers by this point. But, if you’ve gotten this far, maybe you’re asking, “Melanie, you’ve convinced me, but what can I do right now?” I will give you two lists to empower you to take action by giving you a place to start.

Compassionately improve yourself:

  1. Start following some folks with disabilities who are on social media with the goal of learning from their experiences. Listen to what they have to say. Don’t argue with them. Don’t tone police them. Listen to what they are trying to tell you. Maybe it won’t always come out in the way you’d prefer, but listen anyway.
  2. Retro-fit your knowledge. Try to start writing your next component with HTML first, then add functionality with JavaScript. Learn what you get for free from HTML and the browser. Take some courses that are focused on accessibility for engineers. Invest in your own improvement for the sake of improving your craft.
  3. Turn on a screen reader. Learn how it works. Figure out the settings—how do you turn on a text-only version? How do you change the voice? How do you make it stop talking, or make it talk faster? How do you browse by headings? How do you get a list of links? What are the keyboard shortcuts?

Bonus Challenge: Try your hand at building some accessibility-related tooling. Check out A11y Automation Tracker, an open source project that intends to track what automation could exist, but just hasn’t been created yet.

Incrementally improve your code

There are critical blockers that stop people from using your website. Don’t stop and feel bad about them; propel yourself into action and make your code even better than it was before.

Here are some of the worst ones:

  1. Nested interactive elements. Like putting a button inside of a link. Or another button inside of a button.
  2. Missing labels on input fields (or non-associated labels)
  3. Keyboard traps stop your users in their tracks. Learn what they are and how to avoid them.
  4. Are the images on your site important for users? Do they have the alt attribute with a meaningful value?
  5. Are there empty links on your site? Did you use a link when you should have used a button?

Suggestion: Read through the checklist on The A11y Project. It’s by no means exhaustive, but it will get you started.

And you know what? A good place to start is exactly where you are. A good time to start? Today.


Featured header photo by Scott Rodgerson on Unsplash


Why Don’t Developers Take Accessibility Seriously? originally published on CSS-Tricks. You should get the newsletter and become a supporter.

CSS-Tricks

, , , ,

What Would it Take to Prevent CSS Tooltips From Overflowing?

Say you have an elements with CSS tooltips and you’re going to position those tooltips such that it opens up next to the element on hover (or probably better: when clicked/tapped). Next to it where? Above it? What if the element is already really close to the top of the screen? In that case, it should probably open below it. Or vice versa — and the same goes for the left and right edges of the screen. You definitely want it to be visible rather than overflowing the viewport.

Sometimes when you open new UI elements, they need to be edge-aware to prevent the content inside from triggering weird scrollbars, or worse, cutting off content.

A red button and an orange button, both with CSS tooltips, sitting above two large paragraphs of text. The orange button is hovered, revealing a tooltip to the right of it but it is cut off by the edge of the viewport, making the content illegible.
Very important what?!

This is an age-old problem on the web. I remember using jQuery UI tooltips on purpose because it had this special ability to be edge-aware. You can imagine the JavaScript behind it. You figure out where the element is going to be and use positioning math to figure out if it will be within the viewport. If it won’t be, try a different position that does fit.

As ever, everything old is new again. Check out Floating UI, designed just for this problem.

FloatingUI home screen showing a logo that looks like a CSS tooltip with a happy face.

Floating UI is a low-level toolkit to position floating elements while intelligently keeping them in view. Tooltips, popovers, dropdowns, menus, and more.

It looks super well done. I like the focus, the demos are super well done, and it’s a pretty tiny dependency.

But ya know what would be even cooler? If CSS could do this all by itself. That’s the vibe with CSS Anchored Positioning — for now just an “explainer” document:

When building interactive components or applications, authors frequently want to leverage UI elements that can render in a “top-layer”. Examples of such UI elements include content pickers, teaching UI, tooltips, and menus. “Enabling Popups” introduced a new popup element to make many of these top-layer elements easier to author.

Authors frequently wish to “pin” or “anchor” such top-layer UI to a point on another element, referred to here as an “anchor element”. How the top-layer UI is positioned with respect to its anchor element is further influenced or constrained by the edges of the layout viewport.

A four-by-four grid showing the same blue button positioned at different corners of each cell, and a tooltip that avoids the edge of the screen where the button sits.

I love it. The web platform at its best. Seeing what authors are needing to do and reaching for libraries to do, and trying to step in and do it natively (and hopefully better).


What Would it Take to Prevent CSS Tooltips From Overflowing? originally published on CSS-Tricks. You should get the newsletter and become a supporter.

CSS-Tricks

, , , , ,
[Top]

How to Monitor Core Web Vitals and Take Action with Raygun

Raygun is an error and performance monitoring software for websites and mobile apps. In the case of websites, you install their JavaScript snippet onto your site, which takes 2 seconds, and now you’ve got monitoring in place. Why? Well now you can watch the performance of your site, not just in a single report of one test, but historical dashboards, tracking that performance over time.

This is Real User Monitoring (RUM)

RUM is regarded as better data than the alternative, which is running synthetic tests. Imagine running a performance test against a headless browser. Useful, but fake. Better is to measure how real people are experiencing your site, which is exactly how Raygun does it.

When you log into Raygun, you’ll see high-level trends as to how your site is performing, with the ability to dig deeper into specific pages and individual user sessions.

Now with Core Web Vitals

Google’s latest user experience metrics, Largest Contentful Paint, First Input Delay, and Cumulative Layout Shift are now directly in Raygun:

What I found particularly cool about this is that you don’t have to necessarily pick which pages you want to track CWV on, they’ll be tracked on all pages you have Raygun installed on. I imagine for most sites, that’s all pages, so now you’ll have CWV (and all other performance information) on every page of your site. So rather than picking-and-choosing a handful of pages to test, and risking there being outlier pages that behave slowly, you’ve got full coverage.

Filter to What You Need

You’re going to have a lot of data with Raygun, and that’s a very good thing. But that doesn’t mean it has to be overwhelming or you can’t find exactly what you need. Say you’ve heard from a user that the site is behaving slowly for them in Firefox, you can filter for Firefox and look into that.

Take Action

What makes Raygun really useful is having all of the information you need to take action, with access to waterfall timelines, session information, and instance level diagnostics. This means you don’t just monitor what your CWV scores are, you can actively improve them.

Crash Reporting

We’ve mostly talked about performance reporting here, but note that Raygun is an error reporting tool as well. That is significant, as it means you don’t need to reach for a separate service for that vital need. You get your performance and crash reporting information in the same place.


Find issues. Fix issues. Watch your site improve. After your free trial, pricing starts at just $ 8/month for plans that have Real User Monitoring with CWV.


The post How to Monitor Core Web Vitals and Take Action with Raygun appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

CSS-Tricks

, , , , ,
[Top]

Jetpack 8.9: Take Donations, Capture Email Subscribers, AMP integration, and More

(This is a sponsored post.)

Jetpack 8.9 shipped on September 1 and it shows why the plugin continues to be the premier way to take a WordPress site from good to holy smokes! Several new features are packed into the release, but a few really stand out.

Take donations with a new block

The first is donations, and a quick demo of how easy it is to drop a donation form into a page is going to excite anyone who has ever had to cobble together multiple third party scripts and tools to get something like this on a site.

That’s right — it’s as easy as any other block and it connects directly to your Stripe account when you upgrade to a Jetpack paid plan. Non-profits are sure to love this, but even if you’re a plugin developer looking for a way to collect “tips” in exchange for your work, you’ll get a lot of mileage out of something like this.

I’d drop a donations block right here to show you, but if you’re so inclined (😍) we have a MVP supporter thing set up that handles that, which is powered by WooCommerce Memberships.

Collect newsletter signups and automate email marketing

Another feature that stands out is a newsletter signup form. Instead of relying on another plugin for form functionality and another to connect the form to an email newsletter service, Jetpack handles it all with a new block that not only collects subscribers, but integrates directly with Creative Mail by Constant Contact.

That means you not only take signups directly from your site, but you get a way to pull WordPress content and WooCommerce products into emails that support all kinds of automatons, like scheduled sends, action-based triggers, and multi-step marketing journeys. It’s a lot of power in a single package!

It’s worth noting that the newsletter form is in addition to a growing number of forms that are built right into Jetpack, including RSVP, contact, registration, feedback, and appointments.

AMP-ify your content

There isn’t a whole lot of details on this feature, but it certainly warrants attention. Automattic and Google have been working closely together the past several months to ship the 2.0 version of the official AMP plugin for WordPress.

The plan is for the Jetpack team to write up a detailed post sometime soon that thoroughly outlines the integration. Just a guess? Perhaps Jetpack blocks will natively support valid AMP markup in way that maintains the functionality while meeting AMP’s performance standards. We’ll see!


Jetpack 8.9 is the latest release in what’s proving to be a rapidly evolving one-stop shop for the most common and useful WordPress features that normally would require plugin overload. The past year alone has seen a slideshow block, on-site instant search, built-in customer relationship management and security monitoring — and those are just the highlights! You really can’t go wrong with Jetpack if you’re looking for the most powerful set of features in one place. Plug it in, purchase a plan, and you get access to literally dozens of features and enhancements for WordPress without having to hunt them down, one-by-one. Hey, that’s why we use Jetpack around here at CSS-Tricks… and love it!

Direct Link to ArticlePermalink


The post Jetpack 8.9: Take Donations, Capture Email Subscribers, AMP integration, and More appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

CSS-Tricks

, , , , , , ,
[Top]

Let’s Take a Deep Dive Into the CSS Contain Property

Compared to the past, modern browsers have become really efficient at rendering the tangled web of HTML, CSS, and JavaScript code a typical webpage provides. It takes a mere milliseconds to render the code we give it into something people can use.

What could we, as front-end developers, do to actually help the browser be even faster at rendering? There are the usual best practices that are so easy to forget with our modern tooling — especially in cases where we may not have as much control over generated code. We could keep our CSS under control, for instance, with fewer and simpler selectors. We could keep our HTML under control; keep the tree flatter with fewer nodes, and especially fewer children. We could keep our JavaScript under control; while being careful with our HTML and CSS manipulations.

Actually, modern frameworks such as Vue and React do help out a good bit with that last part.

I would like to explore a CSS property that we could use to help the browser figure out what calculations it can reduce in priority or maybe even skip altogether.

This property is called contain. Here is how MDN defines this property:

The contain CSS property allows an author to indicate that an element and its contents are, as much as possible, independent of the rest of the document tree. This allows the browser to recalculate layout, style, paint, size, or any combination of them for a limited area of the DOM and not the entire page, leading to obvious performance benefits.

A simple way to look at what this property provides is that we can give hints to the browser about the relationships of the various elements on the page. Not necessarily smaller elements, such as paragraphs or links, but larger groups such as sections or articles. Essentially, we’re talking about container elements that hold content — even content that can be dynamic in nature. Think of a typical SPA where dynamic content is being inserted and removed throughout the page, often independent of other content on the page.

A browser cannot predict the future of layout changes to the webpage that can happen from JavaScript inserting and removing content on the page. Even simple things as inserting a class name to an element, animating a DOM element, or just getting the dimensions of an element can cause a reflow and repaint of the page. Such things can be expensive and should be avoided, or at least be reduced as much as possible.

Developers can sort of predict the future because they’ll know about possible future changes based on the UX of the page design, such as when the user clicks on a button it will call for data to be inserted in a div located somewhere in the current view. We know that’s a possibility, but the browser does not. We also know that there’s a distinct possibility that inserting data in that div will not change anything visually, or otherwise, for other elements on the page.

Browser developers have spent a good amount of time optimizing the browser to handle such situations. There are various ways of helping the browser be more efficient in such situations, but more direct hints would be helpful. The contain property gives us a way to provide these hints.

The various ways to contain

The contain property has three values that can be used individually or in combination with one another: size, layout, and paint. It also has two shorthand values for common combinations: strict and content. Let’s cover the basics of each.

Please keep in mind that there are a number of rules and edge cases for each of these that are covered in the spec. I would imagine these will not be of much concern in most situations. Yet, if you get an undesired result, then a quick look at the spec might be handy.

There is also a style containment type in the spec that this article will not cover. The reason being that the style containment type is considered of little value at this time and is currently at-risk of being removed from the spec.

Size containment

size containment is actually a simple one to explain. When a container with this containment is involved in the layout calculations, the browser can skip quite a bit because it ignores the children of that container. It is expected the container will have a set height and width; otherwise, it collapses, and that is the only thing considered in layout of the page. It is treated as if it has no content whatsoever.

Consider that descendants can affect their container in terms of size, depending on the styles of the container. This has to be considered when calculating layout; with size containment, it most likely will not be considered. Once the container’s size has been resolved in relation to the page, then the layout of its descendants will be calculated.

size containment doesn’t really provide much in the way of optimizations. It is usually combined with one of the other values.

Although, one benefit it could provide is helping with JavaScript that alters the descendants of the container based on the size of the container, such as a container query type situation. In some circumstances, altering descendants based on the container’s size can cause the container to change size after the change was done to the descendants. Since a change in the container’s size can trigger another change in the descendants you could end up with a loop of changes. size containment can help prevent that loop.

Here’s a totally contrived example of this resizing loop concept:

In this example, clicking the start button will cause the red box to start growing, based on the size of the purple parent box, plus five pixels. As the purple box adjusts in size, a resize observer tells the red square to again resize based on the size of the parent. This causes the parent to resize again and so on. The code stops this process once the parent gets above 300 pixels to prevent the infinite loop.

The reset button, of course, puts everything back into place.

Clicking the checkbox “set size containment” sets different dimensions and the size containment on the purple box. Now when you click on the start button, the red box will resize itself based on the width of the purple box. True, it overflows the parent, but the point is that it only resizes the one time and stops; there’s no longer a loop.

If you click on the resize container button, the purple box will grow wider. After the delay, the red box will resize itself accordingly. Clicking the button again returns the purple box back to its original size and then the red box will resize again.

While it is possible to accomplish this behavior without use of the containment, you will miss out on the benefits. If this is a situation that can happen often in the page the containment helps out with page layout calculations. When the descendants change internal to the containment, the rest of the page behaves as if the changes never happened.

Layout containment

layout containment tells the browser that external elements neither affect the internal layout of the container element, nor does the internal layout of the container element affect external elements. So when the browser does layout calculations, it can assume that the various elements that have the layout containment won’t affect other elements. This can lower the amount of calculations that need to be done.

Another benefit is that related calculations could be delayed or lowered in priority if the container is off-screen or obscured. An example the spec provides is:

[…] for example, if the containing box is near the end of a block container, and you’re viewing the beginning of the block container

The container with layout containment becomes a containing box for absolute or fixed position descendants. This would be the same as applying a relative position to the container. So, keep that in mind how the container’s descendants may be affected when applying this type of containment.

On a similar note, the container gets a new stacking context, so z-index can be used the same as if a relative, absolute, or fixed position was applied. Although, setting the top, right, bottom, or left properties has no effect on the container.

Here’s a simple example of this:

Click the box and layout containment is toggled. When layout containment is applied, the two purple lines, which are absolute positioned, will shift to inside the purple box. This is because the purple box becomes a containing block with the containment. Another thing to note is that the container is now stacked on top of the green lines. This is because the container now has a new stacking context and follows those rules accordingly.

Paint containment

paint containment tells the browser none of the children of the container will ever be painted outside the boundaries of the container’s box dimensions. This is similar to placing overflow: hidden; on the container, but with a few differences.

For one, the container gets the same treatment as it does under layout containment: it becomes a containing block with its own stacking context. So, having positioned children inside paint containment will respect the container in terms of placement. If we were to duplicate the layout containment demo above but use paint containment instead, the outcome would be much the same. The difference being that the purple lines would not overflow the container when containment is applied, but would be clipped at the container’s border-box.

Another interesting benefit of paint containment is that the browser can skip that element’s descendants in paint calculations if it can detect that the container itself is not visible within the viewport. If the container is not in the viewport or obscured in some way, then it’s a guarantee that its descendants are not visible as well. As an example, think of a nav menu that normally sits off-screen to the left of the page and it slides in when a button is clicked. When that menu is in its normal state off-screen, the browser just skips trying to paint its contents.

Containments working together

These three containments provide different ways of influencing parts of rendering calculations performed by the browser. size containment tells the browser that this container should not cause positional shifting on the page when its contents change. layout containment tells the browser that this container’s descendants should not cause layout changes in elements outside of its container and vice-versa. paint containment tells the browser that this container’s content will never be painted outside of the container’s dimensions and, if the container is obscured, then don’t bother painting the contents at all.

Since each of these provide different optimizations, it would make sense to combine some of them. The spec actually allows for that. For example, we could use layout and paint together as values of the contain property like this:

.el {   contain: layout paint; }

Since this is such an obvious thing to do, the spec actually provides two shorthand values:

Shorthand Longhand
content layout paint
strict layout paint size

The content value will be the most common to use in a web project with a number of dynamic elements, such as large multiple containers that have content changing over time or from user activity.

The strict value would be useful for containers that have a defined size that will never change, even if the content changes. Once in place, it’ll stay the intended size. A simple example of that is a div that contains third-party external advertising content, at industry-defined dimensions, that has no relation to anything else on the page DOM-wise.

Performance benefits

This part of the article is tough to explain. The problem is that there isn’t much in the way of visuals about the performance benefits. Most of the benefits are behind-the-scenes optimizations that help the browser decide what to do on a layout or paint change.

As an attempt to show the contain property’s performance benefits, I made a simple example that changes the font-size on an element with several children. This sort of change would normally trigger a re-layout, which would also lead to a repaint of the page. The example covers the contain values of none, content, and strict.

The radio buttons change the value of the contain property being applied to the purple box in the center. The “change font-size” button will toggle the font-size of the contents of the purple box by switching classes. Unfortunately, this class change is also a potential trigger for re-layout. If you’re curious, here is a list of situations in JavaScript and then a similar list for CSS that trigger such layout and paint calculations. I bet there’s more than you think.

My totally unscientific process was to select the contain type, start a performance recording in Chome’s developer tools, click the button, wait for the font-size change, then stop the recording after another second or so. I did this three times for each containment type to be able to compare multiple recordings. The numbers for this type of comparison are in the low milliseconds each, but there’s enough of a difference to get a feel for the benefits. The numbers could potentially be quite different in a more real-world situation.

But there are a few things to note other than just the raw numbers.

When looking through the recording, I would find the relevant area in the timeline and focus there to select the task that covers the change. Then I would look at the event log of the task to see the details. The logged events were: recalculate style, layout, update layer tree, paint, and composite layers. Adding the times of all those gives us the total time of the task.

DevTools showing set time at 27.9 milliseconds which is the same as the total time to recalculate styles.
The event log with no containment.

One thing to note for the two containment types is that the paint event was logged twice. I’ll get back to that in a moment.

DevTools showing set time at 13.8 milliseconds which is the same as the total time to recalculate styles.

Completing the task at hand

Here are the total times for the three containment types, three runs each:

Containment Run 1 Run 2 Run 3 Average
none 24 ms 33.8 ms 23.3 ms 27.03 ms
content 13.2 ms 9 ms 9.2 ms 10.47 ms
strict 5.6 ms 18.9 ms 8.5 ms 11 ms

The majority of the time was spent in layout. There were spikes here and there throughout the numbers, but remember that these are unscientific anecdotal results. In fact, the second run of strict containment had a much higher result than the other two runs; I just kept it in because such things do happen in the real world. Perhaps the music I was listening to at the time changed songs during that run, who knows. But you can see that the other two runs were much quicker.

So, by these numbers you can start to see that the contain property helps the browser render more efficiently. Now imagine my one small change being multiplied over the many changes made to the DOM and styling of a typical dynamic web page.

Where things get more interesting is in the details of the paint event.

Layout once, paint twice

Stick with me here. I promise it will make sense.

I’m going to use the demo above as the basis for the following descriptions. If you wish to follow along then go to the full version of the demo and open the DevTools. Note that you have to open up the details of the “frame” and not the “main” timeline once you run the performance tool to see what I’m about to describe.

Showing frame details open and main details closed in DevTools.
Showing frame details open and main details closed in DevTools

I’m actually taking screenshots from the “fullpage” version since DevTools works better with that version. That said, the regular “full” version should give roughly the same idea.

The paint event only fired once in the event log for the task that had no containment at all. Typically, the event didn’t take too long, ranging from 0.2 ms to 3.6 ms. The deeper details is where it gets interesting. In those details, it notes that the area of paint was the entire page. In the event log, if you hover on the paint event, DevTools will even highlight the area of the page that was painted. The dimensions in this case will be whatever the size of your browser viewport happens to be. It will also note the layer root of the paint.

Showing DevTools paint calculation of 0.7 milliseconds.
Paint event details

Note that the page area to the left in the image is highlighted, even outside of the purple box. Over to the right, are the dimensions of the paint to the screen. That’s roughly the size of the viewport in this instance. For a future comparison, note the #document as the layer root.

Keep in mind that browsers have the concept of layers for certain elements to help with painting. Layers are usually for elements that may overlap each other due to a new stacking context. An example of this is the way applying position: relative; and z-index: 1; to an element will cause the browser to create that element as a new layer. The contain property has the same effect.

There is a section in DevTools called “rendering” and it provides various tools to see how the browser renders the page. When selecting the checkbox named “Layer borders” we can see different things based on the containment. When the containment is none then you should see no layers beyond the typical static web page layers. Select content or strict and you can see the purple box get converted to its own layer and the rest of the layers for the page shift accordingly.

Layers with no containment
Layers with containment

It may be hard to notice in the image, but after selecting content containment the purple box becomes its own layer and the page has a shift in layers behind the box. Also notice that in the top image the layer line goes across on top of the box, while in the second image the layer line is below the box.

I mentioned before that both content and strict causes the paint to fire twice. This is because two painting processes are done for two different reasons. In my demo the first event is for the purple box and the second is for the contents of the purple box.

Typically the first event will paint the purple box and report the dimensions of that box as part of the event. The box is now its own layer and enjoys the benefits that applies.

The second event is for the contents of the box since they are scrolling elements. As the spec explains; since the stacking context is guaranteed, scrolling elements can be painted into a single GPU layer. The dimensions reported in the second event is taller, the height of the scrolling elements. Possibly even narrower to make room for the scrollbar.

First paint event with content containment
Second paint event with content containment

Note the difference in dimensions on the right of both of those images. Also, the layer root for both of those events is main.change instead of the #document seen above. The purple box is a main element, so only that element was painted as opposed as to whole document. You can see the box being highlighted as opposed to the whole page.

The benefits of this is that normally when scrolling elements come into view, they have to be painted. Scrolling elements in containment have already been painted and don’t require it again when coming into view. So we get some scrolling optimizations as well.

Again, this can be seen in the demo.

Back to that Rendering tab. This time, check “Scrolling performance issue” instead. When the containment is set to none, Chrome covers the purple box with an overlay that’s labeled “repaints on scroll.”

DevTools showing “repaints on scroll” with no containment

If you wish to see this happen live, check the “Paint flashing” option.

Please note: if flashing colors on the screen may present an issue for you in some way, please consider not checking the “Paint flashing” option. In the example I just described, not much changes on the page, but if one were to leave that checked and visited other sites, then reactions may be different.

With paint flashing enabled, you should see a paint indicator covering all the text within the purple box whenever you scroll inside it. Now change the containment to content or strict and then scroll again. After the first initial paint flash it should never reappear, but the scrollbar does show indications of painting while scrolling.

Paint flashing enabled and scrolling with no containment
Paint flashing and scrolling with content containment

Also notice that the “repaints on scroll” overlay is gone on both forms of containment. In this case, containment has given us not only some performance boost in painting but in scrolling as well.

An interesting accidental discovery

As I was experimenting with the demo above and finding out how the paint and scrolling performance aspects worked, I came across an interesting issue. In one test, I had a simple box in the center of page, but with minimal styling. It was essentially an element that scrolls with lots of text content. I was applying content containment to the container element, but I wasn’t seeing the scrolling performance benefits described above.

The container was flagged with the “repaints on scroll” overlay and the paint flashing was the same as no containment applied, even though I knew for a fact that content containment was being applied to the container. So I started comparing my simple test against the more styled version I discussed above.

I eventually saw that if the background-color of the container is transparent, then the containment scroll performance benefits do not happen.

I ran a similar performance test where I would change the font-size of the contents to trigger the re-layout and repaint. Both tests had roughly the same results, with only difference that the first test had a transparent background-color and the second test had a proper background-color. By the numbers, it looks like the behind-the-scenes calculations are still more performant; only the paint events are different. It appears the element doesn’t become its own layer in the paint calculations with a transparent background-color.

The first test run only had one paint event in the event log. The second test run had the two paint events as I would expect. Without that background color, it seems the browser decides to skip the layer aspect of the containment. I even found that faking transparency by using the same color as the color behind the element works as well. My guess is if the container’s background is transparent then it must rely on whatever is underneath, making it impossible to separate the container to its own paint layer.

I made another version of the test demo that changes the background-color of the container element from transparent to the same color used for the background color of the body. Here are two screenshots showing the differences when using the various options in the Rendering panel in DevTools.

Rendering panel with transparent background-color

You can see the checkboxes that have been selected and the result to the container. Even with a content containment applied, the box has “repaints on scroll” as well as the green overlay showing painting while scrolling.

Rendering panel with background-color applied

In the second image, you can see that the same checkboxes are selected and a different result to the container. The “repaints on scroll” overlay is gone and the green overlay for painting is also gone. You can see the paint overlay on the scrollbar to show it was active.

Conclusion: make sure to apply some form of background color to your container when applying containment to get all the benefits.

Here’s what I used for the test:

This is the bottom of the page

This article has covered the basics of the CSS contain property with its values, benefits, and potential performance gains. There are some excellent benefits to applying this property to certain elements in HTML; which elements need this applied is up to you. At least, that’s what I gather since I’m unaware of any specific guidance. The general idea is apply it to elements that are containers of other elements, especially those with some form of dynamic aspect to them.

Some possible scenarios: grid areas of a CSS grid, elements containing third-party content, and containers that have dynamic content based on user interaction. There shouldn’t be any harm in using the property in these cases, assuming you aren’t trying to contain an element that does, in fact, rely in some way on another element outside that containment.

Browser support is very strong. Safari is the only holdout at this point. You can still use the property regardless because the browser simply skips over that code without error if it doesn’t understand the property or its value.

So, feel free to start containing your stuff!

The post Let’s Take a Deep Dive Into the CSS Contain Property appeared first on CSS-Tricks.

CSS-Tricks

, , , , , ,
[Top]

Reduced Motion Picture Technique, Take Two

Did you see that neat technique for using the <picture> element with <source media=""> to serve an animated image (or not) based on a prefers-reduced-motion media query?

After we shared that in our newsletter, we got an interesting reply from Michael Gale:

What about folks who love their animated GIFs, but just didn’t want the UI to be zooming all over the place? Are they now forced to make a choice between content and UI?

I thought that was a pretty interesting question.

Also, whenever I see <img src="gif.gif"> these days, my brain is triggered into WELL WHAT ABOUT MP4?! territory, as I’ve been properly convinced that videos are better-in-all-ways on the web than GIFs. Turns out, some browsers support videos right within the <img> element and, believe it or not, you can write fallbacks for that, with — drumroll, please — for the <picture> element as well!

Let’s take a crack at combining all this stuff.

Adding an MP4 source

The easy one is adding an additional <source> with the video. That means we’ll need three source media files:

  1. A fallback non-animated graphic when prefers-reduced-motion is reduce.
  2. An animated GIF as the default.
  3. An MP4 video to replace the GIF, if the fallback is supported.

For example:

<picture>   <source srcset="static.png" media="(prefers-reduced-motion: reduce)"></source>   <source srcset="animated.mp4" type="video/mp4">   <img srcset="animated.gif" alt="animated image" /> </picture>

Under default conditions in Chrome, only the GIF is downloaded and shown:

Chrome DevTools showing only gif downloaded

Under default conditions in Safari, only the MP4 is downloaded and shown:

Safari DevTools showing only mp4 downloaded

If you’ve activated prefers-reduced-motion: reduce in either Chrome or Safari (on my Mac, I go to System PreferencesAccessibilityDisplayReduce Motion), both browsers only download the static PNG file.

Chrome DevTools showing png downloaded

I tested Firefox and it doesn’t seem to work, instead continuing to download the GIF version. Firefox seems to support prefers-reduced-motion, but perhaps it’s just not supported on <source> elements yet? I’m not sure what’s up there.

Wouldn’t it be kinda cool to provide a single animated source and have a tool generate the others from it? I bet you could wire that up with something like Cloudinary.

Adding a toggle to show the animated version

Like Michael Gale mentioned, it seems a pity that you’re entirely locked out from seeing the animated version just because you’ve flipped on a reduced motion toggle.

It should be easy enough to have a <button> that would use JavaScript to yank out the media query and force the browser to show the animated version.

I’m fairly sure there is no practical way to do this declaratively in HTML. We also can’t put this button within the <picture> tag. Even though <picture> isn’t a replaced element, the browser still gets confused and doesn’t like it. Instead, it doesn’t render it at all. No big deal, we can use a wrapper.

<div class="picture-wrap">      <picture>      <!-- sources  -->   </picture>    <button class="animate-button">Animate</button>  </div>

We can position the button on top of the image somewhere. This is just an arbitrary choice — you could put it wherever you want, or even have the entire image be tappable as long as you think you could explain that to users. Remember to only show the button when the same media query matches:

.picture-wrap .animate-button {   display: none; }  @media (prefers-reduced-motion: reduce) {   .picture-wrap .animate-button {      display: block;   } }

When the button is clicked (or tapped), we need to remove the media query to start the animation by downloading an animated source.

let button = document.querySelector(".animate-button");  button.addEventListener("click", () => {   const parent = button.closest(".picture-wrap");   const picture = parent.querySelector("picture");   picture.querySelector("source[media]").remove(); });

Here’s that in action:

See the Pen
Prefers Reduction Motion Technique PLUS!
by Chris Coyier (@chriscoyier)
on CodePen.

Maybe this is a good component?

We could automatically include the button, the button styling, and the button functionality with a web component. Hey, why not?

See the Pen
Prefers Reduction Motion Technique as Web Component
by Chris Coyier (@chriscoyier)
on CodePen.

The post Reduced Motion Picture Technique, Take Two appeared first on CSS-Tricks.

CSS-Tricks

, , , ,
[Top]

Using a Mixin to Take the Math out of Responsive Font Sizes

Responsive Font Size (RFS) is an engine that automatically calculates and updates the font-size property on elements based on the dimensions of the browser viewport.

If you’re thinking that sounds familiar, that’s because there is a slew of tools out there that offer various approaches for fluid typography. In fact, Chris compiled a bunch of those a little while back. Check that out because it’s always good to know what’s out there and what fits best for a particular task.

RFS is different in that it makes writing code for fluid type feel a lot like writing native CSS (or, more accurately, like writing with a preprocessor) directly in the stylesheets you’re already working in — only without having to wrangle and manage a bunch of media queries. It’s even compatible with Sass, Less, Stylus and PostCSS, so it plugs into just about any stack.

Just how integrated is it? Well, let’s compare a snippet for fluid typography that uses the calc() function…

html {   font-size: 16px; }  @media screen and (min-width: 320px) {   html {     font-size: calc(16px + 6 * ((100vw - 320px) / 680));   } }  @media screen and (min-width: 1200px) {   html {     font-size: 22px;   } }

…with a similar example of how it can be done with RFS in Sass:

.title {   @include font-size(4rem); }

Which compiles to:

.title {   font-size: 4rem; }  @media (max-width: 1200px) {   .title {     font-size: calc(1.525rem + 3.3vw);   } }

Curious how that works? Let’s check it out and then go into how to set it up for a project.

The magic behind automatic re-scaling

Here’s a graph to get a better understanding of how RFS re-scales font sizes:

Every color represents a font size that gets passed to the font-size() mixin provided by RFS. The y-axis of the graph represents the font size (in px) and the x-axis represents the width of the viewport (again, in px).

Let’s focus on the green line, which is generated by applying a mixin to an element:

.title {   @include font-size(40); }

In this case, a font size of 40px is passed into the mixin. That value serves as the maximum font size of the element and reaches that size when the viewport is 1200px or wider, at which point it stays at that size.

Conversely, the font size will bottom out at 20px, never going below that mark.

Everything else? Well, that’s where the font size value is automatically calculated, using a function behind the scenes to determine the number according to the current width of the viewport.

RFS is also a little opinionated in that it limits itself to font sizes that are 20px and above. The reasoning is that smaller text (e.g. normal body text) normally does not need to flex as much and is a lot easier to manage than larger pieces of content, like titles and such. That’s very much in line with FitText, which also prefers being used on large text (even though it will not stop you from doing it).

If you’re the type of person who likes to look under the hood, the mixin for each preprocessor is available to view in the RFS GitHub repo. For example, here’s a direct link to the SCSS version. It’s a lot of math!

Note that every font size is generated in a combination of rem and vw units, but they are mapped to px in the graph to make it easier to understand. In other words, it really takes all the mathwork out of the mix.

Everything is configurable

Seriously. Every. Single. Thing.

For example, you may have wondered why the font size capped out at viewports 1200px and wider in the previous example. That can be changed, as well as a ton of other things, including:

  • Base font size: The lowest font size value.
  • Font size unit: The type of unit to use in the output value (px or em).
  • Breakpoint: The maximum width of the viewport where the font size of the element reaches its maximum value.
  • Breakpoint unit: The unit used for the media query that the mixin generates (px, em or rem).
  • Factor: This serves as a sorta volume control that informs the mixin how aggressive it should be in calculating font sizes from the maximum viewport width all the way down.
  • Rem value: This defines the value of 1rem in pixel (px) units.
  • Two dimensional: A feature that sniffs out the smallest side of a viewport and uses it to calculate the font size value. This comes in handy when, say, you’d like to keep the font from getting smaller when a device is rotated from a portrait orientation to landscape.
  • Class: Provides class names that can be added to an element in the HTML to either enable or disable fluid sizing.

So, yeah. A lot of options and flexibility here. The important thing to know is that all of these options are variables that can be defined in your stylesheets.

All this said, the default settings are pretty safe to use, and they will prevent a lot of longer words truncating from the viewport. This is especially true for some languages — like German or Dutch — that contain a lot of compound words.

Using RFS in a project

Let’s dive straight into to the code. It would be exhaustive to look at the code for each preprocessor, so I’ll be explaining everything in the .scss syntax. But if you prefer something else, you can check out the examples in other languages in the GitHub repo in the Usage section.

First and foremost, RFS needs to be installed on the project. It’s available in npm and Yarn:

## npm npm install rfs  ## Yarn yarn add rfs  ## Bower is available, but has been deprecated bower install rfs --save

Then, gotta make sure the mixin is imported with the rest of the styles, wherever you do your imports for other partials:

@import "~rfs/scss";

Now, we can start cooking with the mixin!

.title {   color: #333;   @include font-size(64px); }  .subtitle {   color: #666;   @include font-size(48px); }  .paragraph {   @include font-size(16px); }

I passed values in px, but rem units are also supported. If a value without a unit is passed, px is used by default. The font sizes are always rendered in rem (in combination with vw) to make sure the font sizes also increase when the default font size is increased in the browser (this is a feature often used by visually impaired people).

The output is:

.title {   color: #333;   font-size: 4rem; }  @media (max-width: 1200px) {   .title {     font-size: calc(1.525rem + 3.3vw);   } }  .subtitle {   color: #666;   font-size: 3rem; }  @media (max-width: 1200px) {   .subtitle {     font-size: calc(1.425rem + 2.1vw);   } }  .paragraph {   font-size: 1rem; }

Notice that the mixin is font-size(), but RFS will also let you use it in two other ways:

.title {   @include font-size(4rem);   // or   @include responsive-font-size(64px);   // or   @include rfs(64); }

RFS is baked right into Bootstrap

Here’s a little story for you.

One day, I had this incredibly impulsive idea to put RFS into Bootstrap. I actually did not use Bootstrap at that time, but believed it was a feature Bootstrap could definitely use. I made a pull request and waited a couple months to see what would happen.

In the meantime, I was getting more and more intrigued by Bootstrap and version 4 had just been released. Slowly but surely, I got more involved in contributing to the project and a whole new world opened for me when I discovered the community behind it. It was during hacktoberfest (oh yes, I got my t-shirt) in October 2018 that I got asked to join the Bootstrap team by mdo.

I believe contributing to open source projects is such a fun and rewarding thing. Andrés Galante has a great post on the topic if you’re interested in becoming a contributor.

Since then, RFS has become a project of the Bootstrap team, and on February 11th this year, we launched Bootstrap 4.3 which includes RFS right out of the box. It’s currently disabled by default, but can easily be switched on by setting the Sass variable $ enable-responsive-font-sizes: true.

But make no mistake: RFS can still be used on its own. Just cool that it’s baked right into a widely used framework.

Oh yeah, let’s talk browser support

Support is pretty darn good! In fact, RFS will work anywhere that supports media queries and viewport units. RFS will set a font size for Legacy browsers, like Internet Explorer 8, but the fluidity won’t be there. In other words, should be safe for production!

What’s next for RFS

The next major version of Bootstrap is version 5 and we’re planning to enable RFS by default. We don’t have any plans to change the way it works for now. More than likely, the $ enable-responsive-font-sizes variable will simply be set to true and that’s it.

In the future, I hope I can make use of the min() function because it would generate less CSS and make things a lot less complex. Browsers don’t seem to support this function all too well just yet, but if you’re interested in this feature, you can follow the progress in this GitHub issue.

Anything else? No, but I can leave you with a little song and dance: Na na na na, na na na na, hey hey hey goodbye!

The post Using a Mixin to Take the Math out of Responsive Font Sizes appeared first on CSS-Tricks.

CSS-Tricks

, , , , , ,
[Top]