Daniel Schwarz – CSS-Tricks https://css-tricks.com Tips, Tricks, and Techniques on using Cascading Style Sheets. Wed, 25 Jan 2023 16:05:07 +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 Daniel Schwarz – CSS-Tricks https://css-tricks.com 32 32 45537868 Animating CSS Grid (How To + Examples) https://css-tricks.com/animating-css-grid-how-to-examples/ https://css-tricks.com/animating-css-grid-how-to-examples/#comments Wed, 25 Jan 2023 16:05:04 +0000 https://css-tricks.com/?p=376528 I’m pleased to shine a light on the fact that the CSS grid-template-rows and grid-template-columns properties are now animatable in all major web browsers! Well, CSS Grid has technically supported animations for a long time, as it’s baked right


Animating CSS Grid (How To + Examples) originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
I’m pleased to shine a light on the fact that the CSS grid-template-rows and grid-template-columns properties are now animatable in all major web browsers! Well, CSS Grid has technically supported animations for a long time, as it’s baked right into the CSS Grid Layout Module Level 1 spec.

But animating these grid properties only recently gained supported by all three major browsers. Shall we take a look at a few examples to get the creative juices flowing?

Example 1: Expanding sidebar

First of all, this is what we’re talking about:

A simple two-column grid. Now, before, you might not have built this using CSS Grid because animations and transitions weren’t supported, but what if you wanted the left column — perhaps a sidebar navigation — to expand on hover? Well, now that’s possible.

I know what you’re thinking: “Animating a CSS property? Easy peasy, I’ve been doing it for years!” Me too. However, I ran into an interesting snag while experimenting with a particular use case.

So, we want to transition the grid itself (specifically grid-template-columns, which is set on the .grid class in the example). But the left column (.left) is the selector that requires the :hover pseudo-class. While JavaScript can solve this conundrum easily — thanks, but no thanks — we can accomplish it with CSS alone.

Let’s walk through the whole thing, starting with the HTML. Pretty standard stuff really… a grid with two columns.

<div class="grid">
  <div class="left"></div>
  <div class="right"></div>
</div>

Putting the cosmetic CSS aside, you’ll first need to set display: grid on the parent container (.grid).

.grid {
  display: grid;
}

Next, we can define and size the two columns using the grid-template-columns property. We’ll make the left column super narrow, and later increase its width on hover. The right column takes up the rest of the remaining space, thanks to the auto keyword.

.grid {
  display: grid;
  grid-template-columns: 48px auto;
}

We know we’re going to animate this thing, so let’s go ahead and throw a transition in there while we’re at it so the change between states is smooth and noticeable.

.grid {
  display: grid;
  grid-template-columns: 48px auto;
  transition: 300ms; /* Change as needed */
}

That’s it for the .grid! All that’s left is to apply the hover state. Specifically, we’re going to override the grid-template-columns property so that the left column takes up a greater amount of space on hover.

This alone isn’t all that interesting, although it’s awesome that animations and transitions are supported now in CSS Grid. What’s more interesting is that we can use the relatively new :has() pseudo-class to style the parent container (.grid) while the child (.left) is hovered.

.grid:has(.left:hover) {
  /* Hover styles */
}

In plain English this is saying, “Do something to the .grid container if it contains an element named .left inside of it that is in a hover state.” That’s why :has() is often referred to as a “parent” selector. We can finally select a parent based on the children it contains — no JavaScript required!

So, let’s increase the width of the .left column to 30% when it is hovered. The .right column will continue to take up all the leftover space:

.grid {
  display: grid;
  transition: 300ms;
  grid-template-columns: 48px auto;
}

.grid:has(.left:hover) {
  grid-template-columns: 30% auto;
}

We could use CSS variables as well, which may or may not look cleaner depending on your personal preferences (or you might be using CSS variables in your project anyway):

.grid {
  display: grid;
  transition: 300ms;
  grid-template-columns: var(--left, 48px) auto;
}

.grid:has(.left:hover) {
  --left: 30%;
}

I love that CSS grids can be animated now, but the fact that we can build this particular example with just nine lines of CSS is even more astounding.

Here’s another example by Olivia Ng — similar concept, but with content (click on the nav icon):

Example 2: Expanding Panels

This example transitions the grid container (the column widths) but also the individual columns (their background colors). It’s ideal for providing more content on hover.

It’s worth remembering that the repeat() function sometimes produces buggy transitions, which is why I set the width of each column individually (i.e. grid-template-columns: 1fr 1fr 1fr).

Example 3: Adding Rows and Columns

This example animatedly “adds” a column to the grid. However — you guessed it — this scenario has a pitfall too. The requirement is that the “new” column mustn’t be hidden (i.e. set to display: none), and CSS Grid must acknowledge its existence while setting its width to 0fr.

So, for a three-column grid — grid-template-columns: 1fr 1fr 0fr (yes, the unit must be declared even though the value is 0!) transitions into grid-template-columns: 1fr 1fr 1fr correctly, but grid-template-columns: 1fr 1fr doesn’t. In hindsight, this actually makes perfect sense considering what we know about how transitions work.

Here’s another example by Michelle Barker — same concept, but with an extra column and lot more pizzazz. Make sure to run this one in full-screen mode because it’s actually responsive (no trickery, just good design!).

A few more examples

Because why not?

This “Animated Mondrian” is the original proof of concept for animated CSS grids by Chrome DevRel. The grid-row‘s and grid-column‘s utilize the span keyword to create the layout you see before you, and then the grid-template-row’s and grid-template-column‘s are animated using a CSS animation. It’s nowhere near as complex as it looks!

Same concept, but with more of that Michelle Barker pizzazz. Could make a nice loading spinner?

Wrapping up with a bit of nostalgia (showing my age here), the not-very-griddy animated CSS grid by Andrew Harvard. Again — same concept — it’s just that you can’t see the other grid items. But don’t worry, they’re there.


Animating CSS Grid (How To + Examples) originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/animating-css-grid-how-to-examples/feed/ 15 376528
Newer Things to Know About Good Ol’ HTML Lists https://css-tricks.com/newer-things-to-know-about-good-ol-html-lists/ https://css-tricks.com/newer-things-to-know-about-good-ol-html-lists/#comments Mon, 28 Nov 2022 14:05:11 +0000 https://css-tricks.com/?p=375273 HTML lists are boring. They don’t do much, so we don’t really think about them despite how widely used they are. And we’re still able to do the same things we’ve always done to customize them, like removing markers, reversing …


Newer Things to Know About Good Ol’ HTML Lists originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
HTML lists are boring. They don’t do much, so we don’t really think about them despite how widely used they are. And we’re still able to do the same things we’ve always done to customize them, like removing markers, reversing order, and making custom counters.

There are, however, a few “newer” things — including dangers — to know when using lists. The dangers are mostly minor, but way more common than you might think. We’ll get to those, plus some new stuff we can do with lists, and even new ways to approach old solutions.

To clarify, these are the HTML elements we’re talking about:

  • Ordered lists <ol>
  • Unordered lists <ul>
  • Description lists <dl>
  • Interactive lists <menu>

Ordered lists, unordered lists, and interactive lists contain list items (<li>) which are displayed according to what kind of list we’re dealing with. An ordered list (<ol>) displays numbers next to list items. Unordered lists (<ul>) and menu elements (<menu>) displays bullet points next to list items. We call these “list markers” and they can even be styled using the ::marker pseudo-element. Description lists use description terms (<dt>) and description details (<dd>) instead of <li> and don’t have list markers. They‘re supposed to be used to display metadata and glossaries, but I can’t say I’ve ever seen them in the wild.

Let’s start off with the easy stuff — how to correctly (at least in my opinion) reset list styles. After that, we’ll take a look at a couple of accessibility issues before shining a light on the elusive <menu> element, which you may be surprised to learn… is actually a type of list, too!

Resetting list styles

Browsers automatically apply their own User Agent styles to help with the visual structure of lists right out of the box. That can be great! But if we want to start with a blank slate free of styling opinions, then we have to reset those styles first.

For example, we can remove the markers next to list items pretty easily. Nothing new here:

/* Zap all list markers! */
ol, ul, menu {
  list-style: none;
}

But modern CSS has new ways to help us target specific list instances. Let’s say we want to clear markers from all lists, except if those lists appear in long-form content, like an article. If we combine the powers of newer CSS pseudo-class functions :where() and :not(), we can isolate those instances and allow the markers in those cases:

/* Where there are lists that are not articles where there are lists... */
:where(ol, ul, menu):not(article :where(ol, ul, menu)) {
  list-style: none;
}

Why use :where() instead of :is()? The specificity of :where() is always zero, whereas :is() takes the specificity of the most specific element in its list of selectors. So, using :where() is a less forceful way of overriding things and can be easily overridden itself.

UA styles also apply padding to space a list item’s content from its marker. Again, that’s a pretty nice affordance right out of the box in some cases, but if we’re already removing the list markers like we did above, then we may as well wipe out that padding too. This is another case for :where():

:where(ol, ul, menu) {
  padding-left: 0; /* or padding-inline-start */
}

OK, that’s going to prevent marker-less list items from appearing to float in space. But we sort of tossed out the baby with the bathwater and removed the padding in all instances, including the ones we previously isolated in an <article>. So, now those lists with markers sorta hang off the edge of the content box.

Notice that UA styles apply an extra 40px to the <menu> element.

So what we want to do is prevent the list markers from “hanging” outside the container. We can fix that with the list-style-position property:

Or not… maybe it comes down to stylistic preference?

Newer accessibility concerns with lists

Unfortunately, there are a couple of accessibility concerns when it comes to lists — even in these more modern times. One concern is a result of applying list-style: none; as we did when resetting UA styles.

In a nutshell, Safari does not read ordered and unordered lists styled with list-style: none as actual lists, like when navigating content with a screen reader. In other words, removing the markers also removes the list’s semantic meaning. The fix for this fix it to apply an ARIA list role on the list and a listitem role to the list items so screen readers will pick them up:

<ol style="list-style: none;" role="list">
  <li role="listItem">...</li>
  <li role="listItem">...</li>
  <li role="listItem">...</li>
</ol>

<ul style="list-style: none;" role="list">
  <li role="listItem">...</li>
  <li role="listItem">...</li>
  <li role="listItem">...</li>
</ul>

Oddly, Safari considers this to be a feature rather than a bug. Basically, users would report that screen readers were announcing too many lists (because developers tend to overuse them), so now, only those with role="list" are announced by screen readers, which actually isn’t that odd after all. Scott O’Hara has a detailed rundown of how it all went down.

A second accessibility concern isn’t one of our own making (hooray!). So, you know how you’re supposed to add an aria-label to <section> elements without headings? Well, it sometimes makes sense to do the same with a list that doesn’t contain a heading element that helps describe the list.

<!-- This list is somewhat described by the heading -->
<section>
  <h2>Grocery list</h2>
  <ol role="list">
     <!-- ... -->
  </ol>
</section>

<!-- This list is described by the aria-label -->
<ol role="list" aria-label="Grocery list">
  <!-- ... -->
</ol>

You absolutely don’t have to use either method. Using a heading or an ARIA label is just added context, not a requirement — be sure to test your websites with screen readers and do what offers the best user experience for the situation.

In somewhat related news, Eric Bailey wrote up an excellent piece on why and how he considers aria-label to be a code smell.

Wait, <menu> is a list, too?

OK, so, you’re likely wondering about all of the <menu> elements that I’ve been slipping into the code examples. It’s actually super simple; menus are unordered lists except that they’re meant for interactive items. They’re even exposed to the accessibility tree as unordered lists.

In the early days of the semantic web, I mistakenly believed that menus were like <nav>s before believing that they were for context menus (or “toolbars” as the spec says) because that’s what early versions of the HTML spec said. (MDN has an interesting write-up on all of the deprecated stuff related to <menu> if you’re at all interested.)

Today, however, this is the semantic way to use menus:

<menu aria-label="Share article">
  <li><button>Email</button></li>
  <li><button>Twitter</button></li>
  <li><button>Facebook</button></li>
</menu>

Personally, I think there are some good use-cases for <menu>. That last example shows a list of social sharing buttons wrapped up in a labeled <menu> element, the notable aspect being that the “Share article” label contributes a significant amount of context that helps describe what the buttons do.

Are menus absolutely necessary? No. Are they HTML landmarks? Definitely not. But they’re there if you enjoy fewer <div>s and you feel like the component could use an aria-label for additional context.

Anything else?

Yes, there’s also the aforementioned <dl> (description list) element, however, MDN doesn’t seem to consider them lists in the same way — it’s a list of groups containing terms — and I can’t say that I’ve really seen them in use. According to MDN, they’re supposed to be used for metadata, glossaries, and other types of key-value pairs. I would just avoid them on the grounds that all screen readers announce them differently.

But let’s not end things on a negative note. Here’s a list of super cool things you can do with lists:


Newer Things to Know About Good Ol’ HTML Lists originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/newer-things-to-know-about-good-ol-html-lists/feed/ 18 375273
When is it OK to Disable Text Selection? https://css-tricks.com/when-is-it-ok-to-disable-text-selection/ https://css-tricks.com/when-is-it-ok-to-disable-text-selection/#comments Wed, 14 Sep 2022 13:03:04 +0000 https://css-tricks.com/?p=373100 Using CSS, it’s possible to prevent users from selecting text within an element using user-select: none. Now, it’s understandable why doing so might be considered “controversial”. I mean, should we be disabling standard user behaviors? Generally speaking, no, we


When is it OK to Disable Text Selection? originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
Using CSS, it’s possible to prevent users from selecting text within an element using user-select: none. Now, it’s understandable why doing so might be considered “controversial”. I mean, should we be disabling standard user behaviors? Generally speaking, no, we shouldn’t be doing that. But does disabling text selection have some legitimate (albeit rare) use-cases? I think so.

In this article we’ll explore these use cases and take a look at how we can use user-select: none to improve (not hinder) user experiences. It’s also worth nothing that the user-select property has other values besides none that can be used to alter the behavior of text selection rather than disable it completely, and another value that even enforces text selection, so we’ll also take a look at those.

Possible user-select values

Let’s kick things off by running through the different user-select values and what they do.

Applying user-select: none; to an element means that its text content and nested text content won’t be functionally selectable or visually selectable (i.e. ::selection won’t work). If you were to make a selection that contained some non-selectable content, the non-selectable content would be omitted from the selection, so it’s fairly well implemented. And the support is great.

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

Desktop

ChromeFirefoxIEEdgeSafari
4*2*10*12*3.1*

Mobile / Tablet

Android ChromeAndroid FirefoxAndroidiOS Safari
1151152.1*3.2*

Conversely, user-select: text makes the content selectable. You’d use this value to overwrite user-select: none.

user-select: contain is an interesting one. Applying it means that if a selection begins within the element then it must end within it too, containing it. This oddly doesn’t apply when the selection begins before the element, however, which is probably why no browser currently supports it. (Internet Explorer and earlier versions of Microsoft Edge previously supported it under the guise of user-select: element.)

With user-select: all, selecting part of the element’s content results in all of it being selected automatically. It’s all or nothing, which is very uncompromising but useful in circumstances where users are more likely to copy content to their clipboard (e.g. sharing and embedding links, code snippets, etc.). Instead of double-clicking, users will only need to click once for the content to auto-select.

Be careful, though, since this isn’t always the feature you think it is. What if users only want to select part of the content (e.g. only the font name part of a Google Fonts snippet or one part of a code snippet)? It’s still better to handle ”copy to clipboard” using JavaScript in many scenarios.

A better application of user-select: all is to ensure that quotes are copied entirely and accurately.

The behavior of user-select: auto (the initial value of user-select) depends on the element and how it’s used. You can find out more about this in our almanac.

Now let’s turn to exploring use cases for user-select: none

Stripping non-text from the selection

When you’re copying content from a web page, it’s probably from an article or some other type of long-form content, right? You probably don’t want your selection to include images, emoji (which can sometimes copy as text, e.g. “:thinkingface:”), and other things that you might expect to find wrapped in an <aside> element (e.g. in-article calls to action, ads, or something else that’s not part of the main content).

To prevent something from being included in selections, make sure that it’s wrapped in an HTML element and then apply user-select: none to it:

<p>lorem <span style="user-select: none">🤔</span> ipsum</p>

<aside style="user-select: none">
  <h1>Heading</h1>
  <p>Paragraph</p>
  <a>Call to action</a>
</aside>

In scenarios like this, we’re not disabling selection, but rather optimizing it. It’s also worth mentioning that selecting doesn’t necessarily mean copying — many readers (including myself) like to select content as they read it so that they can remember where they are (like a bookmark), another reason to optimize rather than disable completely.

Preventing accidental selection

Apply user-select: none to links that look like buttons (e.g. <a href="/whatever" class="button">Click Me!</a>).

It’s not possible to select the text content of a <button> or <input type="submit"> because, well, why would you? However, this behavior doesn’t apply to links because traditionally they form part of a paragraph that should be selectable.

Fair enough.

We could argue that making links look like buttons is an anti-pattern, but whatever. It’s not breaking the internet, is it? That ship has sailed anyway, so if you’re using links designed to look like buttons then they should mimic the behavior of buttons, not just for consistency but to prevent users from accidentally selecting the content instead of triggering the interaction.

I’m certainly prone to selecting things accidentally since I use my laptop in bed more than I care to admit. Plus, there are several medical conditions that can affect control and coordination, turning an intended click into an unintended drag/selection, so there are accessibility concerns that can be addressed with user-select too.

Interactions that require dragging (intentionally) do exist too of course (e.g. in browser games), but these are uncommon. Still, it just shows that user-select does in fact have quite a few use-cases.

Avoiding paywalled content theft

Paywalled content gets a lot of hate, but if you feel that you need to protect your content, it’s your content — nobody has the right steal it just because they don’t believe they should pay for it.

If you do want to go down this route, there are many ways to make it more difficult for users to bypass paywalls (or similarly, copy copyrighted content such as the published work of others).

Blurring the content with CSS:

article { filter: blur(<radius>); }

Disabling the keyboard shortcuts for DevTools:

document.addEventListener("keydown", function (e) {
  if (e.keyCode == 123) e.preventDefault();
  else if ((e.ctrlKey || e.metaKey) && e.altKey && e.keyCode == 73) e.preventDefault();
  else if ((e.ctrlKey || e.metaKey) && e.altKey && e.keyCode == 74) e.preventDefault();
  else if ((e.ctrlKey || e.metaKey) && e.altKey && e.keyCode == 85) e.preventDefault();
});

Disabling access to DevTools via the context menu by disabling the context menu itself:

document.addEventListener("contextmenu", e => e.preventDefault())

And of course, to prevent users from copying the content when they’re not allowed to read it at the source, applying user-select: none:

<article style="user-select: none">

Any other use cases?

Those are the three use cases I could think of for preventing text selection. Several others crossed my mind, but they all seemed like a stretch. But what about you? Have you had to disable text selection on anything? I’d like to know!


When is it OK to Disable Text Selection? originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/when-is-it-ok-to-disable-text-selection/feed/ 25 373100
Designing for Long-Form Articles https://css-tricks.com/designing-for-long-form-articles/ https://css-tricks.com/designing-for-long-form-articles/#comments Wed, 10 Aug 2022 14:30:01 +0000 https://css-tricks.com/?p=367370 Designing a beautiful “article” is wrought with tons of considerations. Unlike, say, a homepage, a long-form article is less about designing an interface than it is designing text in a way that creates a relaxed and comfortable reading experience.

That’s …


Designing for Long-Form Articles originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
Designing a beautiful “article” is wrought with tons of considerations. Unlike, say, a homepage, a long-form article is less about designing an interface than it is designing text in a way that creates a relaxed and comfortable reading experience.

That’s because articles deal with long-form content which, in turn, tends to be valued by a ”time on page” interaction with users. We want someone to read a complete narrative. There’s a natural space between the time someone lands on an article and reads all the words. And hopefully, that space is immersive enough to not only hold a user’s, but provoke thoughts, ideas, and, possibly, actions. At least that’s what I’m hoping as I have your attention and you make your way through the very article you’re reading.

There’s a balance. On one hand, we hear that “no one reads the Internet.” On the other, a long-form article demands careful attention. Considering the current value of content marketing and the growing impatience in users, captivating readers for as long as possible should be a key concern. Let’s take a look at some best practices and examples of incredible article pages to get a better idea of what makes a visually appealing reading experience for long-form articles (without sacrificing user experience), and how we can replicate the effects.

Quick wins

Let me quickly list out what I think might already be obvious to many of you, but are effective things for content legibility:

  • Increase the font size: We know that 16px is the default and is perfectly fine in many designs, but a larger font size is inviting in that it implies the user is free to lean back and settle in without having to angle forward with the screen in their face to read.
  • Aim for characters per line: Very few people I know like to work harder than they need to, and that goes for reading too. Rather than using the full viewport width, try to narrow things down and balance that with your larger font size to get fewer characters on each line of text. Your sweet spot may vary, though many folks suggest somewhere between 45-75 characters per line to help limit how far the reader’s eye has to work to go from left to right. Chris has a bookmarklet to help count characters, but we also have the ch unit in CSS to get predictable results.
  • Bump up the line height: A default line height is going to feel smashed. It’s funny, but more space between lines (up to a point, of course) is less work for eyes, which seems antithetical to the characters-per-line advice where we generally want eyes to travel a shorter distance. A line height between 1.2 and 1.5 seems to be a pretty typical range for long-form content.

If you haven’t seen it before, Pierrick Calvez has a great “five-minute” guide to typography that packs in a bunch of low-hanging fruit like these.

Design for extra breathing room

You may be accustomed to designing “above the fold” where real estate is a prime commodity. That’s sort of like beach-front property in the web world because it’s where we’re used to packing in high-value things, like hero banners, calls to action, and anything else to help sell a thing. Above the fold can be a lot like a dense urban downtown with high traffic and high-rise buildings.

Articles are different. They allow you to stretch out a bit. If we want to take the city development analogy a little further, articles have the acreage to lean into a “less is more” sort of design approach. That’s what makes seemingly small design choices — like type — so important to the overall experience.

Check out the example below. The link underlines have a little more room to breathe (specifically, they appear below the descenders). This is actually something that you can enable sitewide but looks especially nice on article pages since it increases readability. That’s the sort of subtle design choice that contributes to extra breathing room.

A long-form article on the Taste website.

text-underline-position: under; is the line of CSS that makes this work. Naturally, text-decoration must be set to something other than none (underline in this case), too.

The example above also features text-decoration-thickness, which alters the thickness of underlines (and other line types). You can use this CSS property to match a line’s thickness to a font’s size and/or weight.

Here’s a full example:

a {
  text-decoration: underline;
  text-decoration-thickness: 2px;

  /* or */
  text-decoration: underline 2px;
  text-underline-position: under;
}

But before you reach for the text-decoration shorthand, Šime Vidas has a few “gotchas” when it comes to using it that are worth reviewing.

Leading into the content

Drop caps are stylized letters that can be placed at the beginning of a document or document section. They were once used in Latin texts, but today they’re mostly used for decorative reasons.

Personally, I think that drop caps hinder readability. However, they can be a nice way to “lead” a reader into the main content, and they shouldn’t introduce any serious accessibility issues as long as you’re using the ::first-letter pseudo-element. There are other (older) methods that involve more HTML and CSS as well as the use of ARIA attributes in order for the content to remain accessible.

Using ::first-letter, the CSS would look something like this:

/* select the first letter of the first paragraph */
article > p:first-child::first-letter {
  color: #903;
  float: left;
  font-family: Georgia;
  font-size: 75px;
  line-height: 60px;
  padding-top: 4px;
  padding-right: 8px;
  padding-left: 3px;
}

It sure would be nice if we could use the initial-letter property, but there’s pretty much no support for it at the time I’m writing this. If we had it, all that math for font size and line height would be calculated for us!

CodePen challenged folks to show off their drop-cap-styling skills several years ago and you can see a whole bunch of neat examples from it in this collection.

Skip to main content

Screen readers allow users to skip to the main content as long as it wraps it within a <main> element. However, those who navigate websites by tabbing don’t benefit from this. Instead, we must create a “skip to main content” anchor link. This link is customarily hidden but revealed once the user makes their first tab (i.e. show on focus).

It would look something like this:

<!-- anchor -->
<a id="skip-link" href="#main">Skip to main content</a>

<!-- target -->
<main class="main">
  <!-- main content -->
</main>
#skip-link {
  position: absolute; /* remove it from the flow */
  transform: translateX(-100%); /* move it off-screen so that it appears hidden but remains focusable */
}
#skip-link:focus {
  position: unset; /* insert it back into the flow */
  transform: unset; /* move it back onto the screen */
}

.main {
  scroll-margin: 1rem; /* adds breathing room above the scroll target */
}

There are other ways to go about it, of course. Here are a couple of deeper dives on creating skip links.

Seamless visuals

I love the illustrations in this article. Despite how incredible they look, they don’t demand too much cognitive attention. They introduce brief moments of delight but also suggest that the article itself has something more important to say. Partly, this comes down to the use of transparency, whereas rectangular images capture more negative space and therefore demand more attention (which is fine if that’s the desired effect and images are crucial to the story).

However, it’s important to know that the images aren’t actually transparent at all, but instead are non-transparent JPEGs with the same background color as the content. I’m presuming that’s to keep the size of the images smaller compared to PNGs that support transparency.

Inspecting an image element in DevTools showing the JPEG images in the source.

The downside to “faking” a transparent background like this is that it would require additional trickery (and maintenance) to support a dark mode UI if your site happens to offer one. If the illustrations are pretty flat and simple, then SVG might be the way to go instead since it’s small, scalable, and capable of blending into whatever background it’s on.

But if you’re bound to using raster images and would rather work with PNG files for transparency, you’ll want to look into using responsive images and the loading="lazy" attribute for faster loading times.

Put the focus on the type and semantics

You may have very little say over how or where someone reads content on the web these days. Whether the user receives it in an RSS feed, gets it delivered by email, sees it copy-and-pasted from a colleague, finds it on a scraped site, or whatnot, your content might look different than you prefer. You could design what you think is the most gorgeous article in all the land and the user still might smash that Reader Mode button to your dismay.

That’s ok! The discoverability of content is very much as important as the design of it, and many users have their own ways of discovering content and preferences for what makes a good reading experience.

But there are reasons why someone would want a Reader Mode. For one, it’s like “not seeing any CSS” at all. By that, I mean Safari’s Reader Mode or Brave SpeedReader, which use machine learning to detect articles. There’s no fetching or executing of CSS, JavaScript, or non-article images, which boosts performance and also blocks ads and tracking.

Fong-form article viewed with Brave's SpeedReader feature.

This sort of “brute minimalism” puts the focus on the content rather than the styles. So, you might actually want to embrace a browser’s opinionated reading styles specifically for that purpose.

The way to do that is not by using CSS, but by paying closer attention to your HTML. Reader modes work best with markup that uses simple, semantic, article-related HTML. You’ve got to do more than simply slapping <article> tags around the article to get the most from it.

You might just find that a minimal design that emphasizes legibility over slickness is actually a good strategy to use in your site’s design. I’d strongly suggest reading Robin’s post on the “smallest CSS” for a solid reading experience.

Roundup of long-form articles!

I’ve shared a lot of what I think makes for a great reading experience for long-form articles on the web. But seeing is believing and I’ve rounded up a bunch of examples that showcase what we’ve covered.


Designing for Long-Form Articles originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/designing-for-long-form-articles/feed/ 5 367370
6 Useful Bookmarklets to Boost Web Development https://css-tricks.com/web-development-bookmarklets/ https://css-tricks.com/web-development-bookmarklets/#comments Mon, 28 Mar 2022 18:15:41 +0000 https://css-tricks.com/?p=364118 A bookmarklet is a JavaScript-based bookmark that adds to a web browser. I’d like to show you some awesome web browser hacks to aid your web development workflow and how to convert those hacks into time-saving bookmarklets.

  1. Activating design mode


6 Useful Bookmarklets to Boost Web Development originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
A bookmarklet is a JavaScript-based bookmark that adds to a web browser. I’d like to show you some awesome web browser hacks to aid your web development workflow and how to convert those hacks into time-saving bookmarklets.

  1. Activating design mode
  2. Applying a background to everything
  3. Simulating events
  4. Setting cookies
  5. Toggling classes
  6. Color widget bookmark
  7. What other bookmarklets can you think of?

Activating design mode

Design mode (styled as designMode since it’s a JavaScript property) is for who like to experiment with variations of copy on a live website. For example, copywriters who like to observe how content reads within the flow of the website’s design, or, say, designers who want to ensure that text fits comfortably within a certain space at a certain font size.

JavaScript has a mightily simple feature that can render an entire HTML document editable. It works exactly like HTML’s contenteditable="true" name-value attribute (or contentEditable="true" in JavaScript) but for the whole document. If you’d like to see how it works, start by entering the browser’s console using the relevant keyboard shortcut:

  • Chrome: Option + + J / Shift + CTRL + J
  • Firefox: Option + + K / Shift + CTRL + K
  • Safari: Option + + C / Shift + CTRL + C

Next, type document.designMode="on" into the console, hit Return, and then click on any text element. You’ll see that this text element (and all other text elements) are now editable simply by clicking on them. This method of editing text on a live website is much faster than having to open DevTools, then right-clicking and selecting the “Edit Text” option… and much less tiresome.

Showing an edited version of the CSS-Tricks guide landing page using the design mode bookmarklet.
“Guides and Thangs” — my favorite part of CSS-Tricks

While I’m not sure that “design mode” is the most accurate description of the feature, it’s super useful nonetheless and it’s actually been around for a really long time, surprisingly.

And what’s even an even faster way to enable it? A bookmarklet, of course! Create a bookmark using javascript: document.designMode="on";void 0; as the URL.

Showing the bookmarklet installation.

Applying a background to everything

When HTML elements don’t have backgrounds, it can be difficult to visualize their bounds and/or accurately measure the distance between them and other elements. Developers might want to better visualize bounds when dealing with optical imbalance (i.e. when something “looks off” even though it’s not), margin collapse (when certain margins are ignored), various issues with display:/float:/position:, and more.

Applying backgrounds means applying a semi-transparent background to all HTML elements in order to better visualize their bounds and spacings. It’s something many of us commonly do by opening up DevTools then typing a CSS declaration like selector { background: rgb(0 0 0 / 10%); } into the “Styles” box. But again, it’s really tiresome and repetitive — and something we can simplify with a bookmarklet.

Once again, to create a bookmark, we’re going to make a URL. Here’s what we can use for this one:

javascript: document.querySelectorAll("*").forEach(element => element.style.background="rgb(0 0 0 / 10%)");

We’re using a semi-transparent background because the transparency stacks, which ensures that every nested element is distinguishable and the distances between them can be measured.

Showing the CSS-Tricks guides landing page with all backgrounds fill with varying shades of gray.
Apply a background to everything to see what’s happening.

Simulating events

Have you ever had to test a web event that first requires a series of interactions, or certain conditions to be met? It’s super time-consuming to have to test or debug these kinds of functionalities. This event simulation bookmarklet can be used to instantly trigger specific events, making testing a breeze.

Simulating an event means coding a “throwaway” button that triggers a JavaScript event, making it much easier to quickly and repeatedly test the event without having to meet any usual user-facing conditions, like needing to be logged in.

Assuming that you have your JavaScript event listeners set up, create a bookmark for each event that you’d like to trigger/simulate and submit the following URL:

javascript: document.querySelector("SELECTOR").click();

Replace “SELECTOR” with your unique selector, replace “click” with “focus” or “blur” (when necessary), or extend the snippet to make it trigger more complex events, like scroll.

Setting cookies

Cookies are tokens that are stored on a website visitor’s computer by the website that they’re visiting. Cookies contain data that can be read by the website that created them until they’ve exceeded their expiration date or have been deleted. The mere existence of a cookie can determine whether or not a visitor is logged in, whereas the data itself can store user information.

An example of a scenario where you might want to set a cookie using a bookmarklet is when you want to force a logged-in state during website testing. Websites often look very different for users that are logged in, however, logging in and out eventually becomes very tedious, so this bookmarklet can save quite a bit of time.

Manually writing expires= dates for cookies is awkward as heck, but luckily this create-your-own-set-cookie-bookmarklet app can generate a bookmarklet for a specific cookie, if you know its exact name.

Toggling classes

You may want to add or remove a class from an HTML element in order to trigger a fresh state or a change in appearance, otherwise known as toggling classes. Class toggling happens behind the scenes of most live websites, but it can also be used during testing to skip having to meet certain user-facing conditions.

Class toggling can be used to trigger changes in appearance (e.g. alternative themes or states) and even animations, but it can be a little fiddly when doing it with developer tools when it’s only for testing reasons (i.e. the website doesn’t actually function that way for users). Similar to the other bookmarklets, use this one to rapidly toggle classes and save yourself time.

Create the following bookmarklet to target all elements that match your chosen “SELECTOR”, which, in turn, toggles the “CLASS.”

javascript: document.querySelectorAll("SELECTOR").forEach(element => element.classList.toggle("CLASS"));

Color widget bookmark

While not technically a “bookmarklet,” this bookmarkable data URI by Scott Jehl opens up an <input type="color"> in a new tab:

data:text/html;charset=utf-8,%3Chtml%3E%3Ctitle%3EColor Picker%3C%2Ftitle%3E%3Cinput type%3D"color"%3E%3C%2Fhtml%3E

Why is that cool? Well, how many times have you needed to grab a color value off a page, only to find yourself cracking open DevTools, clicking through a bunch of elements, and pouring over CSS properties to find the value? Better to run this little guy, click the element, and get a color right away!

What other bookmarklets can you think of?

Are there any overly repetitive web development workflows that require you to use the web browser’s sometimes-awkward developer tools? If so, it’s super easy to create your own time-saving bookmarklets. Just remember to start the URL with javascript:!

And if you’ve made a bookmarklet to simplify your workflow, I’d love to see it! Share them here in the comments and let’s get a nice collection going.


6 Useful Bookmarklets to Boost Web Development originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

]]>
https://css-tricks.com/web-development-bookmarklets/feed/ 32 364118