Web Standards

Ensuring the correct vertical position of large text

Css Tricks - Thu, 02/25/2021 - 1:30pm

Tobi Reif notes how the position of custom fonts set at very large font sizes can be super different, even in the same browser across operating systems. The solution? Well, you know how there are certain CSS properties that only work within @font-face blocks? They are called “descriptors” and font-display is a popular example. There are more that are less-supported, like ascent-override, descent-override, and line-gap-override. Chrome supports them, and lo-and-behold, they can be used to fix this issue.

I really like the idea that these can be used to override the “metrics” of local (fallback) fonts to match a custom font you will load, so that, when it does, there’s little-to-no-movement. I detest FOUT (I know it’s theoretically good for performance), but I can swallow it if the text swap doesn’t move crap around so much.

Direct Link to ArticlePermalink

The post Ensuring the correct vertical position of large text appeared first on CSS-Tricks.

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

How We Improved the Accessibility of Our Single Page App Menu

Css Tricks - Thu, 02/25/2021 - 5:43am

I recently started working on a Progressive Web App (PWA) for a client with my team. We’re using React with client-side routing via React Router, and one of the first elements that we made was the main menu. Menus are a key component of any site or app. That’s really how folks get around, so making it accessible was a super high priority for the team.

But in the process, we learned that making an accessible main menu in a PWA isn’t as obvious as it might sound. I thought I’d share some of those lessons with you and how we overcame them.

As far as requirements go, we wanted a menu that users could not only navigate using a mouse, but using a keyboard as well, the acceptance criteria being that a user should be able to tab through the top-level menu items, and the sub-menu items that would otherwise only be visible if a user with a mouse hovered over a top-level menu item. And, of course, we wanted a focus ring to follow the elements that have focus.

The first thing we had to do was update the existing CSS that was set up to reveal a sub-menu when a top-level menu item is hovered. We were previously using the visibility property, changing between visible and hidden on the parent container’s hovered state. This works fine for mouse users, but for keyboard users, focus doesn’t automatically move to an element that is set to visibility: hidden (the same applies for elements that are given display: none). So we removed the visibility property, and instead used a very large negative position value:

.menu-item { position: relative; } .sub-menu { position: absolute left: -100000px; /* Kicking off the page instead of hiding visiblity */ } .menu-item:hover .sub-menu { left: 0; }

This works perfectly fine for mouse users. But for keyboard users, the sub menu still wasn’t visible even though focus was within that sub menu! In order to make the sub-menu visible when an element within it has focus, we needed to make use of :focus and :focus-within on the parent container:

.menu-item { position: relative; } .sub-menu { position: absolute left: -100000px; } .menu-item:hover .sub-menu, .menu-item:focus .sub-menu, .menu-item:focus-within .sub-menu { left: 0; }

This updated code allows the the sub-menus to appear as each of the links within that menu gets focus. As soon as focus moves to the next sub menu, the first one hides, and the second becomes visible. Perfect! We considered this task complete, so a pull request was created and it was merged into the main branch.

But then we used the menu ourselves the next day in staging to create another page and ran into a problem. Upon selecting a menu item—regardless of whether it’s a click or a tab—the menu itself wouldn’t hide. Mouse users would have to click off to the side in some white space to clear the focus, and keyboard users were completely stuck! They couldn’t hit the esc key to clear focus, nor any other key combination. Instead, keyboard users would have to press the tab key enough times to move the focus through the menu and onto another element that didn’t cause a large drop down to obscure their view.

The reason the menu would stay visible is because the selected menu item retained focus. Client-side routing in a Single Page Application (SPA) means that only a part of the page will update; there isn’t a full page reload.

There was another issue we noticed: it was difficult for a keyboard user to use our “Jump to Content” link. Web users typically expect that pressing the tab key once will highlight a “Jump to Content” link, but our menu implementation broke that. We had to come up with a pattern to effectively replicate the “focus clearing” that browsers would otherwise give us for free on a full page reload.

The first option we tried was the easiest: Add an onClick prop to React Router’s Link component, calling document.activeElement.blur() when a link in the menu is selected:

const Menu = () => { const clearFocus = () => { document.activeElement.blur(); } return ( <ul className="menu"> <li className="menu-item"> <Link to="/" onClick={clearFocus}>Home</Link> </li> <li className="menu-item"> <Link to="/products" onClick={clearFocus}>Products</Link> <ul className="sub-menu"> <li> <Link to="/products/tops" onClick={clearFocus}>Tops</Link> </li> <li> <Link to="/products/bottoms" onClick={clearFocus}>Bottoms</Link> </li> <li> <Link to="/products/accessories" onClick={clearFocus}>Accessories</Link> </li> </ul> </li> </ul> ); }

This approach worked well for “closing” the menu after an item is clicked. However, if a keyboard user pressed the tab key after selecting one of the menu links, then the next link would become focused. As mentioned earlier, pressing the tab key after a navigation event would ideally focus on the “Jump to Content” link first.

At this point, we knew we were going to have to programmatically force focus to another element, preferably one that’s high up in the DOM. That way, when a user starts tabbing after a navigation event, they’ll arrive at or near the top of the page, similiar to a full page reload, making it much easier to access the jump link.

We initially tried to force focus on the <body> element itself, but this didn’t work as the body isn’t something the user can interact with. There wasn’t a way for it to receive focus.

The next idea was to force focus on the logo in the header, as this itself is just a link back to the home page and can receive focus. However, in this particular case, the logo was below the “Jump To Content” link in the DOM, which means that a user would have to shift + tab to get to it. No good.

We finally decided that we had to render an interact-able element, for example, an anchor element, in the DOM, at a point that’s above than the “Jump to Content” link. This new anchor element would be styled so that it’s invisible and that users are unable to focus on it using “normal” web interactions (i.e. it’s taken out of the normal tab flow). When a user selects a menu item, focus would be programmatically forced to this new anchor element, which means that pressing tab again would focus directly on the “Jump to Content” link. It also meant that the sub-menu would immediately hide itself once a menu item is selected.

const App = () => { const focusResetRef = React.useRef(); const handleResetFocus = () => { focusResetRef.current.focus(); }; return ( <Fragment> <a ref={focusResetRef} href="javascript:void(0)" tabIndex="-1" style={{ position: "fixed", top: "-10000px" }} aria-hidden >Focus Reset</a> <a href="#main" className="jump-to-content-a11y-styles">Jump To Content</a> <Menu onSelectMenuItem={handleResetFocus} /> ... </Fragment> ) }

Some notes of this new “Focus Reset” anchor element:

  • href is set to javascript:void(0) so that if a user manages to interact with the element, nothing actually happens. For example, if a user presses the return key immediately after selecting a menu item, that will trigger the interaction. In that instance, we don’t want the page to do anything, or the URL to change.
  • tabIndex is set to -1 so that a user can’t “normally” move focus to this element. It also means that the first time a user presses the tab key upon loading a page, this element won’t be focused, but the “Jump To Content” link instead.
  • style simply moves the element out of the viewport. Setting to position: fixed ensures it’s taken out of the document flow, so there isn’t any vertical space allocated to the element
  • aria-hidden tells screen readers that this element isn’t important, so don’t announce it to users

But we figured we could improve this even further! Let’s imagine we have a mega menu, and the menu doesn’t hide automatically when a mouse user clicks a link. That’s going to cause frustration. A user will have to precisely move their mouse to a section of the page that doesn’t contain the menu in order to clear the :hover state, and therefore allow the menu to close.

What we need is to “force clear” the hover state. We can do that with the help of React and a clearHover class:

// Menu.jsx const Menu = (props) => { const { onSelectMenuItem } = props; const [clearHover, setClearHover] = React.useState(false); const closeMenu= () => { onSelectMenuItem(); setClearHover(true); } React.useEffect(() => { let timeout; if (clearHover) { timeout = setTimeout(() => { setClearHover(false); }, 0); // Adjust this timeout to suit the applications' needs } return () => clearTimeout(timeout); }, [clearHover]); return ( <ul className={`menu ${clearHover ? "clearHover" : ""}`}> <li className="menu-item"> <Link to="/" onClick={closeMenu}>Home</Link> </li> <li className="menu-item"> <Link to="/products" onClick={closeMenu}>Products</Link> <ul className="sub-menu"> {/* Sub Menu Items */} </ul> </li> </ul> ); }

This updated code hides the menu immediately when a menu item is clicked. It also hides immediately when a keyboard user selects a menu item. Pressing the tab key after selecting a navigation link moves the focus to the “Jump to Content” link.

At this point, our team had updated the menu component to a point where we were super happy. Both keyboard and mouse users get a consistent experience, and that experience follows what a browser does by default for a full page reload.

Our actual implementation is slightly different than the example here so we could use the pattern on other projects. We put it into a React Context, with the Provider set to wrap the Header component, and the Focus Reset element being automatically added just before the Provider’s children. That way, the element is placed before the “Jump to Content” link in the DOM hierarchy. It also allows us to access the focus reset function with a simple hook, instead of having to prop drill it.

We have created a Code Sandbox that allows you to play with the three different solutions we covered here. You’ll definitely see the pain points of the earlier implementation, and then see how much better the end result feels!

We would love to hear feedback on this implementation! We think it’s going to work well, but it hasn’t been released to in the wild yet, so we don’t have definitive data or user feedback. We’re certainly not a11y experts, just doing our best with what we do know, and are very open and willing to learn more on the topic.

The post How We Improved the Accessibility of Our Single Page App Menu appeared first on CSS-Tricks.

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

Boost app engagement with chat, voice, and video APIs

Css Tricks - Thu, 02/25/2021 - 5:42am

Sendbird is a service for helping you add social features to your app. Wanna add in-app chat? Sendbird does that. Wanna add in-app voice or video calls? Sendbird does that.

Here’s how I always think about stuff like this. Whatever the thing you are building is, you should specialize in the core of it, and not get bogged down in building essentially another product as you’re doing it. Say you want to build an app for dentists to do bookings and customer management. Please do, by the way, my dentist could really use it. You’ve got a lot of work ahead of you, the core of which is building a thing that is perfect for actual dentists and getting the UX right. In-app chat might be an important part of that, but you aren’t specifically building chat software, you’re building dentist software. Lean on Sendbird for the chat (and everything else).

To elaborate on the dentist software example for a bit, I can tell you more about my dentist. They are so eager to text me, email me, call me, even use social media, to remind me about everything constantly. But for me to communicate with them, I have to call. It’s the only way to talk to them about anything—and it’s obnoxious. If there was a dentist in town where I knew I could fire up a quick digital chat with them to book things, I’d literally switch dentists. Even better if I could click a button in a browser to call them or do a video consult. That’s just good business.

You know what else? Your new app for dentists (seriously, you should do this) is going to have to be compliant on a million standards for any dentist to buy it. This means any software you buy will need to be too. Good thing Sendbird is all set with HIPPA/HITECH, SOC 2, GDPR, and more, not to mention being hugely security-focused.

Sendbird aren’t spring chickens either, they are already trusted by Reddit, Virgin UAE, Yahoo, Meetup, and tons more.

Chat is tricky stuff, too. It’s not just a simple as shuffling a message off to another user and displaying it. Modern chat offers things like reactions, replies, and notifications. Chat needs to be friendly to poor networks and offline situations. Harder still, moderating chat activity and social control like blocking and reporting. Not only does Sendbird help with all that, their UIKit will help you build the interface as well.

Build it with Sendbird, and it’ll scale forever.

Sendbird’s client base gave us confidence that they would be able to handle our traffic and projected growth. ”

Ben Celibicic, CTO

Modern apps have modern users that expect these sort of features.

Try Sendbird

The post Boost app engagement with chat, voice, and video APIs appeared first on CSS-Tricks.

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

Teaching Web Dev for Free is Good Business

Css Tricks - Wed, 02/24/2021 - 12:32pm

It feels like a trend (and a smart one) for tech platforms to invest in really high-quality learning material for their platform. Let’s have a gander.

Webflow University

Surely Webflow is thinking: if people invest in learning Webflow, they’ll be able to build what they need for themselves and their clients in Weblow, and they’ll stick around and be a good customer.

Jamstack Explorers

Surely Netlify is thinking: if people really grok Jamstack, they’ll build their existing and future sites using it. They’ll get comfortable using Netlify’s features to solve their problems, and they’ll stick around and be a good customer.

Salesforce Trailhead

Surely Salesforce is thinking: if we train people to learn Salesforce and build Salesforce-specific software, not only will they be a good customer, but they’ll bring more customers to us and help big companies stay good customers.

Figma Crash Course

This is not created by Figma themselves, but by Pablo Stanley, who must be thinking: I can teach people to use Figma, and along the way show them how cool and powerful Blush is, which will gain Blush good customers.

Apollo Odyssey

Surely Apollo is thinking: if y’all know GraphQL, and learned it in the context of Apollo, you probably continue using Apollo and bring it to the teams you’re on, which might make for great customers.

WP Courses 

This one is an outlier because these are paid courses, but my guess is that Automattic is thinking: there is already a ton of WordPress learning material out there, why not leverage our brand and deep expertise to make content people are willing to pay for.

Git Tutorials & Training

Surely Atlassian is thinking: if we are the place where people literally learned Git, we can sprinkle in our tooling into those lessons, and you’ll use those tools for your Git workflow, which will follow you through your entire developer career. Not to mention this is good SEO juice.

GitHub does the same thing.

Helping your customers learn your platform is certainly not a new concept. The word “webinar” exists after all. It’s a funny word, but effective. For example, AWS Marketplace sponsors CodePen emails sometimes with the idea of getting people to attend webinars about certain technologies. Wanna learn about Apache Kafka? You can do that for free coming up Thursday, February 25th. Surely AWS is thinking if people learn how this technology works, they’ll use AWS and AWS Marketplace partners to spin it up when they get to using it.

Cypress publishes their webinars. Appcues publishes their webinars. It’s not rare.

What feels a new here is the idea of packaging up learning material on a microsite with a fancy design and making it feel in-line with modern learning platforms. Like you are going to some expensive code school, except you’re getting it for free.

I’m a fan of all this. It’s good marketing for companies. It’s a good learning opportunity for everyone else. It’s also very biased. Learning materials you get directly from companies is going to tell you all about how great the technology of that company is. You should know that going in, if it’s isn’t obvious.

I’m also a fan—perhaps an even bigger fan—of paying for high-quality learning material. Our learning partner, Frontend Masters, has no particular bias to technology because you’re their customer. If they help you, they succeed and you succeed as well.

The post Teaching Web Dev for Free is Good Business appeared first on CSS-Tricks.

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

A DRY Approach to Color Themes in CSS

Css Tricks - Wed, 02/24/2021 - 6:21am

The other day, Florens Verschelde asked about defining dark mode styles for both a class and a media query, without repeat CSS custom properties declarations. I had run into this issue in the past but hadn’t come up with a proper solution.

What we want is to avoid redefining—and thus repeating—custom properties when switching between light and dark modes. That’s the goal of DRY (Don’t Repeat Yourself) programming, but the typical pattern for switching themes is usually something like this:

:root { --background: #fff; --text-color: #0f1031; /* etc. */ } @media (prefers-color-scheme: dark) { :root { --background: #0f1031; --text-color: #fff; /* etc. */ } }

See what I mean? Sure, it might not seem like a big deal in an abbreviated example like this, but imagine juggling dozens of custom properties at a time—that’s a lot of duplication!

Then I remembered Lea Verou’s trick using --var: ;, and while it didn’t hit me at first, I found a way to make it work: not with var(--light-value, var(--dark-value)) or some nested combination like that, but by using both side by side!

Certainly, someone smarter must have discovered this before me, but I haven‘t heard of leveraging (or rather abusing) CSS custom properties to achieve this. Without further ado, here’s the idea:

--color: var(--light, orchid) var(--dark, rebeccapurple);

If the --light value is set to initial, the fallback will be used (orchid), which means --dark should be set to a whitespace character (which is a valid value), making the final computed value look like this:

--color: orchid ; /* Note the additional whitespace */

Conversely, if --light is set to a whitespace and --dark to initial, we end up with a computed value of:

--color: rebeccapurple; /* Again, note the whitespace */

Now, this is great but we do need to define the --light and --dark custom properties, based on the context. The user can have a system preference in place (either light or dark), or can have toggled the website‘s theme with some UI element. Just like Florens‘s example, we’ll define these three cases, with some minor readability enhancement that Lea proposed using “on” and “off” constants to make it easier to understand at a glance:

:root { /* Thanks Lea Verou! */ --ON: initial; --OFF: ; } /* Light theme is on by default */ .theme-default, .theme-light { --light: var(--ON); --dark: var(--OFF); } /* Dark theme is off by default */ .theme-dark { --light: var(--OFF); --dark: var(--ON); } /* If user prefers dark, then that's what they'll get */ @media (prefers-color-scheme: dark) { .theme-default { --light: var(--OFF); --dark: var(--ON); } }

We can then set up all of our theme variables in a single declaration, without repetition. In this example, the theme-* classes are set to the html element, so we can use :root as a selector, as many people like to do, but you could set them on the body, if the cascading nature of the custom properties makes more sense that way:

:root { --text: var(--light, black) var(--dark, white); --bg: var(--light, orchid) var(--dark, rebeccapurple); }

And to use them, we use var() with built-in fallbacks, because we like being careful:

body { color: var(--text, navy); background-color: var(--bg, lightgray); }

Hopefully you’re already starting to see the benefit here. Instead of defining and switching armloads of custom properties, we’re dealing with two and setting all the others just once on :root. That’s a huge improvement from where we started.

Even DRYer with pre-processors

If you were to show me this following line of code out of context, I’d certainly be confused because a color is a single value, not two!

--text: var(--light, black) var(--dark, white);

That’s why I prefer to abstract things a bit. We can set up a function with our favorite pre-processor, which is Sass in my case. If we keep our code above defining our --light and --dark values in various contexts, we need to make a change only on the actual custom property declaration. Let’s create a light-dark function that returns the CSS syntax for us:

@function light-dark($light, $dark) { @return var(--light, #{ $light }) var(--dark, #{ $dark }); }

And we’d use it like this:

:root { --text: #{ light-dark(black, white) }; --bg: #{ light-dark(orchid, rebeccapurple) }; --accent: #{ light-dark(#6d386b, #b399cc) }; } CodePen Embed Fallback

You’ll notice there are interpolation delimiters #{ … } around the function call. Without these, Sass would output the code as is (like a vanilla CSS function). You can play around with various implementations of this but the syntax complexity is up to your tastes.

How’s that for a much DRYer codebase?

More than one theme? No problem!

You could potentially do this with more than two modes. The more themes you add, the more complex it becomes to manage, but the point is that it is possible! We add another theme set of ON or OFF variables, and set an extra variable in the list of values.

.theme-pride { --light: var(--OFF); --dark: var(--OFF); --pride: var(--ON); } :root { --text: var(--light, black) var(--dark, white) var(--pride, #ff8c00) ; /* Line breaks are absolutely valid */ /* Other variables to declare… */ }

Is this hacky? Yes, it absolutely is. Is this a great use case for potential, not-yet-existing CSS booleans? Well, that’s the dream.

How about you? Is this something you’ve figured out with a different approach? Share it in the comments!

The post A DRY Approach to Color Themes in CSS appeared first on CSS-Tricks.

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

SmolCSS

Css Tricks - Wed, 02/24/2021 - 5:54am

A wonderful collection of little layout-related CSS snippets from Stephanie Eckles that serves both as a quick reference and a reminder of how straightforward and powerful CSS has become.

Random things to note!

  • The resizeable containers aren’t some JavaScript library. They are just <div>s with resize: horizontal; and overflow: auto; (although there is a nice little lib for that that displays current width output).
  • Each demo can be opened on CodePen, which is the prefill API at work.
  • CSS custom properties are tastefully sprinkled throughout in a way that makes it more understandable instead of less understandable.
  • The dark mode doesn’t go super duper dark, but fairly dark blues and purples. That’s a good reminder that dark mode isn’t gray/black mode. It remembers your setting, but does have flash-of-light-mode, which is the boss-mode problem with color preferences. I think you need server-side tech to really get it perfect.
  • The whole site is open source. Go Eleventy!

Direct Link to ArticlePermalink

The post SmolCSS appeared first on CSS-Tricks.

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

Hiding Content Responsibly

Css Tricks - Tue, 02/23/2021 - 2:35pm

We’ve covered the idea of hiding things in CSS many times here, the most recent post being Marko Ilic’s “Comparing Various Ways to Hide Things in CSS” which did a nice job of comparing different techniques which you’d use in different situations. Hugo “Kitty” Giraudel has done something similar in “Hiding Content Responsibly” which looks at 10 methods—and even those, you could say, aren’t totally comprehensive.

Does this mean CSS is messy and incomprehensible? Nah. I feel like all the methods are logical, have good use cases, and result in good outcomes. Allow me to do a have a pretend conversation walking through my thought process here.

I need to hide this thing completely. For everyone.

No problem, use display: none;.

I need to hide this thing, but only hide it for screen readers, not visually. (For example, an icon that has no additional meaning for screen readers, as there is an accessible label nearby.)

No problem, that’s what the aria-hidden attribute is for.

I need to hide this thing, but only visually, not for screen readers. (For example, the contents of non-active tabs.)

No problem, use a .sr-only class. That leaves it accessible but hides it visually until you remove that class.

Oops, I actually want to hide this thing visually, but I still want it to take up physical space, not collapse. (For example, say a button has a loading spinner icon that is only needed when performing an action. The size of the button should factor in the size of that icon all the time, not just when the spinner is visible. That way, there’s no layout shifting when that icon comes and goes.)

No problem, use transform: scale(0) which will visually collapse it, but the original space will remain, and will leave it accessible to screen readers.

Oh nice, I could transition the transform, too, I suppose. But actually, that transition doesn’t fit my site well. I just want something I can fade out and fade in.

The opacity property is transitional, so transition that between 0 and 1 for fades. The good news is that visibility is also transitional. When fading out, use visibility: hidden, and when fading in, use visibility: visible to hide and unhide the thing from screen readers.

That’s not entirely comprehensive, but I find that covers 95% of hiding cases.

The post Hiding Content Responsibly appeared first on CSS-Tricks.

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

What’s the Backup Plan for Your WordPress Site?

Css Tricks - Tue, 02/23/2021 - 7:08am

Of all the reasons we love and use Jetpack for CSS-Tricks—a poster child WordPress site—is that we can sleep easy at night knowing we have real-time backups running with Jetpack Backup. That way, no matter what, everything that makes this site tick, from all the template files to every single word we’ve ever typed, is always a click away from being restored if we need it for any reason at all.

There’s really no question whether or not you should be backing up your WordPress site. You absolutely should. It’s sort of like being prepared for an earthquake: you know it could happen at any time, so you want to make sure you’ve got all the tooling in place to keep things safe, not if, but when it happens.

What’s your backup plan? For us, it’s logging into WordPress.com, locating which backup to use, and clicking a button to restore things to that point in time. That’s all the files of course, like WordPress itself, the theme, and plugins, but also the entire database and all the media files.

Another reason we love Jetpack Backup? It provides a complete activity log of all the changes that happen on the site. It’s one thing to have your site backed up and be able to restore it. It’s another to know what caused the issue in the first place.

Jetpack Backup offers two plans one for daily backups and the other for real-time backups. We’ve got real-time running around here and that’s a great option for large sites that are updated often, like e-commerce. Most sites can probably get away with daily backups instead.

That leads to another wonderful thing: Jetpack Backup is sold à la carte. That means you can just get backups if that’s all you want from Jetpack. And, hey, if you find yourself needing more from Jetpack, like all the stuff we use it for here, then that rich feature set is just a couple of clicks away.

Not sure what your WordPress backup plan is? You really ought to check out Jetpack Backup. It works extremely well for us and we can’t recommend it enough.

Get Started True Story

While working on a bit of content for @css across team members, I noticed some of what I had written had disappeared. It got saved over by accident. I forgot to turn on “Revisions” for this Custom Post Type (it was a newsletter, which we write in WordPress).

It was tempting to be like, “Oh well, I’m a dummy, I’ll just have to remember and re-write it.” But no! I have Jetpack real-time backups on this site. I was able to find the exact moment I made my changes and download a copy of the site at that moment.

I didn’t need to restore the site to that point, just what I had written. So, I loaded up the wp_posts table from the SQL dump in that backup, plucked out my writing, and put it back in place.

And of course, I enabled revisions for that Custom Post Type so it won’t happen again.

Not only is that a true story, but this is a Jetpack double-whammy, because I “unrolled” that Twitter thread right here in WordPress via a Jetpack feature.

The post What’s the Backup Plan for Your WordPress Site? appeared first on CSS-Tricks.

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

Getting Deep into Shadows

Css Tricks - Mon, 02/22/2021 - 6:00am

Let’s talk shadows in web design. Shadows add texture, perspective, and emphasize the dimensions of objects. In web design, using light and shadow can add physical realism and can be used to make rich, tactile interfaces.

Take the landing page below. It is for cycling tours in Iceland. Notice the embellished drop shadow of the cyclist and how it creates the perception that they are flying above not only the content on the page, but the page itself, as though they are “popping” over the screen. It feels dynamic and immediate, which is perfect for the theme of adventure.

Credit: Kate Hahu

Compare that with this next example. It’s a “flat” design, sans shadows. In this case, the bike itself is the focal point. The absence of depth and realism allows the bike to stand out on its own.

Credit: saravana

You can appreciate the differences between these approaches. Using shadows and depth is a design choice; they should support the theme and the message you want the content to convey.

Light and shadows

As we just saw, depth can enhance content. And what exactly makes a shadow? Light!

It’s impossible to talk about shadow without getting into light. It controls the direction of a shadow as well as how deep or shallow the shadow appears. You can’t have one without the other.

Google’s Material Design design system is a good example of employing light and shadows effectively. You’ve certainly encountered Material Design’s aesthetics because Google employs it on nearly all of its products.

The design system takes cues from the physical world and expresses interfaces in three-dimensional space using light, surfaces, and cast shadows. Their guidelines on using light and shadows covers this in great detail.

In the Material Design environment, virtual lights illuminate the UI. Key lights create sharper, directional shadows, called key shadows. Ambient light appears from all angles to create diffused, soft shadows, called ambient shadows.

Shadows are a core component of Material Design. Compare that with Apple’s Human Interface Guidelines for macOS, where translucency and blurring is more of a driving factor for evoking depth.

In this case, light is still an influential factor, as it allows elements to either blend into the desktop, or even into other panels in the UI. Again, it’s is a design choice to employ this in your interface. Either way, you can see how light influences the visual perception of depth.

Light sources and color

Now that we understand the relationship between light and shadows, we ought to dig in a little deeper to see how light affects shadows. We’ve already seen how the strength of light produces shadows at different depths. But there’s a lot to say about the way light affects the direction and color of shadows.

There are two kinds of shadows that occur when a light shines on an object, a drop shadow and a form shadow.

Drop shadows

A drop shadow is cast when an object blocks a light source. A drop shadow can vary in tone and value. Color terminology can be dense and confusing, so let’s talk about tone and value for a moment.

Tone is a hue blended with grey. Value describes the overall lightness or darkness of a color. Value is a big deal in painting as it is how the artist translates light and object relationships to color.

In the web design world, these facets of color are intrinsic to the color picker UI.

Form shadows

A form shadow, on the other hand, is the side of an object facing away from the light source. A form shadow has softer, less defined edges than a drop shadow. Form shadows illustrate the volume and depth of an object.

The appearance of a shadow depends on the direction of light, the intensity of light, and the distance between the object and the surface where the shadow is cast. The stronger the light, the darker and sharper the shadow is. The softer the light, the fainter and softer the shadow is. In some cases, we get two distinct shadows for directional light. The umbra is where light is obstructed and penumbra is where light is cast off.

If a surface is close to an object, the shadow will be sharper. If a surface is further away, the shadow will be fainter. This is not some abstract scientific stuff. This is stuff we encounter every day, whether you realize it or not.

Light may also be reflected from sides of an object or another surface. Bright surfaces reflect light, dark surfaces absorb light.

These are the most valuable facets of light to understand for web design. The physics behind light is a complex topic, I have just lightly touched on some of it here. If you’d like to see explicit examples of what shadows are cast based on different light sources, this guide to drawing shadows for comics is instructive.

Positioning light sources

Remember, shadows go hand-in-hand with light, so defining a light source — even though there technically isn’t one — is the way to create impressive shadow effects. The trick is to consistently add shadows relative to the light source. A light source positioned above an element will cast a shadow below the element. Placing a light source to the left of an element will cast a shadow to the right. Placing multiple light sources to the top, bottom, left and right of an element actually casts no shadow at all!

A light source can be projected in any direction you choose. Just make sure it’s used consistently in your design, so the shadow on one element matches other shadows on the page.

Elevation

Shadows can also convey elevation. Once again, Material Design is a good example because it demonstrates how shadows are used to create perceived separation between elements.

Credit: Nate Wilson Inner shadows

Speaking of elevation, the box-shadow property is the only property that can create inner shadows for a sunken effect. So, instead of elevating up, the element appears to be pressed in. That’s thanks to the inset keyword.

That good for something like an effect where clicking a button appears to physically press it.

CodePen Embed Fallback

It’s also possible to “fake” an inner text shadow with a little trickery that’s mostly supported across browsers:

CodePen Embed Fallback Layering shadows

We’re not limited to a single shadow per element! For example, we can provide a comma-separated list of shadows on the box-shadow property. Why would we want to do that? Smoother shadows, for one.

CodePen Embed Fallback

Interesting effects is another.

CodePen Embed Fallback

Layering shadows can even enhance typography using the text-shadow property.

CodePen Embed Fallback

Just know that layering shadows is a little different for filter: drop-shadow() It’s syntax also takes a list, but it’s space-separated instead of comma-separated.

.box { box-shadow: 0 2px 2px #555, /* commas */ 0 6px 5px #777, 0 12px 10px #999 ; } .box { filter: drop-shadow(0 2px 2px #555) /* spaces */ drop-shadow(0 6px 5px #777) drop-shadow(0 12px 10px #999); }

Another thing? Shadows stack on top of one another, in the order they are declared where the top shadow is the first one in the list.

You may have guessed that drop-shadow() works a little differently here. Shadows are added exponentially, i.e. 2^number of shadows - 1.

Here’s how that works:

  • 1 shadow = (2^1 – 1). One shadow is rendered.
  • 2 shadows = (2^2 – 1). Three shadows are rendered.
  • 3 shadows = (2^3 – 1). Seven shadows are rendered.

Or, in code:

.one-shadow { filter: drop-shadow(20px 20px 0 grey); } .three-shadows { filter: drop-shadow(20px 20px 0 grey) drop-shadow(40px 0 0 yellow); } .seven-shadows { filter: drop-shadow(20px 20px 0 grey) drop-shadow(40px 0 0 yellow); drop-shadow(80px 0 0 red); }

The <feDropShadow> element works the exact same way for SVGs.

Shadows and accessibility

Here’s something for you to chew on: shadows can help improve accessibility.

Google conducted a study with low-vision participants to better understand how shadows and outlines impact an individual’s ability to identify and interact with a component. They found that using shadows and outlines:

  • increases the ease and speed of finding a component when scanning pages, and
  • improves one’s ability to determine whether or not a component is interactive.

That wasn’t a wide-ranging scientific study or anything, so let’s turn around and see what the W3C says in it’s guidelines for WCAG 2.0 standards:

[…] the designer might darken the background behind the letter, or add a thin black outline (at least one pixel wide) around the letter in order to keep the contrast ratio between the letter and the background above 4.5:1.

That’s talking about light text on a light background. WCAG recommends a contrast ratio that’s at least 4.5:1 between text and images. You can use text shadows to add a stronger contrast between them.

Photo credit: Woody Van der Straeten Shadows and performance

Before diving into shadows and adding them on all the things, it’s worth calling out that they do affect performance.

For example, filter: drop-shadow is hardware-accelerated by some browsers. A new compositor layer may be created for that element, and offloaded to the GPU. You don’t want to have too many layers, as it takes up limited GPU memory, and will eventually degrade performance. You can assess this in your browser’s DevTools.

Blurring is an expensive operation, so use it sparingly. When you blur something, it mixes the colors from pixels all around the output pixel to generate a blurred result. For example, if your <blur-radius> parameter is 2px, then the filter needs to look at two pixels in every direction around each output pixel to generate the mixed color. This happens for each output pixel, so that means a lot of calculations that grow exponentially. So, shadows with a large blur radius are generally slower to render than other shadows.

Did you know?

Did you know that shadows don’t influence the document layout?

A shadow is the same size as the element it targets. You can modify the size of a box-shadow (through the spread radius parameter), but other properties cannot modify the shadow size.

And did you know that a shadow implicitly has a lower z-index than elements? That’s why shadows sit below other elements.

And what about clipping and masking? If an element with a box-shadow is clipped (with clip-path) or uses a mask (with mask), the shadow isn’t shown. Conversely, if an element with text-shadow or filter: drop-shadow() is clipped, a shadow is shown, as long as it is within the clip region.

Here’s another: We can’t create oblique shadows (with diagonal lines) with shadow properties. That requires creating a shadow element and use a transform:skew() on it.

CodePen Embed Fallback

Oh, and one more: box-shadow follows border-radius. If an element has rounded corners, the shadow is rounded as well. In other words, the shadow mirrors the shape of the box. On the other hand, filter: drop-shadow() can create an irregular shape because it respects transparency and follows the shape of the content.

Best use cases for different types of shadows

Practically anything on the web can have a shadow and there are multiple CSS properties and functions that create shadows. But choosing the right type of shadow is what makes a shadow effective.

Let’s evaluate the options:

  • box-shadow: This CSS property creates shadows that conform to the elements bounding box. It’s versatile and can be used on anything from cards to buttons to just about anything where the shadow simply needs to follow the element’s box.
  • text-shadow: This is a CSS property that creates shadows specifically for text elements.
  • filter: drop-shadow(): The CSS property here is filter, but what create the shadow is the drop-shadow function it accepts. What makes this type of shadow different from, say box-shadow, is that it follows the rendered shape of any element (including pseudos).
  • <feDropShadow>: This is actually an SVG element, whereas the rest are CSS properties. So, you would use this to create drop shadows directly in SVG markup.

Once you get the hang of the different types of shadows and each one’s unique shadow-creating powers, the possibilities for shadow effects feels endless. From simple drop shadows to floating elements, and even inner shadows, we can create interesting visuals that add extra meaning or value to UI.

CodePen Embed Fallback

The same goes for text shadows.

CodePen Embed Fallback Shadows in the wild

Shadows are ubiquitous. We’re seeing them used in new and interesting ways all the time.

Have you heard the buzzword “neumorphism” floating around lately? That’s all about shadows. Here’s an implementation by Maria Muñoz:

CodePen Embed Fallback

Yuan Chuan, who makes amazing generative art, calls shadows a secret weapon in UI design:

CSS relies on existing DOM structure in the browser. It’s not possible to generate new elements other than ::before and ::after. Sometimes I really wish CSS had the ability to do so straightforwardly.

Yet, we can partially make up for this by creating various shadows and gradients entirely in CSS.

That’s why having drop-shadow is so exciting. Together with text-shadow and box-shadow we can do a lot more.

Just check out how he uses drop shadows to create intricate patterns.

CodePen Embed Fallback

Yes, that’s pretty crazy. And speaking of crazy, it’s worth mentioning that going too crazy can result in poor performance, so tread carefully.

What about pseudo-elements?

Oh yes, shadow properties are supported by the ::before and ::after pseudo-elements.

Other pseudos that respect shadows? The ::first-letter pseudo-element accepts box-shadow and text-shadow. The ::first-line pseudo-element accepts text-shadow.

Look at how Jhey Tompkins got all creative using box-shadow on pseudo elements to create animated loaders.

CodePen Embed Fallback Animating shadows

Yes, we can make them move! The properties and function we’ve covered here are totally compatible with CSS animations and transitions. That means we can move shadows, blur shadows, expand/shrink shadows (with box-shadow), and alter the color.

Animating a shadow can provide a user with a cue that an element is interactive, or that an action has taken place. We saw earlier with our button example that an inset shadow showed that the button had been pressed. Another common animation pattern is elevating a card on hover.

CodePen Embed Fallback

If you want to optimize the animation performance, avoid animating box-shadow! It is more performant to animate drop-shadow(). But if you want the smoothest animation, a hack is the best option! Add an ::after pseudo-element with a bigger box-shadow, and animate its opacity instead.

CodePen Embed Fallback

Of course, there is a lot more you can animate. I will leave that exploration up to you!

Wrapping up

Phew, who knew there was so much to something as seemingly “simple” as CSS shadows! There’s the light source and how shadows are cast. The different types of shadows and their color. There’s using shadows for evoking depth, elevating elements and insetting them. There’s the fact that we can layer shadows on top of other shadows. And that we have a selection of CSS properties that we can use for different use cases. Then, there are the accessibility and performance implications that come with them. And, hey, animation is thing! That’s a heckuva lot!

Anyway, hopefully this broad overview gave you something new to chew on, or at the very least, helped you brush up on some concepts.

The post Getting Deep into Shadows appeared first on CSS-Tricks.

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

To the brain, reading computer code is not the same as reading language

Css Tricks - Mon, 02/22/2021 - 5:56am

One of the things I do when teaching beginning front-end development is ask students to describe what it’s like to read HTML. I give them pretty basic markup for a long-form article, and ask them to read it twice: first in the code, then on the front end.

The #1 common response I hear? It’s like learning a new language.

Of course it is, I tell them. It’s in the name: Hypertext Markup Language. So, I advise them to start treating the materials in the course like they’re learning French, Spanish, or any other language.

Then I wake up this morning and see this MIT study that reading computer code is not the same as reading language, even though they share similarities.

In spite of those similarities, MIT neuroscientists have found that reading computer code does not activate the regions of the brain that are involved in language processing. Instead, it activates a distributed network called the multiple demand network, which is also recruited for complex cognitive tasks such as solving math problems or crossword puzzles.

Duh, you might say. But wait, reading code actually appears to activate additional parts of the multiple demand network that make the task more or a near-match to mathematical reasoning than the exact same thing.

The MIT team found that reading computer code appears to activate both the left and right sides of the multiple demand network […]. This finding goes against the hypothesis that math and coding rely on the same brain mechanisms.

So, back to my HTML reading assignment. Is it better to teach code as a language for recognizing symbols that communicate to the browser what to do, or as a math skill that’s based on solving problems?

The answer is &#x1f937;‍♂️.

The most interesting thing about the study to me is not how to teach code, but rather how how I work with it. Chris always says a front-end developer is aware, and the fact that reading code taps on a region of the brain that’s responsible for handling multi-tasking and holding lots of information only supports that. It also explains why I personally get annoyed when I’m pulled away from my code or distracted from it—it’s like my brain has to drop all the plates it was balancing to pay attention to something else, then pick up and reassemble all the pieces before I can jump back in to what I was doing.

Direct Link to ArticlePermalink

The post To the brain, reading computer code is not the same as reading language appeared first on CSS-Tricks.

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

Progressive enhancement and accessibility

QuirksBlog - Thu, 02/18/2021 - 1:29am

This article asks a question I don’t know the answer to: What is the exact relationship between progressive enhancement and accessiblity?

I mean, there is considerable overlap between the two. Good progressive enhancement can help accessibility, while accessibility can guide progressive enhancement decisions.

When I created the progressive enhancement reading list for my PE course in March I asked for good articles. I got a few submissions that I eventually rejected because they were about an accessibility problem that isn’t (quite) PE. Still, these submissions indicate that PE problems can be confused with accessibility ones. We instinctively we feel there’s considerable overlap between the two.

Still, they are not the same. You can have an thorny progressive enhancement problem that poses no accessibility problems, and you can have an accessibility problem that bears no relation to progressive enhancement.

The problem is that I can’t quite put my finger on where progressive enhancement and accessibility meet. Well, they can meet in individual problems, but that’s not what I mean. I’m looking for serious theoretical thought, and so far I haven’t found any. Also, my brain refuses to throw out a workable definition and stays stubbornly silent.

So can anyone define the relationship between progressive enhancement and accessibility? You can reach me via Twitter or my contact form.

Progressive Enhancement reading list 2021

QuirksBlog - Thu, 02/18/2021 - 1:23am

In March I am going to teach the Progressive Enhancement course of the Web minor at university for the third time. I decided to expand the reading list for this course, and here I present the version I’m going to use in 2021.

img { max-width: 100%; } Defining progressive enhancement

Let’s start at the original definition of progressive enhancement.

In 2008 Aaron Gustafson published Understanding Progressive Enhancement at A List Apart, and placed progressive enhancement at the forefront of web developer thinking. Aaron did not invent the concept — he points to prior art (slides) by Steve Champeon and Nick Finck. Still, Aaron’s article popularised the concept.

Aaron compares progressive enhancement to its precursor graceful degradation and finds that PE is the better approach — something that has become generally accepted since then. He also described progressive enhancement comprehensively, and we essentially still follow his definition.

Chris Taylor sees progressive enhancement as technical credit, the opposite of the technical debt you incur when you quickly insert some hacks to get the system to work and solemnly resolve to fix them “later.” (Hint: later never comes.) PE is the opposite: it prevents problems from arising, and thus saves you time in the future. The article also contains a useful overview of progressive enhancement principles.

Progressive enhancement also helps you combat browser incompatibilities. Justin Crawford, Chris Mills, and Ali Spivak make the web work for everyone by addressing cross-browser problems and their causes (which mostly come down to web developers not quite knowing what they’re doing). Better browser compatibility leads to better accessibility, and also to better results, since users will switch sites if they encounter problems. The best way to get these results is to practice PE. (And there we go again: PE and accessibility are clearly related. But how exactly?)

Their browser market share notes are worth repeating. Although Chrome is the largest browser, in January 2021 it still has only 63% of the market according to StatCounter. That sounds like a lot, but it means 37% of your users do not use Chrome. Don’t leave them out in the cold.

Does this sound theoretical? Let’s get practical. Robin Whittleton explains why we use progressive enhancement to build GOV.UK and walks you through the decisions. This is still a high-level overview, but it was actually used in an actual major website. We’ll see gov.uk in action later in this reading list.

Progressive enhancement and UX

The Nielsen Norman Group discusses the role of enhancement in web design and shows that progressive enhancement is useful in non-technical contexts as well. Where the previous articles focused on technical issues, this one gives a good theoretical overview of PE from a UX perspective.

What is progressive enhancement’s purpose in user interface design, and how do you decide which functionalities should be progressively enhanced? The article offers a few hardware examples, for instance the mouse wheel, which was a progressive enhancement when it was introduced, and still is, because touchscreen devices as well as keypads lack a wheel (and, in fact, a mouse). Input modes are ruled by PE, too.

Two excellent general rules are worth quoting in full:

  1. Don’t add other enhancements that provide the same functionality. [...] You want to give people the chance to practice and strengthen the enhancement; if you add other enhancements for the same interface functionality, it will be less likely that any one of them will get enough use.
  2. Be consistent. Use the same enhancement everywhere you can. That is, try to give users many opportunities to practice and thus strengthen the association between the enhancement and its effect in the interface. (Remember, repetition is the mother of retention.) Ideally, designers should use the same enhancements across many different sites, to allow people to learn them.

Aaron Walter created the Hierarchy of User Needs model, which forms the basis of a theory of user delight: why usability is the foundation for delightful experiences, also by the Nielsen Norman Group (image below borrowed from this article).

Delight is all very well, but without a solid foundation of usability, reliability, and functionality it falls flat. If something looks gorgeous but is incomprehensible, doesn’t always work, or doesn’t work at all, it is useless. The relationship between the four layers of user needs is pure progressive enhancement: the next layer is only useful if the layers below it work, and for each functionality you have to decide in which layer(s) to put it.

The PE layers

Let’s return to the technical aspects of progressive enhancement.

In order to progressively enhance a site you first need to define its core functionality. As Andy Bell says, a minimum viable experience makes for a resilient, inclusive website or app. He argues that porting the idea of a minimum viable product to the website experience is a good starting point for your PE project. Which core functionalities are required to give any user the opportunity to finish the task at hand? How do we identify a minimum viable experience, and how do we layer JavaScript functionalities on top of them?

Speaking of layers, Hidde de Vries explains why it's good for users that HTML, CSS and JS are separate languages. He argues that separation of concerns between structure, presentation, and behaviour remains a good thing. This impacts progressive enhancement by forcing you to think about which functionalities you should implement in which layer(s).

So let’s go through the layers.

Layer 1: HTML

Terence Eden discusses the unreasonable effectiveness of simple HTML by telling a story about a user being forced to work on a government-related task on the PlayStation browser (which is — let’s call it not good and leave it at that). The user managed to do what she set out because the site she needed had a simple, good HTML structure that works in any browser. This is what core functionality and minimum viable experience are all about. And you just need HTML to do it.

Dave Rupert created an indispensable list of HTML: the inaccessible parts, where he gives a round-up of accessibility problems with HTML elements. If you want to use any of these HTML elements you should apply the principles of progressive enhancement to make sure they work everywhere. This shows that HTML is not necessarily restricted to the lowest, functional layer but can also enhance (or detract from) the reliable, functional, and pleasurable layers. (Also, it shows yet again there is a close relationship between progressive enhancement and accessibility.)

Léonie Watson wrote a short note on progressive ARIA where she shows that changing the role of an element (here a link to a button; why?; but this happens all the time) also means you should make sure users can click it with the Space key. This is possible for buttons, but not for links, and if you change a link to a button the browser doesn’t automatically add the Space key. So you have to progressively enhance it.

Layer 2: CSS

I have not been able to find specific articles about CSS and progressive enhancement, although they must be out there. I’ll update this section when I find any.

Layer 3: JavaScript

Then we come to the elephant in the room: JavaScript. I mean, everyone has JavaScript, right? As Stuart Langridge shows, this is untrue. Even if the user doesn’t disable JavaScript explicitly there may be many reasons why they don’t have JavaScript.

Incidentally, measuring the number of users who turn off JavaScript is very easy. Just tweet something like “No one turns off JavaScript anyway,” wait for about a day for people to tell you in no uncertain terms they do in fact turn off JavaScript, count these reactions, and you know how many people turn off JavaScript.

Given that JavaScript is a progressive enhancement challenge, not only because it can be absent but also because “modern” web development uses such an incredible amount of it, Jeremy Keith’s 2014 call to be progressive remains relevant today. This article summarises an interesting discussion from those days and contains a lot of excellent points about how to view progressive enhancement, browsers, JavaScript, and more.

Jeremy calls for more server-side components:

Personally, I try not to completely reinvent all the business logic that I’ve already figured out on the server, and then rewrite it all in JavaScript. I prefer to use JavaScript—and specifically Ajax—as a dumb waiter, shuffling data back and forth between the client and server, where the real complexity lies.

I also think that building in this way will take longer …at first. But then on the next project, it takes less time. And on the project after that, it takes less time again. From that perspective, it’s similar to switching from tables for layout to using CSS, or switching from building fixed-with sites to responsive design: the initial learning curve is steep, but then it gets easier over time, until it simply becomes normal.

Did anyone listen to him in the years since 2014? (Hint: no.)

Chris James gives a quick overview of the past web, when things were still good, and describes the Web I Want. Then he gives a useful overview of why we don’t need that much JavaScript in our pages: HTML is already perfectly suited for showing content pages.

Finally, Thomas Steiner explains how to progressively enhance your Progressive Web App by digging into layers of JavaScript support in an advanced article. Assuming JavaScript is present, he gives an example where a simple but insufficient JavaScript is enhanced when the browser supports the File System Access API. He then gives a few other examples of modern APIs and how to feature-detect them. This is on a site by the Chrome devrel team, so it’s Chrome-centric in the features it treats, but the techniques Thomas teaches are applicable anywhere.

Practical examples

Jim Nielsen shows how he is progressively enhancing a small widget. This is a simple, first PE mini-project that is well suited to understand the basic concepts. He uses JavaScript to progressively enhance a static page, and the key takeaway is how the script changes the page’s static content.

Andy Bell (again) studies the power of progressive enhancement. He discusses a (no longer existing) web app in PE terms: start with the core functionality, then layer extras on top. Contains an excellent, simple bit of advice on how to handle the fact that some browsers don’t support CSS grid. This article highlights practical PE decisions and how they work.

Chris Scott created a practical Progressive Enhancement and Data Visualizations example project where he progressively enhances a timeline by first creating a solid HTML structure, then adds some presentational CSS, and then layers JavaScript and SVG on top that changes the presentation considerably.

That’s it. That was the reading list.

If you know of more good articles for the next version you can reach me via Twitter or my contact form.

Wed, 12/31/1969 - 2:00pm
Syndicate content
©2003 - Present Akamai Design & Development.