Šime Vidas – CSS-Tricks https://css-tricks.com Tips, Tricks, and Techniques on using Cascading Style Sheets. Thu, 02 Mar 2023 18:20:12 +0000 en-US hourly 1 https://wordpress.org/?v=6.2.2 https://i0.wp.com/css-tricks.com/wp-content/uploads/2021/07/star.png?fit=32%2C32&ssl=1 Šime Vidas – CSS-Tricks https://css-tricks.com 32 32 45537868 Everything You Need to Know About the Gap After the List Marker https://css-tricks.com/everything-you-need-to-know-about-the-gap-after-the-list-marker/ https://css-tricks.com/everything-you-need-to-know-about-the-gap-after-the-list-marker/#respond Thu, 02 Mar 2023 18:20:03 +0000 https://css-tricks.com/?p=376748 I was reading “Creative List Styling” on Google’s web.dev blog and noticed something odd in one of the code examples in the ::marker section of the article. The built-in list markers are bullets, ordinal numbers, and letters. The ::marker pseudo-element …


Everything You Need to Know About the Gap After the List Marker originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
I was reading “Creative List Styling” on Google’s web.dev blog and noticed something odd in one of the code examples in the ::marker section of the article. The built-in list markers are bullets, ordinal numbers, and letters. The ::marker pseudo-element allows us to style these markers or replace them with a custom character or image.

::marker {
  content: url('/marker.svg') ' ';
}

The example that caught my attention uses an SVG icon as a custom marker for the list items. But there’s also a single space character (" ") in the CSS value next to the url() function. The purpose of this space seems to be to insert a gap after the custom marker.

When I saw this code, I immediately wondered if there was a better way to create the gap. Appending a space to content feels more like a workaround than the optimal solution. CSS provides margin and padding and other standard ways to space out elements on the page. Could none of these properties be used in this situation?

First, I tried to substitute the space character with a proper margin:

::marker {
  content: url('/marker.svg');
  margin-right: 1ch;
}

This didn’t work. As it turns out, ::marker only supports a small set of mostly text-related CSS properties. For example, you can change the font-size and color of the marker, and define a custom marker by setting content to a string or URL, as shown above. But the margin and padding properties are not supported, so setting them has no effect. What a disappointment.

Could it really be that a space character is the only way to insert a gap after a custom marker? I needed to find out. As I researched this topic, I made a few interesting discoveries that I’d like to share in this article.

Adding padding and margins

First, let’s confirm what margin and padding do on the <ul> and <li> elements. I’ve created a test page for this purpose. Drag the relevant sliders and observe the effect on the spacing on each side of the list marker. Tip: Use the Reset button liberally to reset all controls to their initial values.

Note: Browsers apply a default padding-inline-left of 40px to <ol> and <ul> elements. The logical padding-inline-left property is equivalent to the physical padding-left property in writing systems with a left-to-right inline direction. In this article, I’m going to use physical properties for the sake of simplicity.

As you can see, padding-left on <li> increases the gap after the list marker. The other three properties control the spacing to the left of the marker, in other words, the indentation of the list item.

Notice that even when the list item’s padding-left is 0px, there is still a minimum gap after the marker. This gap cannot be decreased with margin or padding. The exact length of the minimum gap depends on the browser.

First three properties: UL margin-left, UL padding-left, LI margin-left. Fourth property: LI padding-left.
The first three properties push the entire list item (including the marker) to the right. The fourth property pushes only the list item’s content to the right.

To sum up, the list item’s content is positioned at a browser-specific minimum distance from the marker, and this gap can be further increased by adding a padding-left to <li>.

Next, let’s see what happens when we position the marker inside the list item.

Moving the marker inside the list item

The list-style-position property accepts two keywords: outside, which is the default, and inside, which moves the marker inside the list item. The latter is useful for creating designs with full-width list items.

A grocery list. Each item has a thin bottom border that extends from the left to the right edge of the list.
The list marker is positioned inside the list item, so that the list item’s bottom border can extend to the left edge of the list box

If the marker is now inside the list item, does this mean that padding-left on <li> no longer increases the gap after the marker? Let’s find out. On my test page, turn on list-style-position: inside via the checkbox. How are the four padding and margin properties affected by this change?

As you can see, padding-left on <li> now increases the spacing to the left of the marker. This means that we’ve lost the ability to increase the gap after the marker. In this situation, it would be useful to be able to add margin-right to the ::marker itself, but that doesn’t work, as we’ve established above.

The four properties: UL margin-left, UL padding-left, LI margin-left, LI padding-left.
All four properties push the entire list item to the right. The minimum gap cannot be increased by standard means.

Additionally, there’s a bug in Chromium that causes the gap after the marker to triple after switching to inside positioning. By default, the length of the gap is about one-third of the text size. So at a default font-size of 16px, the gap is about 5.5px. After switching to inside, the gap grows to the full 16px in Chrome. This bug affects the disc, circle, and square markers, but not ordinal number markers.

The following image shows the default rendering of outside and inside-positioned list markers across three major browsers on macOS. For your convenience, I’ve horizontally aligned all list items on their markers to make it easier to compare the differences in gap sizes.

Six list items with varying gaps between the marker and text.
Only Firefox maintains the same gap size between the two marker positioning modes. This can be considered a browser interoperability (interop) issue.

To sum up, switching to list-style-position: inside introduces two problems. We can no longer increase the gap via padding-left on <li>, and the gap size is inconsistent between browsers.

Finally, let’s see what happens when we replace the default list marker with a custom marker.

Switching to a custom marker

There are two ways to define a custom marker:

  • list-style-type and list-style-image properties
  • content property on the ::marker pseudo-element

The content property is more powerful. For example, it allows us to use the counter() function to access the list item’s ordinal number (the implicit list-item counter) and decorate it with custom strings.

Unfortunately, Safari doesn’t support the content property on ::marker yet (WebKit bug). For this reason, I’m going to use the list-style-type property to define the custom marker. You can still use the ::marker selector to style the custom marker declared via list-style-type. That aspect of ::marker is supported in Safari.

Any Unicode character can potentially serve as a custom list marker, but only a small set of characters actually have “Bullet” in their official name, so I thought I’d compile them here for reference.

CharacterNameCode pointCSS keyword
BulletU+2022disc
Triangular BulletU+2023
Hyphen BulletU+2043
Black Leftwards BulletU+204C
Black Rightwards BulletU+204D
Inverse BulletU+25D8
White BulletU+25E6circle
Reversed Rotated Floral Heart BulletU+2619
Rotated Heavy Black Heart BulletU+2765
Rotated Floral Heart BulletU+2767
Circled White BulletU+29BE
⦿Circled BulletU+29BF

Note: The CSS square keyword does not have a corresponding “Bullet” character in Unicode. The character that comes closest is the Black Small Square (▪️) emoji (U+25AA).

Now let’s see what happens when we replace the default list marker with list-style-type: "•" (U+2022 Bullet). This is the same character as the default bullet, so there shouldn’t be any major rendering differences. On my test page, turn on the list-style-type option and observe any changes to the marker.

As you can see, there are two significant changes:

  1. There is no longer a minimum gap after the marker.
  2. The bullet has become smaller, as if it were rendered at a smaller font-size.

According to CSS Counter Styles Level 3, the default list marker (disc) should be “similar to • U+2022 BULLET”. It seems that browsers increase the size of the default bullet to make it more legible. Firefox even uses a special font, -moz-bullet-font, for the marker.

:marker selected in the inspector. Fonts used: -moz-bullet-font.
The “Fonts” pane in Firefox’s DOM inspector reveals the special font.

Can the small size problem be fixed with CSS? On my test page, turn on marker styling and observe what happens when you change the font-size, line-height, and font-family of the marker.

As you can see, increasing the font-size causes the custom marker to become vertically misaligned, and this cannot be corrected by decreasing the line-height. The vertical-align property, which could easily fix this problem, is not supported on ::marker.

But did you notice that changing the font-family can cause the marker to become bigger? Try setting it to Tahoma. This could potentially be a good-enough workaround for the small-size problem, although I haven’t tested which font works best across the major browsers and operating systems.

You may also have noticed that the Chromium bug doesn’t occur anymore when you position the marker inside the list item. This means that a custom marker can serve as a workaround for this bug. And this leads me to the main problem, and the reason why I started researching this topic. If you define a custom marker and position it inside the list item, there is no gap after the marker and no way to insert a gap by standard means.

  1. There is no minimum gap after custom markers.
  2. ::marker doesn’t support padding or margin.
  3. padding-left on <li> doesn’t increase the gap, since the marker is positioned inside.

Summary

Here’s a summary of all the key facts that I’ve mentioned in the article:

  1. Browsers apply a default padding-inline-start of 40px to <ul> and <ol> elements.
  2. There is a minimum gap after built-in list markers (disc, decimal, etc.). There is no minimum gap after custom markers (string or URL).
  3. The length of the gap can be increased by adding a padding-left to <ul>, but only if the marker is positioned outside the list item (the default mode).
  4. Custom string markers have a smaller default size than built-in markers. Changing the font-family on ::marker can increase their size.

Conclusion

Looking back at the code example from the beginning of the article, I think I understand now why there’s a space character in the content value. There is just no better way to insert a gap after the SVG marker. It’s a workaround that is needed because no amount of margin and padding can create a gap after a custom marker that is positioned inside the list item. A margin-right on ::marker could easily do it, but that is not supported.

Until ::marker adds support for more properties, web developers will often have no choice but to hide the marker and emulate it with a ::before pseudo-element. I had to do that myself recently because I couldn’t change the marker’s background-color. Hopefully, we won’t have to wait too long for a more powerful ::marker pseudo-element.


Everything You Need to Know About the Gap After the List Marker originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/everything-you-need-to-know-about-the-gap-after-the-list-marker/feed/ 0 376748
How I Added Scroll Snapping To My Twitter Timeline https://css-tricks.com/how-i-added-scroll-snapping-to-my-twitter-timeline/ https://css-tricks.com/how-i-added-scroll-snapping-to-my-twitter-timeline/#comments Fri, 05 Aug 2022 13:10:09 +0000 https://css-tricks.com/?p=367283 CSS Scroll Snap allows websites to snap the web page or any other scroll container to a specific scroll position when the user performs a scrolling operation. This feature has been supported in all modern browsers for over two years, …


How I Added Scroll Snapping To My Twitter Timeline originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
CSS Scroll Snap allows websites to snap the web page or any other scroll container to a specific scroll position when the user performs a scrolling operation. This feature has been supported in all modern browsers for over two years, but many websites that could benefit from it are still not using it.

Scroll snapping is probably most associated with horizontal carousels (see Chris’s CSS-only approach) and particular web pages divided into full-screen slides. But why stop there? I believe that snapping can improve the scrolling experience on any web page that lays out items in a grid or feed.

For example, most shopping websites show products in a grid. Ideally, the user would like to jump between the grid rows with minimal effort. The user can press Space to scroll the page by roughly one screen (viewport height), but depending on the height of the grid rows, the scroll position will eventually get “out of sync” with the grid, and the user will have to re-adjust it manually.

If we add scroll snapping to this page, the user can consistently scroll to the next row with the Space key (pressing Shift + Space will scroll to the previous row). It’s pretty effortless.

I think that scroll snapping would be a welcome addition to this website. And it’s not even that complicated to implement. The CSS code that I used for this example is relatively simple:

html {
  scroll-snap-type: y proximity;
}

.product-item {
  scroll-snap-align: start;
  scroll-margin-top: 75px; /* height of web page’s sticky header */
}

You don’t have to wait if a website you visit regularly hasn’t yet added scroll snapping and you think it would improve your scrolling experience. You can add scroll snapping yourself — with user styles.

Adding user styles to websites

In the video above, you can see that I selected a user.css file in Safari’s advanced preferences. This file is a user style sheet. It contains CSS styles that I’ve written, stored in a local .css file, and added to Safari. These “user styles” are then applied to every web page I open in Safari.

Chrome and Firefox do not allow users to select a user style sheet. Firefox supported a similar feature called userContent.css in the past, but that feature was deprecated and disabled by default in 2019. I recommend the Stylus browser extension for these two browsers (and other Chromium-based browsers).

One significant advantage of Stylus is that it allows you to write user styles for specific websites and URLs. Safari’s user style sheet applies to all websites, but this can be worked around, e.g., by using the new :has() pseudo-class to create selectors that only match specific websites.

The Stylus extension has been reviewed by both Chrome and Firefox teams and received a badge that denotes high standards.

The CSS Cascading module defines a User Origin for styles the user adds. Safari’s user style sheet belongs to this origin, but the Stylus extension injects user styles to the Author Origin, where the website’s style sheets live. Specifically, Stylus inserts user styles directly to the page via a <style> element at the end of <html> which makes it the final style sheet on the page. Technically, this means styles added via Stylus are classified as author styles since they’re not in the User Origin, but I will continue to call them user styles because the user adds them.

However, it’s worth keeping this distinction in mind because it affects the cascade. When selector specificity is equal, a real user style is weaker than the page’s own style. This makes user styles an excellent fit for user defaults. Under the same conditions, a style added via Stylus is stronger than the page‘s style, so Stylus cannot as easily be used to define user defaults.

If we add !important to the mix, both real user styles and styles added via Stylus are stronger than the page’s styles. So when you want to impose your user styles on a website, it doesn’t matter if you use Safari’s “Style sheet” option or the Stylus extension. Your !important styles will win either way.

In the next section, I will use a set of !important user styles to enforce scroll snapping on the timeline page of Twitter’s website. My goal is to speed up the process of reading my Twitter timeline by avoiding awkward scroll positions where the topmost tweet is only partially on screen.

Scroll snap for Twitter’s timeline

After some experimentation, I’ve settled on the following CSS code. These styles work well in Firefox, but I’ve experienced some issues in Chrome and Safari. I will describe these issues in more detail later in the article, but for now, let’s focus on the behavior in Firefox.

html {
  scroll-snap-type: y mandatory !important;
}

/* tweets in the timeline are <article> elements */
article {
  scroll-snap-align: start !important;
}

/* un-stick the sticky header and make it “snappable” as well */
[aria-label="Home timeline"] > :first-child {
  position: static !important;
  scroll-snap-align: start !important;
}

/* hide the “new Tweets available” floating toast notification */
[aria-label="New Tweets are available."] {
  display: none !important;
}

It is necessary to add !important to each declaration because all the user styles must win over the web page’s own styles for our custom scroll snapping implementation to work correctly. I wish that instead of repeatedly writing !important, I could just put my user styles in an “important layer,” but such a CSS feature does not exist (yet).

Watch the video below to see my scroll snap user styles in action. Notice how each press on the Space key scrolls the next set of tweets into view, and the first tweet of each set is aligned to the top edge of the viewport. This allows me to read my timeline more quickly. When I need to go back to the previous set of tweets, I can press Shift + Space.

What I like about this type of scroll snapping is that it allows me to predict how far the page will scroll whenever I press Space. Each scroll distance equals the combined heights of the visible tweets that are entirely on the screen. In other words, the partially visible tweet at the bottom of the screen will move to the top of the screen, which is precisely what I want.

I know in advance that pressing Space will scroll Dave’s tweet to the top of the screen.

To try out my scroll snap user styles on your own Twitter timeline, follow these steps:

  1. Install the Stylus extension with Firefox Add-ons or the Chrome Web Store.
  2. Navigate to your Twitter timeline at https://twitter.com/home.
  3. Click the Stylus icon in the browser’s toolbar and click “this URL” in the pop-up.
  4. Stylus will open a code editor in a new browser tab. Copy-paste my scroll snap user styles into the editor and press the Save button in the sidebar on the left. The styles will be applied to your Twitter timeline immediately (no need to reload the page).
  5. You can update the styles at any time. Click the Stylus icon and the Pencil icon to open the editor again.

Inability to override snapping

My implementation of scroll snapping for Twitter’s timeline has one major flaw. If a tweet is taller than the viewport, it is impossible to scroll the page to reveal the bottom part of that tweet (e.g., if you want to like or retweet that tweet) because the browser forcefully snaps the page to show the top of the tweet (or the top of the following tweet).

The severity of this problem depends on the user’s display. Viewing Twitter’s timeline on a large desktop monitor at a small page zoom factor, you may not encounter any tweets taller than the viewport.

I have asked the CSS Working Group if it would be possible to add a mechanism allowing the user to override the browser’s mandatory scroll snapping. I should probably mention that this problem could, at least in theory, be resolved by switching from mandatory to proximity snapping. I’ve tested proximity snapping in Chrome and Firefox, and I found it inconsistent and confusing. The browser would often snap when I didn’t expect it to, and vice versa. Maybe Twitter’s code is interfering with the proximity algorithm, the browsers are still a bit buggy, or perhaps I’m just “scrolling it wrong,” if that’s even possible. I don’t know.

But the main reason why I went with mandatory snapping is that I wanted to avoid situations where the topmost tweet is only partially on screen after a scroll. The type of fast-scrolling between sets of tweets that I’ve shown in the video above is only possible with mandatory snapping.

If you, like me, prefer mandatory snapping, I can suggest the following two workarounds for the “tall tweet” problem:

  • You can open the tweet on its own page and return to the timeline afterward.
  • If you only want to click the Like or Retweet buttons, you can Shift-click the tweet to select it and then press L to like it, or T followed by Enter to retweet it.

Issues in Chrome and Safari

My scroll snap user styles produce noticeably different scroll snapping behaviors in Chrome, Safari, and Firefox. Those differences are in part since the exact implementation of the snapping mechanism is left up to the browser:

The CSS Scroll Snap Module intentionally does not specify nor mandate any precise animations or physics used to enforce snap positions; this is left up to the user agent.

The current version of Safari has a bug that prevents scroll snapping from working correctly on the Twitter timeline. I have reported this bug.

In Chrome, I have encountered the following problems:

  • The scrolling operations animate inconsistently. Sometimes the animation is slow, sometimes it’s instant, and sometimes it starts slow but is then cut short. I found this irritating.
  • The scrolling operations animate too slowly in general. I performed a test in Chrome and Firefox (20 Space presses), and it took me 70% more time to cover the same distance on my Twitter timeline in Chrome than in Firefox (18.5 seconds in Chrome vs. 11 seconds in Firefox).
  • When I scroll using my laptop’s trackpad, the page flickers a lot. When I attempt to scroll fast by holding down the Space key, the page scrolls very slowly and oscillates. I suspect that both issues are caused by the same algorithm. It seems that Chrome re-snaps at a very high rate in these cases. I have reported this bug.

These browser bugs and differences between browsers can be a problem for websites considering implementing scroll snapping. For example, a web developer might hold back because they don’t like how scroll snapping behaves in one particular browser. Browsers can mitigate this problem by becoming more interoperable. In fact, Scroll Snap is one of the areas of focus of the cross-browser Interop 2022 effort.

Another way the situation could be improved is by introducing new CSS properties that would make scroll snapping more configurable. This could include the duration of the snapping animation, the length of the proximity threshold for snapping, and a mechanism to override mandatory snapping.

To snap or not to snap?

I’ve been using my scroll snap user styles on Twitter’s timeline for a couple of weeks, and I don’t want to go back. The ability to quickly flip through my feed with only the Space key is just on another level.

However, I consider this an advanced feature that probably isn’t for everyone. There’s a reason why I’ve enabled it only on the timeline (/home path) and nowhere else on Twitter’s website. Snapping is a significant change in how the page scrolls, and it takes some time to get used to. It can work great for a specific use case, but it can also get in the way and frustrate the user.

Websites with feeds should therefore consider offering scroll snapping only as an optional feature, after careful consideration and plenty of testing in different browsers and with different input methods (mouse, keyboard, trackpad, touch screen, etc.).

Before you go…

Finally, I highly recommend installing and trying out the Stylus browser extension. Web developers (or anyone who knows CSS) have the power to style any website in their browser. You can apply minor improvements and fixes to your favorite websites. I mostly use it to hide page elements that I find annoying, such as sticky headers, video pop-ups, and vote counts.

But more importantly, Stylus allows you to quickly test new CSS features on any website and report browser bugs, if necessary. By doing this, you can help make the web platform a little better.


How I Added Scroll Snapping To My Twitter Timeline originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/how-i-added-scroll-snapping-to-my-twitter-timeline/feed/ 8 367283
When to Avoid the text-decoration Shorthand Property https://css-tricks.com/when-to-avoid-css-text-decoration-shorthand/ https://css-tricks.com/when-to-avoid-css-text-decoration-shorthand/#comments Fri, 25 Feb 2022 15:28:33 +0000 https://css-tricks.com/?p=363619 In my recent article about CSS underline bugs in Chrome, I discussed text-decoration-thickness and text-underline-offset, two relatively new and widely-supported CSS properties that give us more control over the styling of underlines.

Let me demonstrate the usefulness of …


When to Avoid the text-decoration Shorthand Property originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
In my recent article about CSS underline bugs in Chrome, I discussed text-decoration-thickness and text-underline-offset, two relatively new and widely-supported CSS properties that give us more control over the styling of underlines.

Let me demonstrate the usefulness of text-decoration-thickness on a simple example. The Ubuntu web font has a fairly thick default underline. We can make this underline thinner like so:

:any-link {
  text-decoration-thickness: 0.08em;
}
Showing two links, a default and one that decreases the text-decoration-thickness.

/explanation Throughout this article, I will use the :any-link selector instead of the a element to match hyperlinks. The problem with the a tag as a selector is that it matches all <a> elements, even the ones that don’t have a href attribute and thus aren’t hyperlinks. The :any-link selector only matches <a> elements that are hyperlinks. Web browsers also use :any-link instead of a in their user agent stylesheets.

Hover underlines

Many websites, including Google Search and Wikipedia, remove underlines from links and only show them when the user hovers a link. Removing underlines from links in body text is not a good idea, but it can make sense in places where links are more spaced apart (navigation, footer, etc.). With that being said, here’s a simple implementation of hover underlines for links in the website’s header:

header :any-link {
  text-decoration: none;
}

header :any-link:hover {
  text-decoration: underline;
}

But there’s a problem. If we tested this code in a browser, we’d notice that the underlines in the header have the default thickness, not the thinner style that we declared earlier. Why did text-decoration-thickness stop working after we added hover underlines?

Let’s look at the full CSS code again. Can you think of a reason why the custom thickness doesn’t apply to the hover underline?

:any-link {
  text-decoration-thickness: 0.08em;
}

header :any-link {
  text-decoration: none;
}

header :any-link:hover {
  text-decoration: underline;
}

The reason for this behavior is that text-decoration is a shorthand property and text-decoration-thickness its associated longhand property. Setting text-decoration to none or underline has the side effect of re-initializing the other three text decoration components (thickness, style, and color). This is defined in the CSS Text Decoration module:

The text-decoration property is a shorthand for setting text-decoration-line, text-decoration-thickness, text-decoration-style, and text-decoration-color in one declaration. Omitted values are set to their initial values.

You can confirm this in the browser’s DevTools by selecting one of the hyperlinks in the DOM inspector and then expanding the text-decoration property in the CSS pane.

DevTools screenshot showing text-decoration styles on the :any-link pseudo-selector.

In order to get text-decoration-thickness to work on hover underlines, we’ll have to make a small change to the above CSS code. There are actually multiple ways to achieve this. We could:

  • set text-decoration-thickness after text-decoration,
  • declare the thickness in the text-decoration shorthand, or
  • use text-decoration-line instead of text-decoration.

Choosing the best text-decoration option

Our first thought might be to simply repeat the text-decoration-thickness declaration in the :hover state. It’s a quick and simple fix that indeed works.

/* OPTION A */

header :any-link {
  text-decoration: none;
}

header :any-link:hover {
  text-decoration: underline;
  text-decoration-thickness: 0.08em; /* set thickness again */
}

However, since text-decoration is a shorthand and text-decoration-thickness is its associated longhand, there really should be no need to use both at the same time. As a shorthand, text-decoration allows setting both the underline itself and the underline’s thickness, all in one declaration.

/* OPTION B */

header :any-link {
  text-decoration: none;
}

header :any-link:hover {
  text-decoration: underline 0.08em; /* set both line and thickness */
}

If this code looks unfamiliar to you, that could be because the idea of using text-decoration as a shorthand is relatively new. This property was only subsequently turned into a shorthand in the CSS Text Decoration module. In the days of CSS 2, text-decoration was a simple property.

Unfortunately, Safari still hasn’t fully caught up with these changes. In the WebKit browser engine, the shorthand variant of text-decoration remains prefixed (-webkit-text-decoration), and it doesn’t support thickness values yet. See WebKit bug 230083 for more information.

This rules out the text-decoration shorthand syntax. The above code won’t work in Safari, even if we added the -webkit- prefix. Luckily, there’s another way to avoid repeating the text-decoration-thickness declaration.

When text-decoration was turned into a shorthand, a new text-decoration-line longhand was introduced to take over its old job. We can use this property to hide and show the underline without affecting the other three text decoration components.

/* OPTION C */

header :any-link {
  text-decoration-line: none;
}

header :any-link:hover {
  text-decoration-line: underline;
}

Since we’re only updating the line component of the text-decoration value, the previously declared thickness remains intact. I think that this is the best way to implement hover underlines.

Be aware of shorthands

Keep in mind that when you set a shorthand property, e.g., text-decoration: underline, any missing parts in the value are re-initialized. This is also why styles such as background-repeat: no-repeat are undone if you set background: url(flower.jpg) afterwards. See the article “Accidental CSS Resets” for more examples of this behavior.


When to Avoid the text-decoration Shorthand Property originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/when-to-avoid-css-text-decoration-shorthand/feed/ 2 363619
CSS Underlines Are Too Thin and Too Low in Chrome https://css-tricks.com/css-underlines-are-too-thin-and-too-low-in-chrome/ https://css-tricks.com/css-underlines-are-too-thin-and-too-low-in-chrome/#comments Tue, 04 Jan 2022 15:30:18 +0000 https://css-tricks.com/?p=359838 I’ve encountered two bugs in Chrome while testing the new CSS text-decoration-thickness and text-underline-offset properties, and I want to share them with you here in this article.

Table of Contents


CSS Underlines Are Too Thin and Too Low in Chrome originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
I’ve encountered two bugs in Chrome while testing the new CSS text-decoration-thickness and text-underline-offset properties, and I want to share them with you here in this article.

Table of Contents

First, let’s acknowledge one thing:

Default underlines are inconsistent

Let’s add a text link to a plain web page, set its font-family to Arial, and compare the underlines across browsers and operating systems.

From left to right: Chrome, Safari, and Firefox on macOS; Safari on iOS; Chrome, and Firefox on Windows; Chrome, and Firefox on Android.

As you can see, the default underline is inconsistent across browsers. Each browser chooses their own default thickness and vertical position (offset from the baseline) for the underline. This is in line with the CSS Text Decoration module, which specifies the following default behavior (auto value):

The user agent chooses an appropriate thickness for text decoration lines. […] The user agent chooses an appropriate offset for underlines.

Luckily, we can override the browsers’ defaults

There are two new, widely supported CSS properties that allow us to precisely define the thickness and offset for our underlines:

With these properties, we can create consistent underlines even across two very different browsers, such as the Gecko-based Firefox on Android and the WebKit-based Safari on macOS.

h1 {
  text-decoration: underline;
  text-decoration-thickness: 0.04em;
  text-underline-offset: 0.03em;
}
Top row: the browsers’ default underlines; bottom row: consistent underlines with CSS. (Demo)

Note: The text-decoration-thickness property also has a special from-font value that instructs browsers to use the font’s own preferred underline width, if available. I tested this value with a few different fonts, but the underlines were inconsistent.

OK, so let’s move on to the two Chrome bugs I noted earlier.

Chrome bug 1: Underlines are too thin on macOS

If you set the text-decoration-thickness property to a font-relative length value that computes to a non-integer pixel value, Chrome will “floor” that value instead of rounding it to the nearest integer. For example, if the declared thickness is 0.06em, and that computes to 1.92px, Chrome will paint a thickness of 1px instead of 2px. This issue is limited to macOS.

a {
  font-size: 2em; /* computes to 32px */
  text-decoration-thickness: 0.06em; /* computes to 1.92px */
}

In the following screenshot, notice how the text decoration lines are twice as thin in Chrome (third row) than in Safari and Firefox.

From top to bottom: Safari, Firefox, and Chrome on macOS. (Demo)

For more information about this bug, see Chromium issue #1255280.

Chrome bug 2: Underlines are too low

The text-underline-offset property allows us to precisely set the distance between the alphabetic baseline and the underline (the underline’s offset from the baseline). Unfortunately, this feature is currently not implemented correctly in Chrome and, as a result, the underline is positioned too low.

h1 {
  text-decoration: underline;
  text-decoration-color: #f707;

  /* disable “skip ink” */
  -webkit-text-decoration-skip: none; /* Safari */
  text-decoration-skip-ink: none;

  /* cover the entire descender */
  text-decoration-thickness: 0.175em; /* descender height */
  text-underline-offset: 0; /* no offset from baseline */
}

Because of this bug, it is not possible to move the underline all the way up to the baseline in Chrome.

From left to right: Safari, Firefox, and Chrome on macOS. View this demo on CodePen.

For more information about this bug, see Chromium issue #1172623.

Note: As you might have noticed from the image above, Safari draws underlines on top of descenders instead of beneath them. This is a WebKit bug that was fixed very recently. The fix should ship in the next version of Safari.

Help prioritize the Chrome bugs

The two new CSS properties for styling underlines are a welcome addition to CSS. Hopefully, the two related Chrome bugs will be fixed sooner rather than later. If these CSS features are important to you, make your voice heard by starring the bugs in Chromium’s bug tracker.

Sign in with your Google account and click the star button on issues #1172623 and #1255280.

CSS Underlines Are Too Thin and Too Low in Chrome originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/css-underlines-are-too-thin-and-too-low-in-chrome/feed/ 4 359838
Firefox’s `bolder` Default is a Problem for Variable Fonts https://css-tricks.com/firefoxs-bolder-default-is-a-problem-for-variable-fonts/ https://css-tricks.com/firefoxs-bolder-default-is-a-problem-for-variable-fonts/#comments Tue, 07 Sep 2021 14:41:57 +0000 https://css-tricks.com/?p=351017 Variable fonts make it easy to create a large set of font styles from a single font file. Unfortunately, the default rendering of the <b> and <strong> elements in browsers today is not very compatible with the wide range of …


Firefox’s `bolder` Default is a Problem for Variable Fonts originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
Variable fonts make it easy to create a large set of font styles from a single font file. Unfortunately, the default rendering of the <b> and <strong> elements in browsers today is not very compatible with the wide range of font-weight values enabled by variable fonts.

https://twitter.com/zachleat/status/1374443096281280517

Browsers disagree on the default font-weight of <b>

The purpose of the <b> and <strong> elements is to draw attention to a specific word or span of text on the page. Browsers make these elements stand out by increasing their font-weight. This works well under normal conditions. For example, MDN Web Docs uses <b> in a few places in the “Found a problem?” card at the bottom of each page.

Screenshot of an MDN article with red arrows pointing at instances of bolded words on the page.

Things become more complicated when the text on the page has a custom font-weight. The default weight of text is 400, but the font-weight property accepts any number between 1 and 1000 (inclusive). Let’s take a look at how Chrome and Firefox render text wrapped in <b> by default depending on the font-weight of the surrounding text.

View on CodePen

Chrome and Firefox disagree on the default rendering of <b> elements. Chrome uses a constant font-weight of 700 (Safari behaves the same), while Firefox chooses between three values (400, 700, and 900) depending on the font-weight of the surrounding text.

Where is this difference coming from?

As you might have guessed, Chrome and Firefox use different font-weight values for the <b> and <strong> elements in their user agent stylesheets.

/* Chrome and Safari’s user agent stylesheet */
strong, b {
  font-weight: bold;
}

/* Firefox’s user agent stylesheet */
strong, b {
  font-weight: bolder;
}

The bold and bolder values are specified in the CSS Fonts module; bold is equivalent to 700, while bolder is a relative weight that is calculated as follows:

If the outer text has a font-weight of…the bolder keyword computes to…
1 to 349400
350 to 549700
550 to 899900
900 to 1000No change (same value as outer text)

Chrome and Firefox disagree on the default rendering of <b>, but which browser follows the standards more closely? The font-weight property itself is defined in the CSS Fonts module, but the suggested font-weight values for different HTML elements are located in the Rendering section of the HTML Standard.

/* The HTML Standard suggests the following user agent style */
strong, b {
  font-weight: bolder;
}

The HTML Standard started suggesting bolder instead of bold all the way back in 2012. As of today, only Firefox follows this recommendation. Chrome and Safari have not made the switch to bolder. Because of this inconsistency, the popular Normalize base stylesheet has a CSS rule that enforces bolder across browsers.

Which of the two defaults is better?

There are two different defaults in browsers, and Firefox’s default matches the standard. So, should Chrome align with Firefox, or is Chrome’s default the better one? Let’s take another look at the default rendering of the <b> element.

View on CodePen

Each of the two defaults has a weak spot: Chrome’s bold default breaks down at higher font-weight values (around 700), while Firefox’s bolder default has a problem with lower font-weight values (around 300).

In the worst-case scenario for Firefox, text wrapped in <b> becomes virtually indiscernible. The following screenshot shows text at a font-weight of 349 in Firefox. Can you spot the single word that is wrapped in <b>? Firefox renders this element at a default font-weight of 400, which is an increase of only 51 points.

Three paragraphs of text about English scientist Tim Berners-Lee. All of the text appears to be the same font weight.
(View on CodePen)

The takeaway

If you use thin fonts or variable fonts at font-weight values below 350, be aware that the <b> and <strong> elements may not always be discernible in Firefox by default. In this case, it is probably a good idea to manually define a custom font-weight for <b> and <strong> instead of relying on the browser’s sub-optimal default, which insufficiently increases the font-weight of these elements.

/* Defining the regular and bold font-weight at the same time */

body {
  font-weight: 340;
}

b,
strong {
  font-weight: 620;
}

The bolder value is outdated and doesn’t work well with variable fonts. Ideally, text wrapped in <b> should be easy to spot regardless of the font-weight of the surrounding text. Browsers could achieve that by always increasing the font-weight by the same or a similar amount.

On that note, there is a discussion in the CSS Working Group about allowing percentages in font-weight in the same manner as in font-size. Lea Verou writes:

A far more common use case is when we want a bolder or lighter stroke than the surrounding text, in a way that’s agnostic to the weight of the surrounding text.

/* Increasing font-size by 100% */
h1 {
  font-size: 200%;
}

/* PROPOSAL - Increasing font-weight by 50% */
strong, b {
  font-weight: 150%;
}

Taking variable fonts into account, a value like 150% would probably be a better default than the existing bold/bolder defaults in browsers today.


Firefox’s `bolder` Default is a Problem for Variable Fonts originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/firefoxs-bolder-default-is-a-problem-for-variable-fonts/feed/ 4 351017
Custom State Pseudo-Classes in Chrome https://css-tricks.com/custom-state-pseudo-classes-in-chrome/ https://css-tricks.com/custom-state-pseudo-classes-in-chrome/#comments Thu, 06 May 2021 14:28:53 +0000 https://css-tricks.com/?p=339586 There is an increasing number of “custom” features on the web platform. We have custom properties (--my-property), custom elements (<my-element>), and custom events (new CustomEvent('myEvent')). At one point, we might even get custom media


Custom State Pseudo-Classes in Chrome originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
There is an increasing number of “custom” features on the web platform. We have custom properties (--my-property), custom elements (<my-element>), and custom events (new CustomEvent('myEvent')). At one point, we might even get custom media queries (@media (--my-media)).

But that’s not all! You might have missed it because it wasn’t mentioned in Google’s “New in Chrome 90” article (to be fair, declarative shadow DOM stole the show in this release), but Chrome just added support for yet another “custom” feature: custom state pseudo-classes (:--my-state).

Built-in states

Before talking about custom states, let’s take a quick look at the built-in states that are defined for built-in HTML elements. The CSS Selectors module and the “Pseudo-classes” section of the HTML Standard specify a number of pseudo-classes that can be used to match elements in different states. The following pseudo-classes are all widely supported in today’s browsers:

User action
:hover the mouse cursor hovers over the element
:active the element is being activated by the user
:focus the element has the focus
:focus-within the element has or contains the focus
Location
:visited the link has been visited by the user
:target the element is targeted by the page URL’s fragment
Input
:disabled the form element is disabled
:placeholder-shown the input element is showing placeholder text
:checked the checkbox or radio button is selected
:invalid the form element’s value is invalid
:out-of-range the input element’s value is outside the specificed range
:-webkit-autofill the input element has been autofilled by the browser
Other
:defined the custom element has been registered

Note: For brevity, some pseudo-classes have been omitted, and some descriptions don’t mention every possible use-case.

Custom states

Like built-in elements, custom elements can have different states. A web page that uses a custom element may want to style these states. The custom element could expose its states via CSS classes (class attribute) on its host element, but that’s considered an anti-pattern.

Chrome now supports an API for adding internal states to custom elements. These custom states are exposed to the outer page via custom state pseudo-classes. For example, a page that uses a <live-score> element can declare styles for that element’s custom --loading state.

live-score {
  /* default styles for this element */
}

live-score:--loading {
  /* styles for when new content is loading */
}

Let’s add a --checked state to a <labeled-checkbox> element

The Custom State Pseudo Class specification contains a complete code example, which I will use to explain the API. The JavaScript portion of this feature is located in the custom element‘s class definition. In the constructor, an “element internals” object is created for the custom element. Then, custom states can be set and unset on the internal states object.

Note that the ElementInternals API ensures that the custom states are read-only to the outside. In other words, the outer page cannot modify the custom element’s internal states.

class LabeledCheckbox extends HTMLElement {
  constructor() {
    super();

    // 1. instantiate the element’s “internals”
    this._internals = this.attachInternals();

    // (other code)
  }

  // 2. toggle a custom state
  set checked(flag) {
    if (flag) {
      this._internals.states.add("--checked");
    } else {
      this._internals.states.delete("--checked");
    }
  }

  // (other code)
}

The web page can now style the custom element’s internal states via custom pseudo-classes of the same name. In our example, the --checked state is exposed via the :--checked pseudo-class.

labeled-checkbox {
  /* styles for the default state */
}

labeled-checkbox:--checked {
  /* styles for the --checked state */
}
Try the demo in Chrome

This feature is not (yet) a standard

Browser vendors have been debating for the past three years how to expose the internal states of custom elements via custom pseudo-classes. Google’s Custom State Pseudo Class specification remains an “unofficial draft” hosted by WICG. The feature underwent a design review at the W3C TAG and has been handed over to the CSS Working Group. In Chrome’s ”intent to ship” discussion, Mounir Lamouri wrote this:

It looks like this feature has good support. It sounds that it may be hard for web developers to benefit from it as long as it’s not widely shipped, but hopefully Firefox and Safari will follow and implement it too. Someone has to implement it first, and given that there are no foreseeable backward incompatible changes, it sounds safe to go first.

We now have to wait for the implementations in Firefox and Safari. The browser bugs have been filed (Mozilla #1588763 and WebKit #215911) but have not received much attention yet.


Custom State Pseudo-Classes in Chrome originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/custom-state-pseudo-classes-in-chrome/feed/ 1 339586
Platform News: Using :focus-visible, BBC’s New Typeface, Declarative Shadow DOMs, A11Y and Placeholders https://css-tricks.com/platform-news-using-focus-visible-bbcs-new-typeface-declarative-shadow-doms-a11y-and-placeholders/ https://css-tricks.com/platform-news-using-focus-visible-bbcs-new-typeface-declarative-shadow-doms-a11y-and-placeholders/#comments Fri, 16 Apr 2021 14:33:05 +0000 https://css-tricks.com/?p=338429 There’s a whole lot of accessibility in this week’s news, from the nuances of using :focus-visible and input placeholders, to accessible typefaces and a Safari bug with :display: contents. Plus, a snippet for a bare-bones web component that supports …


Platform News: Using :focus-visible, BBC’s New Typeface, Declarative Shadow DOMs, A11Y and Placeholders originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
There’s a whole lot of accessibility in this week’s news, from the nuances of using :focus-visible and input placeholders, to accessible typefaces and a Safari bug with :display: contents. Plus, a snippet for a bare-bones web component that supports style encapsulation.

Now may be a good time to start using :focus-visible

The CSS :focus-visible pseudo-class replaces :focus as the new way to create custom focus indicators for keyboard users. Chrome recently switched from :focus to :focus-visible in the user agent stylesheet and, as a result of that change, the default focus ring is no longer shown when the user clicks or taps a button.

When switching from :focus to :focus-visible, consider backwards compatibility. Your keyboard focus indicators should be clearly visible in all browsers, not just the ones that support :focus-visible. If you only style :focus-visible, non-supporting browsers will show the default focus ring which, depending on your design, “may not be sufficiently clear or visible at all.”

button {
  background: white;
}

button:focus-visible {
  outline: none;
  background: #ffdd00; /* gold */
}

A good way to start using :focus-visible today is to define the focus styles in a :focus rule and then immediately undo these same styles in a :focus:not(:focus-visible) rule. This is admittedly not the most elegant and intuitive pattern, but it works well in all browsers:

  • Browsers that don’t support :focus-visible use the focus styles defined in the :focus rule and ignore the second style rule completely (because :focus-visible is unknown to them).
  • In browsers that do support :focus-visible, the second style rule reverts the focus styles defined in the :focus rule if the :focus-visible state isn’t active as well. In other words, the focus styles defined in the :focus rule are only in effect when :focus-visible is also active.
button:focus {
  outline: none;
  background: #ffdd00; /* gold */
}

button:focus:not(:focus-visible) {
  background: white; /* undo gold */
}

The BBC created a more accessible typeface

The BBC created their own custom typeface called Reith (named after the BBC’s founder Sir John Reith). Their goal was to create a font that supports multiple languages and is easier to read, especially on small devices. The font was tested with mixed-ability user groups (dyslexia and vision impairment) and across different screen sizes.

We [the BBC] were using Helvetica or Arial. We also had Gill Sans as the corporate typeface. These typefaces were designed a hundred years ago for the printed page [and] don’t perform well on today’s modern digital screens.

Reith Sans can bee seen in use on BBC Sport

Note: If you’d like to inspect Reith Sans and Reith Serif in Wakamai Fondue, you can quickly access the URLs of the WOFF2 files in the “All fonts on page” section of the Fonts pane in Firefox’s DOM inspector on BBC’s website.

display: contents is still not accessible in Safari

The CSS display: contents value has been supported in browsers since 2018. An element with this value “does not generate any boxes” and is effectively replaced by its children. This is especially useful in flex and grid layouts, where the contents value can be used to “promote” more deeply nested elements to flex/grid items while retaining a semantic document structure.

Source: Manuel Rego Casasnovas

Unfortunately, this feature originally shipped with an implementation bug that removed the element from the browser’s accessibility tree. For example, applying display: contents to a <ul> element resulted in that element no longer mentioned by screen readers. Since then, this bug has been fixed in Firefox and Chrome (in the latest version).

View on CodePen

In Chrome and Firefox, the screen reader informs the user that the “Main, navigation” contains a “list, 2 items.” In Safari, the latter part is missing because the <ul> and <li> elements are not present in the accessibility tree. Until Apple fixes this bug in Safari, be careful when using the contents value on semantic elements and test in screen readers to confirm that your pages are accessible in Safari as well.

Set opacity when overriding the color of placeholder text

Accessibility experts recommend avoiding placeholders if possible because they can be confused for pre-populated text and disappear when the user starts entering a value. However, many websites (including Wikipedia and GOV.UK) use placeholders in simple web forms that contain only a single input field, such as a search field.

The subscription form for the CSS-Tricks newsletter uses a placeholder in the email field

Placeholders can be styled via the widely supported ::placeholder pseudo-element. If your design calls for a custom color for placeholder text, make sure to specify both color and opacity. The latter is needed for Firefox, which applies opacity: 0.54 to ::placeholder by default. If you don’t override this value, your placeholder text may have insufficient contrast in Firefox.

.search-field::placeholder {
  color: #727272;
  opacity: 1; /* needed for Firefox */
}
The placeholder text on eBay’s website is lighter in Firefox and doesn’t meet the minimum contrast requirement of 4.5:1

Declarative shadow DOM could help popularize style encapsulation

One of the key features of shadow DOM is style encapsulation, wherein the outer page’s style rules don’t match elements inside the shadow tree, and vice versa. In order to use this feature, you need to attach a shadow DOM tree to an element (usually a custom element, like <my-element>) and copy the element’s template (usually from a <template> element in the DOM) to the element’s newly created shadow DOM.

These steps can only be performed in JavaScript. If you’re only interested in style encapsulation and don’t need any dynamic functionality for your element, here is the minimum amount of JavaScript required to create a custom element with a shadow DOM:

customElements.define(
  "my-element",
  class extends HTMLElement {
    constructor() {
      super();

      // find <template id="my-template"> in the DOM
      let template = document.getElementById("my-template");

      // make a copy of the template contents…
      let content = template.content.cloneNode(true);

      // …and inject it into <my-element>’s shadow DOM
      this.attachShadow({ mode: "open" }).appendChild(content);
    }
  }
);

For an example of style encapsulation, see Miriam Suzanne’s <media-object> element on CodePen. The scoped styles are located in the <template> element in the HTML pane. Notice how this CSS code can use simple selectors, such as article, that only match elements inside <media-object>’s shadow DOM.

JavaScript may soon no longer be required to create this type of style encapsulation in modern browsers. Earlier this week, Chrome became the first browser to ship Google’s Declarative Shadow DOM proposal. If it becomes a standard, this feature will also make it possible to use Shadow DOM in combination with server-side rendering.


Platform News: Using :focus-visible, BBC’s New Typeface, Declarative Shadow DOMs, A11Y and Placeholders originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/platform-news-using-focus-visible-bbcs-new-typeface-declarative-shadow-doms-a11y-and-placeholders/feed/ 4 338429
Platform News: Rounded Outlines, GPU-Accelerated SVG Animations, How CSS Variables Are Resolved https://css-tricks.com/platform-news-rounded-outlines-gpu-accelerated-svg-animations-how-css-variables-are-resolved/ https://css-tricks.com/platform-news-rounded-outlines-gpu-accelerated-svg-animations-how-css-variables-are-resolved/#comments Fri, 02 Apr 2021 19:35:28 +0000 https://css-tricks.com/?p=337636 In the news this week, Firefox gets rounded outlines, SVG animations are now GPU-accelerated in Chrome, there are no physical units in CSS, The New York Times crossword is accessible, and CSS variables are resolved before the value is inherited.…


Platform News: Rounded Outlines, GPU-Accelerated SVG Animations, How CSS Variables Are Resolved originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
In the news this week, Firefox gets rounded outlines, SVG animations are now GPU-accelerated in Chrome, there are no physical units in CSS, The New York Times crossword is accessible, and CSS variables are resolved before the value is inherited.

Let’s jump in the news!

Rounded outlines are coming to Firefox

The idea to have the outline follow the border curve has existed ever since it became possible to create rounded borders via the border-radius property in the mid 2000s. It was suggested to Mozilla, WebKit, and Chromium over ten years ago, and it’s even been part of the CSS UI specification since 2015:

The parts of the outline are not required to be rectangular. To the extent that the outline follows the border edge, it should follow the border-radius curve.

Fast-forward to today in 2021 and outlines are still rectangles in every browser without exception:

But this is finally starting to change. In a few weeks, Firefox will become the first browser with rounded outlines that automatically follow the border shape. This will also apply to Firefox’s default focus outline on buttons.

Three sets of round yellow buttons, comparing how Chrome, Firefox, and Safari handle outlines.

Please star Chromium Issue #81556 (sign in required) to help prioritize this bug and bring rounded outlines to Chrome sooner rather than later.

SVG animations are now GPU-accelerated in Chrome

Until recently, animating an SVG element via CSS would trigger repaint on every frame (usually 60 times per second) in Chromium-based browsers. Such constant repainting can have a negative impact on the smoothness of the animation and the performance of the page itself.

The latest version of Chrome has eliminated this performance issue by enabling hardware acceleration for SVG animations. This means that SVG animations are offloaded to the GPU and no longer run on the main thread.

Side by side comparison of the Performance tab in Chrome DevTools.
In this example, the SVG circle is continuously faded in and out via a CSS animation (see code)

The switch to GPU acceleration automatically made SVG animations more performant in Chromium-based browsers (Firefox does this too), which is definitely good news for the web:

Hooray for more screen reader-accessible, progressively enhanced SVG animations and less Canvas.

There cannot be real physical units in CSS

CSS defines six physical units, including in (inches) and cm (centimeters). Every physical unit is in a fixed ratio with the pixel unit, which is the canonical unit. For example, 1in is always exactly 96px. On most modern screens, this length does not correspond to 1 real-world inch.

The FAQ page of the CSS Working Group now answers the question why there can’t be real physical units in CSS. In short, the browser cannot always determine the exact size and resolution of the display (think projectors). For websites that need accurate real-world units, the Working Group recommends per-device calibration:

Have a calibration page, where you ask the user to measure the distance between two lines that are some CSS distance apart (say, 10cm), and input the value they get. Use this to find the scaling factor necessary for that screen (CSS length divided by user-provided length).

This scaling factor can then be set to a custom property and used to compute accurate lengths in CSS:

html {
  --unit-scale: 1.428;
}

.box {
  /* 5 real-world centimeters */
  width: calc(5cm * var(--unit-scale, 1));
}

The Times crossword is accessible to screen reader users

The NYT Open team wrote about some of the improvements to the New York Times website that have made it more accessible in recent years. The website uses semantic HTML (<article>, <nav>, etc.), increased contrast on important components (e.g., login and registration), and skip-to-content links that adapt to the site’s paywall.

Furthermore, the Games team made the daily crossword puzzle accessible to keyboard and screen reader users. The crossword is implemented as a grid of SVG <rect> elements. As the user navigates through the puzzle, the current square’s aria-label attribute (accessible name) is dynamically updated to provide additional context.

Screenshot of the crossword game with an open screen reader dialog announcing what is on the screen.
The screen reader announces the clue, the number of letters in the solution, and the position of the selected square

You can play the mini crossword without an account. Try solving the puzzle with the keyboard.

CSS variables are resolved before the value is inherited

Yuan Chuan recently shared a little CSS quiz that I didn’t answer correctly because I wasn’t sure if a CSS variable (the var() function) is resolved before or after the value is inherited. I’ll try to explain how this works on the following example:

html {
  --text-color: var(--main-color, black);
}

footer {
  --main-color: brown;
}

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

The question: Is the color of the paragraph in the footer black or brown? There are two possibilities. Either (A) the declared values of both custom properties are inherited to the paragraph, and then the color property resolves to brown, or (B) the --text-color property resolves to black directly on the <html> element, and then this value is inherited to the paragraph and assigned to the color property.

Two CSS rulesets, one as Option A and the other as Option B, both showing how variables are inherited and resolved between elements.

The correct answer is option B (the color is black). CSS variables are resolved before the value is inherited. In this case, --text-color falls back to black because --main-color does not exist on the <html> element. This rule is specified in the CSS Variables module:

It is important to note that custom properties resolve any var() functions in their values at computed-value time, which occurs before the value is inherited.


Platform News: Rounded Outlines, GPU-Accelerated SVG Animations, How CSS Variables Are Resolved originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/platform-news-rounded-outlines-gpu-accelerated-svg-animations-how-css-variables-are-resolved/feed/ 4 337636
Platform News: Prefers Contrast, MathML, :is(), and CSS Background Initial Values https://css-tricks.com/platform-news-prefers-contrast-mathml-is-and-css-background-initial-values/ https://css-tricks.com/platform-news-prefers-contrast-mathml-is-and-css-background-initial-values/#comments Fri, 19 Mar 2021 15:05:14 +0000 https://css-tricks.com/?p=336679 In this week’s round-up, prefers-contrast lands in Safari, MathML gets some attention, :is() is actually quite forgiving, more ADA-related lawsuits, inconsistent initial values for CSS Backgrounds properties can lead to unwanted — but sorta neat — patterns.

The prefers-contrast: more


Platform News: Prefers Contrast, MathML, :is(), and CSS Background Initial Values originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
In this week’s round-up, prefers-contrast lands in Safari, MathML gets some attention, :is() is actually quite forgiving, more ADA-related lawsuits, inconsistent initial values for CSS Backgrounds properties can lead to unwanted — but sorta neat — patterns.

The prefers-contrast: more media query is supported in Safari Preview

After prefers-reduced-motion in 2017, prefers-color-scheme in 2019, and forced-colors in 2020, a fourth user preference media feature is making its way to browsers. The CSS prefers-contrast: more media query is now supported in the preview version of Safari. This feature will allow websites to honor a user’s preference for increased contrast.

Screenshot of the iPhone 12 landing page on Apple's website. A big red arrow points out light grey text on the page.
Apple could use this new media query to increase the contrast of gray text on its website
.pricing-info {
  color: #86868b; /* contrast ratio 3.5:1 */
}

@media (prefers-contrast: more) {
  .pricing-info {
    color: #535283; /* contrast ratio 7:1 */
  }
}

Making math a first-class citizen on the web

One of the earliest specifications developed by the W3C in the mid-to-late ’90s was a markup language for displaying mathematical notations on the web called MathML. This language is currently supported in Firefox and Safari. Chrome’s implementation was removed in 2013 because of “concerns involving security, performance, and low usage on the Internet.”

If you’re using Chrome or Edge, enable “Experimental Web Platform features” on the about:flags page to view the demo.

There is a renewed effort to properly integrate MathML into the web platform and bring it to all browsers in an interoperable way. Igalia has been developing a MathML implementation for Chromium since 2019. The new MathML Core Level 1 specification is a fundamental subset of MathML 3 (2014) that is “most suited for browser implementation.” If approved by the W3C, a new Math Working Group will work on improving the accessibility and searchability of MathML.

The mission of the Math Working Group is to promote the inclusion of mathematics on the Web so that it is a first-class citizen of the web that displays well, is accessible, and is searchable.

CSS :is() upgrades selector lists to become forgiving

The new CSS :is() and :where() pseudo-classes are now supported in Chrome, Safari, and Firefox. In addition to their standard use cases (reducing repetition and keeping specificity low), these pseudo-classes can also be used to make selector lists “forgiving.”

For legacy reasons, the general behavior of a selector list is that if any selector in the list fails to parse […] the entire selector list becomes invalid. This can make it hard to write CSS that uses new selectors and still works correctly in older user agents.

In other words, “if any part of a selector is invalid, it invalidates the whole selector.” However, wrapping the selector list in :is() makes it forgiving: Unsupported selectors are simply ignored, but the remaining selectors will still match.

Unfortunately, pseudo-elements do not work inside :is() (although that may change in the future), so it is currently not possible to turn two vendor-prefixed pseudo-elements into a forgiving selector list to avoid repeating styles.

/* One unsupported selector invalidates the entire list */
::-webkit-slider-runnable-track, ::-moz-range-track {
  background: red;
}

/* Pseudo-elements do not work inside :is() */
:is(::-webkit-slider-runnable-track, ::-moz-range-track) {
  background: red;
}

/* Thus, the styles must unfortunately be repeated */
::-webkit-slider-runnable-track {
  background: red;
}
::-moz-range-track {
  background: red;
}

Dell and Kraft Heinz sued over inaccessible websites

More and more American businesses are facing lawsuits over accessibility issues on their websites. Most recently, the tech corporation Dell was sued by a visually impaired person who was unable to navigate Dell’s website and online store using the JAWS and VoiceOver screen readers.

The Defendant fails to communicate information about its products and services effectively because screen reader auxiliary aids cannot access important content on the Digital Platform. […] The Digital Platform uses visual cues to convey content and other information. Unfortunately, screen readers cannot interpret these cues and communicate the information they represent to individuals with visual disabilities.

Earlier this year, Kraft Heinz Foods Company was sued for failing to comply with the Web Content Accessibility Guidelines on one of the company’s websites. The complaint alleges that the website did not declare a language (lang attribute) and provide accessible labels for its image links, among other things.

In the United States, the Americans with Disabilities Act (ADA) applies to websites, which means that people can sue retailers if their websites are not accessible. According to the CEO of Deque Systems (the makers of axe), the recent increasing trend of web-based ADA lawsuits can be attributed to a lack of a single overarching regulation that would provide specific compliance requirements.

background-clip and background-origin have different initial values

By default, a CSS background is painted within the element’s border box (background-clip: border-box) but positioned relative to the element’s padding box (background-origin: padding-box). This inconsistency can result in unexpected patterns if the element’s border is semi-transparent or dotted/dashed.

A pink and triple rectangle with rounded edges. The colors overlap in a pattern.
.box {
  /* semi-transparent border */
  border: 20px solid rgba(255, 255, 255, 0.25);

  /* background gradient */
  background: conic-gradient(
    from 45deg at bottom left,
    deeppink,
    rebeccapurple
  );
}

Because of the different initial values, the background gradient in the above image is repeated as a tiled image on all sides under the semi-transparent border. In this case, positioning the background relative to the border box (background-origin: border-box) makes more sense.


Platform News: Prefers Contrast, MathML, :is(), and CSS Background Initial Values originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/platform-news-prefers-contrast-mathml-is-and-css-background-initial-values/feed/ 1 336679
Platform News: Defaulting to Logical CSS, Fugu APIs, Custom Media Queries, and WordPress vs. Italics https://css-tricks.com/platform-news-defaulting-to-logical-css-fugu-apis-custom-media-queries-and-wordpress-vs-italics/ https://css-tricks.com/platform-news-defaulting-to-logical-css-fugu-apis-custom-media-queries-and-wordpress-vs-italics/#comments Fri, 12 Mar 2021 15:51:32 +0000 https://css-tricks.com/?p=336380 Looks like 2021 is the time to start using CSS Logical Properties! Plus, Chrome recently shipped a few APIs that have raised eyebrows, SVG allows us to disable its aspect ratio, WordPress focuses on the accessibility of its typography, and …


Platform News: Defaulting to Logical CSS, Fugu APIs, Custom Media Queries, and WordPress vs. Italics originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
Looks like 2021 is the time to start using CSS Logical Properties! Plus, Chrome recently shipped a few APIs that have raised eyebrows, SVG allows us to disable its aspect ratio, WordPress focuses on the accessibility of its typography, and there’s still no update (or progress) on the development of CSS custom media queries.

Let’s jump right into the news…

Logical CSS could soon become the new default

Six years after Mozilla shipped the first bits of CSS Logical Properties in Firefox, this feature is now on a path to full browser support in 2021. The categories of logical properties and values listed in the table below are already supported in Firefox, Chrome, and the latest Safari Preview.

CSS property or valueThe logical equivalent
margin-topmargin-block-start
text-align: righttext-align: end
bottominset-block-end
border-leftborder-inline-start
(n/a)margin-inline

Logical CSS also introduces a few useful shorthands for tasks that in the past required multiple declarations. For example, margin-inline sets the margin-left and margin-right properties, while inset sets the top, right, bottom and left properties.

/* BEFORE */
main {
  margin-left: auto;
  margin-right: auto;
}

/* AFTER */
main {
  margin-inline: auto;
}

A website can add support for an RTL (right-to-left) layout by replacing all instances of left and right with their logical counterparts in the site’s CSS code. Switching to logical CSS makes sense for all websites because the user may translate the site to a language that is written right-to-left using a machine translation service. The biggest languages with RTL scripts are Arabic (310 million native speakers), Persian (70 million), and Urdu (70 million).

/* Switch to RTL when Google translates the page to an RTL language */
.translated-rtl {
  direction: rtl;
}

David Bushell’s personal website now uses logical CSS and relies on Google’s translated-rtl class to toggle the site’s inline base direction. Try translating David’s website to an RTL language in Chrome and compare the RTL layout with the site’s default LTR layout.

Chrome ships three controversial Fugu APIs

Last week Chrome shipped three web APIs for “advanced hardware interactions”: the WebHID and Web Serial APIs on desktop, and Web NFC on Android. All three APIs are part of Google’s capabilities project, also known as Project Fugu, and were developed in W3C community groups (though they’re not web standards).

  • The WebHID API allows web apps to connect to old and uncommon human interface devices that don’t have a compatible device driver for the operating system (e.g., Nintendo’s Wii Remote).
  • The Web Serial API allows web apps to communicate (“byte by byte”) with peripheral devices, such as microcontrollers (e.g., the Arduino DHT11 temperature/humidity sensor) and 3D printers, through an emulated serial connection.
  • Web NFC allows web apps to wirelessly read from and write to NFC tags at short distances (less than 10 cm).

Apple and Mozilla, the developers of the other two major browser engines, are currently opposed to these APIs. Apple has decided to “not yet implement due to fingerprinting, security, and other concerns.” Mozilla’s concerns are summarized on the Mozilla Specification Positions page.

Source: webapicontroversy.com

Stretching SVG with preserveAspectRatio=none

By default, an SVG scales to fit the <svg> element’s content box, while maintaining the aspect ratio defined by the viewBox attribute. In some cases, the author may want to stretch the SVG so that it completely fills the content box on both axes. This can be achieved by setting the preserveAspectRatio attribute to none on the <svg> element.

View demo

Distorting SVG in this manner may seem counterintuitive, but disabling aspect ratio via the preserveAspectRatio=none value can make sense for simple, decorative SVG graphics on a responsive web page:

This value can be useful when you are using a path for a border or to add a little effect on a section (like a diagonal [line]), and you want the path to fill the space.

WordPress tones down the use of italics

An italic font can be used to highlight important words (e.g., the <em> element), titles of creative works (<cite>), technical terms, foreign phrases (<i>), and more. Italics are helpful when used discreetly in this manner, but long sections of italic text are considered an accessibility issue and should be avoided.

Italicized text can be difficult to read for some people with dyslexia or related forms of reading disorders.

Putting the entire help text in italics is not recommended

WordPress 5.7, which was released earlier this week, removed italics on descriptions, help text, labels, error details text, and other places in the WordPress admin to “improve accessibility and readability.”

In related news, WordPress 5.7 also dropped custom web fonts, opting for system fonts instead.

Still no progress on CSS custom media queries

The CSS Media Queries Level 5 module specifies a @custom-media rule for defining custom media queries. This proposed feature was originally added to the CSS spec almost seven years ago (in June 2014) and has since then not been further developed nor received any interest from browser vendors.

@custom-media --narrow-window (max-width: 30em);

@media (--narrow-window) {
  /* narrow window styles */
}

A media query used in multiple places can instead be assigned to a custom media query, which can be used everywhere, and editing the media query requires touching only one line of code.

Custom media queries may not ship in browsers for quite some time, but websites can start using this feature today via the official PostCSS plugin (or PostCSS Preset Env) to reduce code repetition and make media queries more readable.

On a related note, there is also the idea of author-defined environment variables, which (unlike custom properties) could be used in media queries, but this potential feature has not yet been fully fleshed out in the CSS spec.

@media (max-width: env(--narrow-window)) {
  /* narrow window styles */
}

Platform News: Defaulting to Logical CSS, Fugu APIs, Custom Media Queries, and WordPress vs. Italics originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/platform-news-defaulting-to-logical-css-fugu-apis-custom-media-queries-and-wordpress-vs-italics/feed/ 2 336380
Weekly Platform News: Focus Rings, Donut Scope, More em Units, and Global Privacy Control https://css-tricks.com/weekly-platform-news-focus-rings-donut-scope-ditching-em-units-and-global-privacy-control/ https://css-tricks.com/weekly-platform-news-focus-rings-donut-scope-ditching-em-units-and-global-privacy-control/#comments Thu, 04 Mar 2021 21:33:01 +0000 https://css-tricks.com/?p=335856 In this week’s news, Chrome tackles focus rings, we learn how to get “donut” scope, Global Privacy Control gets big-name adoption, it’s time to ditch pixels in media queries, and a snippet that prevents annoying form validation styling.

Chrome will…


Weekly Platform News: Focus Rings, Donut Scope, More em Units, and Global Privacy Control originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
In this week’s news, Chrome tackles focus rings, we learn how to get “donut” scope, Global Privacy Control gets big-name adoption, it’s time to ditch pixels in media queries, and a snippet that prevents annoying form validation styling.

Chrome will stop displaying focus rings when clicking buttons

Chrome, Edge, and other Chromium-based browsers display a focus indicator (a.k.a. focus ring) when the user clicks or taps a (styled) button. For comparison, Safari and Firefox don’t display a focus indicator when a button is clicked or tapped, but do only when the button is focused via the keyboard.

The focus ring will stay on the button until the user clicks somewhere else on the page.

Some developers find this behavior annoying and are using various workarounds to prevent the focus ring from appearing when a button is clicked or tapped. For example, the popular what-input library continuously tracks the user’s input method (mouse, keyboard or touch), allowing the page to suppress focus rings specifically for mouse clicks.

[data-whatintent="mouse"] :focus {
  outline: none;
}

A more recent workaround was enabled by the addition of the CSS :focus-visible pseudo-class to Chromium a few months ago. In the current version of Chrome, clicking or tapping a button invokes the button’s :focus state but not its :focus-visible state. that way, the page can use a suitable selector to suppress focus rings for clicks and taps without affecting keyboard users.

:focus:not(:focus-visible) {
  outline: none;
}

Fortunately, these workarounds will soon become unnecessary. Chromium’s user agent stylesheet recently switched from :focus to :focus-visible, and as a result of this change, button clicks and taps no longer invoke focus rings. The new behavior will first ship in Chrome 90 next month.

The enhanced CSS :not() selector enables “donut scope”

I recently wrote about the A:not(B *) selector pattern that allows authors to select all A elements that are not descendants of a B element. This pattern can be expanded to A B:not(C *) to create a “donut scope.”

For example, the selector article p:not(blockquote *) matches all <p> elements that are descendants of an <article> element but not descendants of a <blockquote> element. In other words, it selects all paragraphs in an article except the ones that are in a block quotation.

The donut shape that gives this scope its name

The New York Times now honors Global Privacy Control

Announced last October, Global Privacy Control (GPC) is a new privacy signal for the web that is designed to be legally enforceable. Essentially, it’s an HTTP Sec-GPC: 1 request header that tells websites that the user does not want their personal data to be shared or sold.

The DuckDuckGo Privacy Essentials extension enables GPC by default in the browser

The New York Times has become the first major publisher to honor GPC. A number of other publishers, including The Washington Post and Automattic (WordPress.com), have committed to honoring it “this coming quarter.”

From NYT’s privacy page:

Does The Times support the Global Privacy Control (GPC)?

Yes. When we detect a GPC signal from a reader’s browser where GDPR, CCPA or a similar privacy law applies, we stop sharing the reader’s personal data online with other companies (except with our service providers).

The case for em-based media queries

Some browsers allow the user to increase the default font size in the browser’s settings. Unfortunately, this user preference has no effect on websites that set their font sizes in pixels (e.g., font-size: 20px). In part for this reason, some websites (including CSS-Tricks) instead use font-relative units, such as em and rem, which do respond to the user’s font size preference.

Ideally, a website that uses font-relative units for font-size should also use em values in media queries (e.g., min-width: 80em instead of min-width: 1280px). Otherwise, the site’s responsive layout may not always work as expected.

For example, CSS-Tricks switches from a two-column to a one-column layout on narrow viewports to prevent the article’s lines from becoming too short. However, if the user increases the default font size in the browser to 24px, the text on the page will become larger (as it should) but the page layout will not change, resulting in extremely short lines at certain viewport widths.

If you’d like to try out em-based media queries on your website, there is a PostCSS plugin that automatically converts min-width, max-width, min-height, and max-height media queries from px to em.

(via Nick Gard)

A new push to bring CSS :user-invalid to browsers

In 2017, Peter-Paul Koch published a series of three articles about native form validation on the web. Part 1 points out the problems with the widely supported CSS :invalid pseudo-class:

  • The validity of <input> elements is re-evaluated on every key stroke, so a form field can become :invalid while the user is still typing the value.
  • If a form field is required (<input required>), it will become :invalid immediately on page load.

Both of these behaviors are potentially confusing (and annoying), so websites cannot rely solely on the :invalid selector to indicate that a value entered by the user is not valid. However, there is the option to combine :invalid with :not(:focus) and even :not(:placeholder-shown) to ensure that the page’s “invalid” styles do not apply to the <input> until the user has finished entering the value and moved focus to another element.

The CSS Selectors module defines a :user-invalid pseudo-class that avoids the problems of :invalid by only matching an <input> “after the user has significantly interacted with it.”

Firefox already supports this functionality via the :-moz-ui-invalid pseudo-class (see it in action). Mozilla now intends to un-prefix this pseudo-class and ship it under the standard :user-invalid name. There are still no signals from other browser vendors, but the Chromium and WebKit bugs for this feature have been filed.


Weekly Platform News: Focus Rings, Donut Scope, More em Units, and Global Privacy Control originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/weekly-platform-news-focus-rings-donut-scope-ditching-em-units-and-global-privacy-control/feed/ 3 335856
Weekly Platform News: Reduced Motion, CORS, WhiteHouse.gov, popups, and 100vw https://css-tricks.com/weekly-platform-news-reduced-motion-cors-whitehouse-gov-popups-and-100vw/ https://css-tricks.com/weekly-platform-news-reduced-motion-cors-whitehouse-gov-popups-and-100vw/#comments Fri, 26 Feb 2021 17:00:26 +0000 https://css-tricks.com/?p=335485 In this week’s roundup, we highlight a proposal for a new <popup> element, check the use of prefers-reduced-motion on award-winning sites, learn how to opt into cross-origin isolation, see how WhiteHouse.gov approaches accessibility, and warn the dangers of 100vh.…


Weekly Platform News: Reduced Motion, CORS, WhiteHouse.gov, popups, and 100vw originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
In this week’s roundup, we highlight a proposal for a new <popup> element, check the use of prefers-reduced-motion on award-winning sites, learn how to opt into cross-origin isolation, see how WhiteHouse.gov approaches accessibility, and warn the dangers of 100vh.

Let’s get into the news!

The new HTML <popup> element is in development

On January 21, Melanie Richards from the Microsoft Edge web platform team posted an explainer for a proposed HTML <popup> element (the name is not final). A few hours later, Mason Freed from Google announced an intent to prototype this element in the Blink browser engine. Work on the implementation is taking place in Chromium issue #1168738.

A popup is a temporary (transient) and “light-dismissable” UI element that is displayed on the the “top layer” of all other elements. The goal for the <popup> element is to be fully stylable and accessible by default. A <popup> can be anchored to an activating element, such as a button, but it can also be a standalone element that is displayed on page load (e.g., a teaching UI).

Two use cases showing a white action menu with four gray menu links below a blue menu button, and another example of a blog button with a large dark blue tooltip beneath it with two paragraphs of text in white.

A <popup> is automatically hidden when the user presses the Esc key or moves focus to a different element (this is called a light dismissal). Unlike the <dialog> element, only one <popup> can be shown at a time, and unlike the deprecated <menu> element, a <popup> can contain arbitrary content, including interactive elements:

We imagine <popup> as being useful for various different types of popover UI. We’ve chosen to use an action menu as a primary example, but folks use popup-esque patterns for many different types of content.

Award-winning websites should honor the “reduce motion” preference

Earlier this week, AWWWARDS announced the winners of their annual awards for the best websites of 2020. The following websites were awarded:

All these websites are highly dynamic and show full-screen motion on load and during scroll. Unfortunately, such animations can cause dizziness and nausea in people with vestibular disorders. Websites are therefore advised to reduce or turn off non-essential animations via the prefers-reduced-motion media query, which evaluates to true for people who have expressed their preference for reduced motion (e.g., the “Reduce motion” option on Apple’s platforms). None of the winning websites do this.

/* (code from animal-crossing.com) */
@media (prefers-reduced-motion: reduce) {
  .main-header__scene {
    animation: none;
  }
}

An example of a website that does this correctly is the official site of last year’s Animal Crossing game. Not only does the website honor the user’s preference via prefers-reduced-motion, but it also provides its own “Reduce motion” toggle button at the very top of the page.

Screenshot of the animal crossing game website that is bright with a solid green header above a gold ribbon that displays menu items. Below is the main banner showing a still of the animated game with a wooden welcome to Animal Crossing sign in the foreground.

(via Eric Bailey)

Websites can now opt into cross-origin isolation

Cross-origin isolation is part of a “long-term security improvement.” Websites can opt into cross-origin isolation by adding the following two HTTP response headers, which are already supported in Chrome and Firefox:

Cross-Origin-Embedder-Policy: require-corp
Cross-Origin-Opener-Policy: same-origin

A cross-origin-isolated page relinquishes its ability to load content from other origins without their explicit opt-in (via CORS headers), and in return, the page gains access to some powerful APIs, such as SharedArrayBuffer.

if (crossOriginIsolated) {
  // post SharedArrayBuffer
} else {
  // do something else
}

The White House recommits to accessibility

The new WhiteHouse.gov website of the Biden administration was built from scratch in just six weeks with accessibility as a top priority (“accessibility was top of mind”). Microsoft’s chief accessibility officer reviewed the site and gave it the thumbs up.

The website’s accessibility statement (linked from the site’s footer) declares a “commitment to accessibility” and directly references the latest version of the Web Content Accessibility Guidelines, WCAG 2.1 (2018). This is notable because federal agencies in the USA are only required to comply with WCAG 2.0 (2008).

The Web Content Accessibility Guidelines are the most widely accepted standards for internet accessibility. … By referencing WCAG 2.1 (the latest version of the guidelines), the Biden administration may be indicating a broader acceptance of the WCAG model.

The CSS 100vw value can cause a useless horizontal scrollbar

On Windows, when a web page has a vertical scrollbar, that scrollbar consumes space and reduces the width of the page’s <html> element; this is called a classic scrollbar. The same is not the case on macOS, which uses overlay scrollbars instead of classic scrollbars; a vertical overlay scrollbar does not affect the width of the <html> element.

macOS users can switch from overlay scrollbars to classic scrollbars by setting “Show scroll bars” to ”Always” in System preferences > General.

The CSS length value 100vw is equal to the width of the <html> element. However, if a classic vertical scrollbar is added to the page, the <html> element becomes narrower (as explained above), but 100vw stays the same. In other words, 100vw is wider than the page when a classic vertical scrollbar is present.

This can be a problem for web developers on macOS who use 100vw but are unaware of its peculiarity. For example, a website might set width: 100vw on its article header to make it full-width, but this will cause a useless horizontal scrollbar on Windows that some of the site’s visitors may find annoying.

Screenshot of an article on a white background with a large black post title, post date and red tag links above a paragraph of black text. A scrollbar is displayed on the right with two large red arrows illustrating the page width, which is larger than the 100 viewport width unit.

Web developers on macOS can switch to classic scrollbars to make sure that overflow bugs caused by 100vw don’t slip under their radar. In the meantime, I have asked the CSS Working Group for comment.


Weekly Platform News: Reduced Motion, CORS, WhiteHouse.gov, popups, and 100vw originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/weekly-platform-news-reduced-motion-cors-whitehouse-gov-popups-and-100vw/feed/ 3 335485
Weekly Platform News: WebKit autofill, Using Cursor Pointer, Delaying Autoplay Videos https://css-tricks.com/weekly-platform-news-webkit-autofill-using-cursor-pointer-delaying-autoplay-videos/ https://css-tricks.com/weekly-platform-news-webkit-autofill-using-cursor-pointer-delaying-autoplay-videos/#respond Fri, 12 Feb 2021 21:53:33 +0000 https://css-tricks.com/?p=334360 In this week’s roundup, WebKit’s prefixed autofill becomes a standard, the pointer cursor is for more than just links, and browsers are jumping on board to delay videos set to autoplay until they’re in view… plus more! Let’s jump right …


Weekly Platform News: WebKit autofill, Using Cursor Pointer, Delaying Autoplay Videos originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
In this week’s roundup, WebKit’s prefixed autofill becomes a standard, the pointer cursor is for more than just links, and browsers are jumping on board to delay videos set to autoplay until they’re in view… plus more! Let’s jump right into it.

CSS ::-webkit-autofill has become a standard feature

Chrome, Safari, and pretty much every other modern web browser except Firefox (more on that later) have supported the CSS :-webkit-autofill pseudo-class for many years. This selector matches form fields that have been autofilled by the browser. Websites can use this feature to style autofilled fields in CSS (with some limitations) and detect such fields in JavaScript.

let autofilled = document.querySelectorAll(":-webkit-autofill");

There currently does not exist a standard autocomplete or autofill event that would fire when the browser autofills a form field, but you can listen to the input event on the web form and then check if any of its fields match the :-webkit-autofill selector.

The HTML Standard has now standardized this feature by adding :autofill (and :-webkit-autofill as an alias) to the list of pseudo-classes that match HTML elements. This pseudo-class will also be added to the CSS Selectors module.

The :autofill and :-webkit-autofill pseudo-classes must match <input> elements that have been autofilled by the user agent. These pseudo-classes must stop matching if the user edits the autofilled field.

Following standardization, both pseudo-classes have been implemented in Firefox and are expected to ship in Firefox 86 later this month.

In the article “Let’s Bring Spacer GIFs Back!” Josh W. Comeau argues for using a “spacer” <span> element instead of a simple CSS margin to define the spacing between the icon and text of a button component.

In our home-button example, should the margin go on the back-arrow, or the text? It doesn’t feel to me like either element should “own” the space. It’s a distinct layout concern.

CSS Grid is an alternative to such spacer elements. For example, the “Link to issue” link in CSS-Tricks’s newsletter section contains two non-breaking spaces (&nbsp;) to increase the spacing between the emoji character and text, but the link could instead be turned into a simple grid layout to gain finer control over the spacing via the gap property.

The CSS Basic User Interface module defines the CSS cursor property, which allows websites to change the type of cursor that is displayed when the user hovers specific elements. The specification has the following to say about the property’s pointer value:

The cursor is a pointer that indicates a link. … User agents must apply cursor: pointer to hyperlinks. … Authors should use pointer on links and may use on other interactive elements.

Accordingly, browsers display the pointer cursor (rendered as a hand) on links and the default cursor (rendered as an arrow) on buttons. However, most websites (including Wikipedia) don’t agree with this default style and apply cursor: pointer to other interactive elements, such as buttons and checkboxes, as well.

Another interactive element for which it makes sense to use the pointer cursor is the <summary> element (the “toggle button” for opening and closing the parent <details> element).

Browsers delay autoplay until the video comes into view

Compared to modern video formats, animated GIF images are up to “twice as expensive in energy use.” For that reason, browsers have relaxed their video autoplay policies (some time ago) to encourage websites to switch from GIFs to silent or muted videos.

<!-- a basic re-implementation of a GIF using <video> -->
<video autoplay loop muted playsinline src="meme.mp4"></video>

If you’re using <video muted autoplay>, don’t worry about pausing such videos when they’re no longer visible in the viewport (e.g., using an Intersection Observer). All major browsers (except Firefox) already perform this optimization by default:

<video autoplay> elements will only begin playing when visible on-screen such as when they are scrolled into the viewport, made visible through CSS, and inserted into the DOM.

(via Zach Leatherman)

Chrome introduces three new @font-face descriptors

Different browsers and operating systems sometimes use different font metrics even when rendering the same font. These differences affect the vertical position of text, which is especially noticeable on large headings.

Similarly, the different font metrics of a web font and its fallback font can cause a layout shift when the fonts are swapped during page load.

To help websites avoid layout shift and create interoperable text layouts, Chrome recently added the following three new CSS @font-face descriptors for overriding the font’s default metrics:

  • ascent-override (ascent is the height above the baseline)
  • descent-override (descent is the depth below the baseline)
  • line-gap-override
@font-face {
  font-family: Roboto;
  /* Merriweather Sans has 125.875px ascent 
   * and 35px descent at 128px font size.
   */
  ascent-override: calc(125.875 / 128 * 100%);
  descent-override: calc(35 / 128 * 100%);
  src: local(Roboto-Regular);
}

The following video shows how overriding the ascent and descent metrics of the fallback font (Roboto) to match the same metrics of the web font (Merriweather Sans) can avoid layout shift when swapping between these two fonts.


Weekly Platform News: WebKit autofill, Using Cursor Pointer, Delaying Autoplay Videos originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/weekly-platform-news-webkit-autofill-using-cursor-pointer-delaying-autoplay-videos/feed/ 0 334360
Weekly Platform News: The :not() pseudo-class, Video Media Queries, clip-path: path() Support https://css-tricks.com/weekly-platform-news-the-not-pseudo-class-video-media-queries-clip-path-path-support/ https://css-tricks.com/weekly-platform-news-the-not-pseudo-class-video-media-queries-clip-path-path-support/#comments Fri, 05 Feb 2021 21:02:30 +0000 https://css-tricks.com/?p=333984 Hey, we’re back with weekly updates about the browser landscape from Šime Vidas.

In this week’s update, the CSS :not pseudo class can accept complex selectors, how to disable smooth scrolling when using “Find on page…” in Chrome, Safari’s …


Weekly Platform News: The :not() pseudo-class, Video Media Queries, clip-path: path() Support originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
Hey, we’re back with weekly updates about the browser landscape from Šime Vidas.

In this week’s update, the CSS :not pseudo class can accept complex selectors, how to disable smooth scrolling when using “Find on page…” in Chrome, Safari’s support for there media attribute on <video> elements, and the long-awaited debut of the path() function for the CSS clip-path property.

Let’s jump into the news…

The enhanced :not() pseudo-class enables new kinds of powerful selectors

After a years-long wait, the enhanced :not() pseudo-class has finally shipped in Chrome and Firefox, and is now supported in all major browser engines. This new version of :not() accepts complex selectors and even entire selector lists.

For example, you can now select all <p> elements that are not contained within an <article> element.

/* select all <p>s that are descendants of <article> */
article p {
}

/* NEW! */
/* select all <p>s that are not descendants of <article> */
p:not(article *) {
}

In another example, you may want to select the first list item that does not have the hidden attribute (or any other attribute, for that matter). The best selector for this task would be :nth-child(1 of :not([hidden])), but the of notation is still only supported in Safari. Luckily, this unsupported selector can now be re-written using only the enhanced :not() pseudo-class.

/* select all non-hidden elements that are not preceded by a non-hidden sibling (i.e., select the first non-hidden child */
:not([hidden]):not(:not([hidden]) ~ :not([hidden])) {
}

The HTTP Refresh header can be an accessibility issue

The HTTP Refresh header (and equivalent HTML <meta> tag) is a very old and widely supported non-standard feature that instructs the browser to automatically and periodically reload the page after a given amount of time.

<!-- refresh page after 60 seconds -->
<meta http-equiv="refresh" content="60">

According to Google’s data, the <meta http-equiv="refresh"> tag is used by a whopping 2.8% of page loads in Chrome (down from 4% a year ago). All these websites risk failing several success criteria of the Web Content Accessibility Guidelines (WCAG):

If the time interval is too short, and there is no way to turn auto-refresh off, people who are blind will not have enough time to make their screen readers read the page before the page refreshes unexpectedly and causes the screen reader to begin reading at the top.

However, WCAG does allow using the <meta http-equiv="refresh"> tag specifically with the value 0 to perform a client-side redirect in the case that the author does not control the server and hence cannot perform a proper HTTP redirect.

(via Stefan Judis)

How to disable smooth scrolling for the “Find on page…” feature in Chrome

CSS scroll-behavior: smooth is supported in Chrome and Firefox. When this declaration is set on the <html> element, the browser scrolls the page “in a smooth fashion.” This applies to navigations, the standard scrolling APIs (e.g., window.scrollTo({ top: 0 })), and scroll snapping operations (CSS Scroll Snap).

Unfortunately, Chrome erroneously keeps smooth scrolling enabled even when the user performs a text search on the page (“Find on page…” feature). Some people find this annoying. Until that is fixed, you can use Christian Schaefer’s clever CSS workaround that effectively disables smooth scrolling for the “Find on page…” feature only.

@keyframes smoothscroll1 {
  from,
  to {
    scroll-behavior: smooth;
  }
}

@keyframes smoothscroll2 {
  from,
  to {
    scroll-behavior: smooth;
  }
}

html {
  animation: smoothscroll1 1s;
}

html:focus-within {
  animation-name: smoothscroll2;
  scroll-behavior: smooth;
}

In the following demo, notice how clicking the links scrolls the page smoothly while searching for the words “top” and “bottom” scrolls the page instantly.

Safari still supports the media attribute on video sources

With the HTML <video> element, it is possible to declare multiple video sources of different MIME types and encodings. This allows websites to use more modern and efficient video formats in supporting browsers, while providing a fallback for other browsers.

<video>
  <source src="/flower.webm" type="video/webm">
  <source src="/flower.mp4" type="video/mp4">
</video>

In the past, browsers also supported the media attribute on video sources. For example, a web page could load a higher-resolution video if the user’s viewport exceeded a certain size.

<video>
  <source media="(min-width: 1200px)" src="/large.mp4" type="video/mp4">
  <source src="/small.mp4" type="video/mp4">
</video>

The above syntax is in fact still supported in Safari today, but it was removed from other browsers around 2014 because it was not considered a good feature:

It is not appropriate for choosing between low resolution and high resolution because the environment can change (e.g., the user might fullscreen the video after it has begun loading and want high resolution). Also, bandwidth is not available in media queries, but even if it was, the user agent is in a better position to determine what is appropriate than the author.

Scott Jehl (Filament Group) argues that the removal of this feature was a mistake and that websites should be able to deliver responsive video sources using <video> alone.

For every video we embed in HTML, we’re stuck with the choice of serving source files that are potentially too large or small for many users’ devices … or resorting to more complicated server-side or scripted or third-party solutions to deliver a correct size.

Scott has written a proposal for the reintroduction of media in video <source> elements and is welcoming feedback.

The CSS clip-path: path() function ships in Chrome

It wasn’t mentioned in the latest “New in Chrome 88” article, but Chrome just shipped the path() function for the CSS clip-path property, which means that this feature is now supported in all three major browser engines (Safari, Firefox, and Chrome).

The path() function is defined in the CSS Shapes module, and it accepts an SVG path string. Chris calls this the ultimate syntax for the clip-path property because it can clip an element with “literally any shape.” For example, here’s a photo clipped with a heart shape:


Weekly Platform News: The :not() pseudo-class, Video Media Queries, clip-path: path() Support originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/weekly-platform-news-the-not-pseudo-class-video-media-queries-clip-path-path-support/feed/ 6 333984
Weekly Platform News: Strict Tracking Protection, Dark Web Pages, Periodic Background Sync https://css-tricks.com/weekly-platform-news-strict-tracking-protection-dark-web-pages-periodic-background-sync/ https://css-tricks.com/weekly-platform-news-strict-tracking-protection-dark-web-pages-periodic-background-sync/#comments Thu, 12 Dec 2019 21:41:42 +0000 https://css-tricks.com/?p=300225 In this week’s news: Firefox gets strict, Opera goes to the dark side, and Chrome plans to let web apps run in the background.

Let’s get into the news.

Firefox for Android will block tracking content

Mozilla has announced that …


Weekly Platform News: Strict Tracking Protection, Dark Web Pages, Periodic Background Sync originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
In this week’s news: Firefox gets strict, Opera goes to the dark side, and Chrome plans to let web apps run in the background.

Let’s get into the news.

Firefox for Android will block tracking content

Mozilla has announced that the upcoming revamped Firefox for Android (currently available in a test version under the name “Firefox Preview”) will include strict tracking protection by default.

On the phone or tablet, most users care much more about performance and blocking of annoyances compared to desktop. Users are more forgiving when a site doesn’t load exactly like it’s meant to. So we decided that while Firefox for desktop’s default mode is “Standard,” Firefox Preview will use “Strict” mode.

Strict tracking protection additionally blocks “tracking content”: ads, videos, and other content with tracking code.

(via Mozilla)

Opera adds option that renders all websites in dark mode

Opera for Android has added a “Dark web pages” option that renders all websites in dark mode. If a website does not provide dark mode styles (via the CSS prefers-color-scheme media feature), Opera applies its own “clever CSS changes” to render the site in dark mode regardless.

(via Stefan Stjernelund)

Periodic Background Sync is coming to Chrome

Google intends to ship Periodic Background Sync in the next version of Chrome (early next year). This feature will enable installed web apps to run background tasks at periodic intervals with network connectivity.

Chrome’s implementation restricts the API to installed web apps. Chrome grants the permission on behalf of the user for any installed web app. The API is not available outside of installed PWAs.

Apple and Mozilla are currently opposed to this API. At Mozilla, there are opinions that the feature is “harmful in its current state,” while Apple states multiple privacy and security risks.

(via Mugdha Lakhani)

More news…

Read more news in my weekly newsletter for web developers. Pledge as little as $2 per month to get the latest news from me via email every Monday.

More News →


Weekly Platform News: Strict Tracking Protection, Dark Web Pages, Periodic Background Sync originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/weekly-platform-news-strict-tracking-protection-dark-web-pages-periodic-background-sync/feed/ 2 300225