Tag: It’s

Working With Web Feeds: It’s More Than RSS

Between Google Chrome experimenting with “following” sites, along with a growing frustration of how social media platforms limit a creator’s reach to their fans through algorithmic feeds, there’s been renewed interest in RSS feeds and they’re primed for a comeback as we get into 2022.

This research is brought to you by support from Frontend Masters, CSS-Tricks’ official learning partner.

Need front-end development training?

Frontend Masters is the best place to get it. They have courses on all the most important front-end technologies. Interested in going full-stack? Here’s your best bet:

You may have heard whispers that “RSS in dead” around the web, but the truth is that they are still widely used as virtually every podcast uses one. Maybe you used to be an RSS fan and need to get re-acquainted with it. Or maybe you’re like Chris here at CSS-Tricks and still love RSS. Whatever the case, RSS is a web technology like any other, and there are best practices for how to create and curate a feed.

That’s exactly what I’m going to walk you through in this article. Let’s talk about the different kinds of feeds, how to implement them, and what strategies you can use to get the most out of your feed content.

RSS vs. Atom vs. JSON

Believe it or not, RSS is just one format among other types of syndicated web feeds. The most common formats are:

  1. RSS
  2. Atom
  3. JSON Feed

I’ve used RSS to signify these formats since it’s a far more popular search term but I’ll refer to these technologies as web feeds in this article unless I’m referring to a specific format.

On Sept 26–Oct 2, 2021, RSS had 37 points, web 6, atom 2 and jsonfeed 0. S
Google Trends for Atom, JSON, RSS and web feeds. (Source: Google Web Trends)

While Atom, RSS and, JSON feeds accomplish the same thing, there are a few differences between them:

  • Atom and RSS are based on XML while a JSON feed is based on, well, JSON.
  • All of these formats can be extended in some way. In a JSON feed, this is done by adding an object with a key that starts with an underscore anywhere in a feed’s object. With Atom and RSS, you do this by declaring the namespace on the root element. One example of this is on podcast feeds which declare the iTunes podcast namespace, allowing for the use of <itunes:*> tags.
  • JSON feed is a newer feed format meaning that support for it might not be as broad as Atom or RSS. If you have a podcast, however, RSS is a must.
  • While all of the formats require a unique identifier for each entry/item, Atom takes it a step further as it requires a unique identifier for every feed.
  • All allow HTML markup, though they handle it differently. JSON uses the content_html key containing JSON escaped HTML. Atom uses the content tag with type=html containing XML escaped HTML. RSS uses the <description> tag (or the content extension) which either contains XML-escaped HTML or the HTML unescaped in a <![CDATA[]]> tag.

Other than these things, there are only minor differences between them. You might think that the size of the file could be a possible difference, but compression reduces them all to just a few kilobytes apiece. Unless your application has a specific use case that requires a specific format (like podcasts), it doesn’t hurt to provide multiple formats, but RSS and Atom have the most support.

What makes a “good” feed?

Let’s look at some best practices for making feeds. Like most things on the web, there are things we can do to optimize our work to get the most out of it.

1. It’s easy to find

It doesn’t help to have a feed if no one knows about it. And one way to make a feed discoverable is to link it up in the <head> of your site. This way, feed readers are able to crawl and recognize when a site offers a content feed.

Here’s an example showing all three formats linked up in the document head:

<head>   <link rel="alternate" type="application/rss+xml" href="https://codelab.farai.xyz/index.rss.xml" title="Farai's Codelab's RSS Feed" />   <link rel="alternate" type="application/feed+json" href="https://codelab.farai.xyz/index.feed.json" title="Farai's Codelab's JSON Feed" />   <link rel="alternate" type="application/atom+xml" href="https://codelab.farai.xyz/index.atom.xml" title="Farai's Codelab's ATOM Feed" />   <!-- etc. --> </head>

And, yes, it’s OK to use all three! You can specify as many links as you want, though some feed readers might only recognize the first one. The important thing is that one includes rel="alternate" and the feed’s MIME type. There’s also the option to add a title which never hurts.

What else can you do to make your feed easy to find? Advertise it! Place direct links to the feeds somewhere prominent on your site that people can use to copy and paste into their feed reader.

That’s what CSS Tricks does. This is the link to the site’s RSS and it’s available in the footer across the entire site. Some feed readers can pick up on these links, too, even though they are outside of the <head>.

Screenshot of the CSS-Tricks footer showing a column of links with the heading Follow, and links for social networks, including the site's RSS feed. The background is near black, the headings are orange, and the links are light gray.
Oh, you want to subscribe to the CSS-Tricks RSS feed? Please do! Your RSS feed is just as much a thing to follow as any social network.

As for what to name the feed itself, it doesn’t matter as long as it’s discoverable. Here’s a good look into how various sites name their feeds, but I’ve named mine feed.json, feed.rss.xml and feed.atom.xml for JSON feed, Atom, and RSS respectively.

2. It takes advantage of HTTP

There are certain basic features of the web that can be leveraged to make your feeds a little better.

For example, be sure to compress your feeds, as it greatly reduces the overall file size and the time to download it. Most servers can take care of this for you, using gzip, Brotli, or some other compression engine.

Likewise, it’s a good idea to support either ETags or If-Modified-Since as they both allow clients to cache feeds and informs the browser whether a newer version of the feed is ready before it is downloaded. Much like compression, your server may take care of this as well.

Another thing to do: enable permissive CORS. Otherwise, clients could be blocked from fetching the feed. And while you should consider the security implications of letting any old site fetch your feed, it’s highly unlikely that it becomes a major issue for most small sites and feeds. This one-liner is all you need to enable CORS:

Access-Control-Allow-Origin: *

3. It displays full content instead of summaries

This is totally a user experience thing. You may have even experienced this before, where you subscribe to an RSS feed and all you get is the first paragraph or a summary of the post. Why? The traditional thinking is that providing only a summary encourages users to click through to your site, thereby leading to more visits. And more visits equals more eyeballs, which equals more revenue, etc.

I suggest avoiding that and instead allow your feeds to send the entire content for each post/entry/item. Many users prefer reading content in a feed reader because of the emphasis they place on legibility.

If you’re concerned about some dishonest person scraping your content and displaying it on their own site because you’re feeding the full content, let me reassure you: it’s no harder to a web page than a syndicated feed.

And if you’re a publisher who relies on display ads, and are concerned about the impact that sending full content might have on your revenue: you can still add static ads directly into your feed content. Besides, some readers can parse the web page associated with a feed entry so it can be read in the reader as well.

Dark UI with blue links and light gray text showing an article from a blog.
N/N Group article rendered in the NetNewsWire reader

But let’s not be dogmatic and all, because there are situations where summaries make sense. One is when a feed has a bunch of long-form entries. Another is when you have rich content that can only be viewed in a particular way (think show notes for a podcast). In that case, try making a good summary. One example is Nielsen Norman Group’s RSS which has a summary and an excerpt up to the first <h2> tag.

If I ever decide to only show summaries in my feed, I’d make sure to include an image, an outline of the content’s main points, and a link to the canonical version in addition to the summary. It is a bit of work but it gives the reader an idea what to expect, unlike some feeds I’ve seen which awkwardly truncate content to just the first few words.

Showing a post title in white with the published date and time below it in light gray. Below that is an image of a tired looking man with dark slicked back hair holding a 10 of diamonds card. Below that is the first sentence of a post that breaks mid-sentence.
Yes? You want to finish that sentence?

4. It is designed for reading

When crafting content, consider how it might be seen outside the context of a web browser, in places where JavaScript and CSS are limited. Sara Soueidan has a bunch of tips and ideas that are worth checking out. The main idea: provide a good fallback experience for your content.

This is a mostly an issue when it comes to embedded elements. While some embeds contain fallback content in their markup (like Twitter’s embedded tweets and CodePen’s embedded pens), others might not. Certain embeds (including videos posted to Vimeo) can only be embedded on certain domains meaning those won’t show up in a feed reader. So you need provide a way to view it somehow, like an image or a link to a webpage.

Showing the same article rendered in both Microsoft Outlook (left) and NetNewsWire (right). The article includes three embeds, one from Twitter, one from YouTube, and the third from TinkerCad), where each includes some form of fallback content for a better reading experience.

There are plenty of ways to do fallbacks. Twitter’s embed falls back to a <blockquote> — which makes total sense as a tweet is sort of like a quote — and a link to the tweet itself, which allows some clients that do not support embeds, like Outlook, to effectively render the content in a way that is still accessible to the user.

Though NetNewsWire is good with embeds, YouTube sometimes prevents it from playing videos like here. So, instead, the embed falls back to a link that points the user to watch it on YouTube’s site. Outlook doesn’t support YouTube embeds (or any embeds at all), but a descriptive link to the video on YouTube is still available.

The moral of the story: know your readers and how they render content so you can provide the best fallback experience possible.

Beware of relative URLs

One big issue across feeds is resolving relative URLs for images and links. Resolving based off the feed’s canonical link might work, but what happens if that link is in a subdirectory? The XML formats could use the xml:base attribute which defines the base URL to use when resolving relative URLs, but that’s only supported by Atom and is ignored and deprecated by most readers.

The most robust solution is to use absolute URLs for every href and src in an entry’s content. Meaning that the markup looks something like this:

<p>Read <a href="https://css-tricks.com/archives/">all our articles</a>.</p>

…and neither this:

<p>Read <a href="/archives/">all our articles</a>.</p>

…nor this:

<p>Read <a href="archives/">all our articles</a>.</p>

This is hard to do automatically, moreso with statically-generated sites. One approach is to make relative URLs absolute after compiling the feed in a build pipeline. Another approach is to manipulate the way Markdown links and images are rendered by your static site generator so that the URLs are absolute. I hope that more static site generators allow the second option but, for now, Hugo is the only static site generator that supports this through Markdown render hooks.

But wait, there’s an exception to this rule. And it’s footnotes. Some readers can detect footnotes and handle them. Here’s some HTML that should work in any feed reader that supports relative jump links:

<p>They’d managed to place 27.9MB of images onto the Critical Path.  Almost 30MB of previously non-render blocking assets had just been  turned into blocking ones on purpose with no escape hatch. Start  render time was as high as 27.1s over a cable connection<sup id="fnref:1">   <a href="#fn:1" class="footnote">1</a></sup>.</p>  <div class="footnotes">   <ol>     <li id="fn:1">      <p>5Mb up, 1Mb down, 28ms RTT. <a href="#fnref:1" class="reversefootnote">↩</a></p>     </li>   </ol> </div>

How to handle ads in feeds

You’re unlikely to get JavaScript support inside of an RSS reader, and that means no ads connected to an ad server. In other words, ads will need to be part of your content rather than something that is dynamically injected into place.

Showing an advertisement for anima that displays a brightly colored image, text below the image that says our sponsor, followed by the post title in blue, a blurb from the article content, them a blue learn more link.
The Codrops newsletter is an example that does this well. The newsletter includes a sponsored image and text, and clearly indicates the content is sponsored.

PSA: Not all content needs to be included in a feed

I’ve seen feeds in which every piece of content published is packed in and made available all the way back to the very first entry in the feed. I also see plenty of feeds from publishers who post dozens of entries a day. In both cases, I suggest limiting both the amount of content that’s available from past archives and considering multiple feeds instead of one.

Perfect example. Check out MacRumors.com’s feed because it’s extremely active with dozens of new articles published daily. Can you imagine going back to an article from, say, 10 years ago in that feed? Likely not. Unless the feed is for a podcast where storing every episode makes sense, try limiting the number of entries stored in your feed, as users are likely more interested in newer content. This reduces bandwidth and reduces update times which especially counts since users have many feeds to refresh.

I am tempted to say that 10–15 posts is enough to store and display at a time, but like many things, “it depends.” While storing a few makes sense for a site that pushes new content a few times a month, other sites that post way more frequently might eclipse that in a day. So, really, the ideal number of posts is going to depend on the type of content you publish (is it timely or evergreen?) and both the volume and frequency of what you publish (is it a lot throughout the day or a few times a month?).

But what I’m really trying to get at is that you want to avoid overwhelming users by inundating them with a pile of articles to get through. A couple of ways to avoid that include:

  • displaying summaries instead of full content (see, another exception to a previous rule!), and
  • filtering content so that users can choose from multiple feeds for specific types of content. In other words, if you want to provide every single post (or a complete timeline on a particular topic), consider making a dedicated feed for that topic/category/tag/whatever.

The reason I’m so fussy about the size of a feed is that—like images, scripts, and other assets—the number and size of feeds affect the performance of a feed reader. The more feeds a user is subscribed to and the more entries that need to be fetched from those feeds add to the time it takes to refresh and display that content.

Moving feeds

Like websites might change domains, you may need to move a feed from its current address. It’s not terribly difficult to do, but there are important things to consider before making a move.

For instance, it’s a good idea to ensure that your feed’s items have a global unique identifier (GUID). This maps out to feed’s guid in RSS and its id in both Atom and JSON. The GUI prevents feed readers from fetching duplicate entries. This is all the more important (and challenging) if you’re working with a static site.

While it may be tempting to use the entry’s permalink as an identifier, remember, those can change. To make a GUID, I’d recommend looking into using a tag URI. A tag URI consists of:

  • an authority (i.e., the domain of the site)
  • a date (that indicates a point in time that the tagging entity controlled the authority name associated with the feed)
  • the specific URL to fetch
  • a fragment (which might be a sub resource or a timestamp)
tag:<authority>,<YYYY-MM-DD>:<specific>#<fragment>

The <specific> portion could be something like the relative portion of your site’s homepage URL (i.e. /) and the fragment can be the content’s published timestamp. For instance, a post here on CSS Tricks could have a tag URI that looks like this:

tag:css-tricks.com,2021-16-11:/#1637082038781

This way, the authority date ensures that even if the domain changed hands. Plus, it can be managed in a static site generator as you can track domain changes over time.

The biggest reason I suggest the tag URI scheme is that Atom requires a feed’s id to be in a URL format. Even though RSS and JSON don’t have the same constraint, the tag URI scheme works for them as well, meaning we have full support.

And, with a robust id in place, a feed can be safely moved without feed readers pulling in duplicate entries. To move the feed itself, set up a 301 redirect to the new location and you’re done.

You might come across a technique called the XML redirect in which a file containing the feed’s new location is placed at the old location. As great as this would work for times when you can’t manipulate HTTP codes, I couldn’t find any feed readers which implement this.

Validating a feed

Feeds, like HTML, need to be valid in order to properly work. The benefit of a validated feed is that you know your code is free from errors and that entries are properly flowing from your site to feed readers.

W3C’s feed validation service is one option for RSS and Atom feeds. You provide the URL to the feed or paste the feed’s actual code, and you’ll get a full report that shows whether you’re hitting all the best practices. You’re likely to get warnings. It happens. Most warnings are really just a heads up and might not have an impact on the feed.

That said, there are two things that should always be addressed when validating a feed:

  • item should contain a guid element: The unique identifier, as we saw, prevents a feed reader from showing the same entry twice when a feed moves.
  • element should contain absolute URL references—these are hard for readers to resolve, so avoid relative URLs where possible.

What about JSON? To validate a JSON feed, try either using validator.jsonfeed.org or verifying against the JSON Feed schema using any JSON schema validator.

Managing or restricting access to a feed

You know how you can subscribe to a paid podcast and you get access to a special feed URL that contains all the “premium” content you gain access to with your subscription? Well, that’s because we can control who has access to a particular feed while locking others out from receiving the content.

There are two techniques for managing access to a feed:

  • HTTP basic authentication requires a username and password, which are either prompted for the user to provide or inferred in the feed URL itself, e.g. https://username:password@domain.example/path.
  • Providing a token as a query parameter, e.g. http://domain.com/path?token=xyz

As long as the URL is HTTPS, they have the same security, as the URL paths and passwords are encrypted. As for handling authentication it on the server, that’s a whole other topic though there are quite a few articles on it right here on CSS-Tricks.

Join the RSS Club!

OK, so the first rule of the RSS Club is:

Don’t talk about it. Let people find it. Make it worthwhile.

But I’m going to talk about it because feeds that are part of the RSS Club are excellent examples of tailored feeds. That’s because the feed entries are only available in those feeds. In other words, the blog posts are published, but never display on the actual site — they’re only accessible by feed.

Dave Rupert founded the club a number of years ago and it’s a great way to make RSS a first-class citizen for consuming content within a small community.

Joining the club means having a dedicated feed for posts that are only available in that feed. For example, in WordPress, you could create a new “RSS Club” category and filter it out of the main post query. That way, you’re able to either provide a feed just for that category, or the full feed that still includes posts in that category.

(Sorry for spilling the beans, Dave!)

Web feeds beyond content

RSS can be used for more things than blog posts or articles. For instance, GitHub has Atom feeds for issues, commits, pull requests, and releases.

They can also be used to provide updates. Let’s say you wanted a feed that notifies you when there are changes to your website. That’s a great idea, right? Always nice to know what’s happening, especially when there’s more than one cook in the kitchen.

You could build some sort of system that polls your feed periodically for changes then trigger a new feed entry, but that requires a lot of resources. Another idea is to implement webhooks you tell where to look for changes. Then again, managing and sending out notifications can be a hassle, especially if all you want is to monitor content.

I think it’s worth checking out WebSub. You, as a publisher, tell a hub that the site has changed, and the hub notifies whatever system that’s subscribed to the site’s web feeds. You can publish your feed to an existing hub — like Google’s PubSubHubbub Hub — then specify the hub in your feeds. YouTube has implemented this.

WebSub Flow Diagram, Julien Genestoux
Copyright © 2018 World Wide Web Consortium, (MIT, ERCIM, Keio, Beihang).

Examples!

What’s a tutorial like this without a few good examples? Let’s look at three real-world examples.

1. RSS Podcast

Did you know that CSS-Tricks has a podcast for an ongoing series that covers web history? Well, it does. And, yes, you can subscribe to it via RSS.

Podcasts must use RSS with the xmlns:content and xmlns:itunes extensions, which are needed to provide metadata about the podcast and its episodes. The audio file for each episode is specified in an enclosure along with its mime type and size. RSS is limited to one enclosure, but both Atom and JSON support multiple enclosures.

Here’s the feed. Notice the iTunes-specific tags as well as other bits of information that are provided for additional context:

<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd">   <channel>     <atom:link href="https://adactio.s3.amazonaws.com/audio/narration/web_history/podcast.xml" rel="self" type="application/rss+xml" />     <title>Web History</title>     <link>https://css-tricks.com/category/history/</link>     <language>en</language>     <copyright>2020</copyright>     <description>Written by Jay Hoffmann and narrated by Jeremy Keith.</description>     <image>       <url>https://adactio.s3.amazonaws.com/audio/narration/web_history/WebHistoryPodcast.jpg</url>       <title>Web History</title>       <link>https://css-tricks.com/category/history/</link>     </image>     <itunes:author>Jay Hoffman</itunes:author>     <itunes:summary>The history of the web.</itunes:summary>     <itunes:explicit>no</itunes:explicit>     <itunes:type>episodic</itunes:type>     <itunes:owner>       <itunes:name>Jeremy Keith</itunes:name>       <itunes:email>jeremy@adactio.com</itunes:email>     </itunes:owner>     <itunes:image href="https://adactio.s3.amazonaws.com/audio/narration/web_history/WebHistoryPodcast.jpg"/>     <itunes:category text="Technology"></itunes:category>     <item>       <title>Chapter 10: Browser Wars</title>       <description>In June of 1995, representatives from Microsoft arrived at the Netscape offices. The stated goal was to find ways to work together—Netscape as the single dominant force in the browser market and Microsoft as a tech giant just beginning to consider the implications of the Internet. Both groups, however, were suspicious of ulterior motives.</description>       <pubDate>Mon, 8 Nov 2021 12:00:00 -0000</pubDate>       <link>https://css-tricks.com/chapter-10-browser-wars/</link>       <itunes:title>Chapter 10: Browser Wars</itunes:title>       <itunes:episode>10</itunes:episode>       <itunes:episodeType>full</itunes:episodeType>       <itunes:author>Jay Hoffman</itunes:author>       <itunes:summary>In June of 1995, representatives from Microsoft arrived at the Netscape offices. The stated goal was to find ways to work together—Netscape as the single dominant force in the browser market and Microsoft as a tech giant just beginning to consider the implications of the Internet. Both groups, however, were suspicious of ulterior motives.</itunes:summary>       <content:encoded>         <![CDATA[           <p>In June of 1995, representatives from Microsoft arrived at the Netscape offices. The stated goal was to find ways to work together—Netscape as the single dominant force in the browser market and Microsoft as a tech giant just beginning to consider the implications of the Internet. Both groups, however, were suspicious of ulterior motives.</p>         ]]>       </content:encoded>       <itunes:duration>00:40:40</itunes:duration>       <guid>https://adactio.s3.amazonaws.com/audio/narration/web_history/Chapter_10_Browser_Wars.mp3</guid>       <enclosure url="https://adactio.s3.amazonaws.com/audio/narration/web_history/Chapter_10_Browser_Wars.mp3" length="19608877" type="audio/mpeg"/>     </item> </channel> </rss>

2. RSS for posts

Let’s look to CSS-Tricks once again, this time for an example of what a pretty standard RSS feed of blog posts looks like.

The code for this particular RSS feed is a little more verbose than your typical feed, and that’s to do with the multiple extensions added to the <rss> tag. A number of them aren’t reachable but there are some that handle other things, like xmlns:wfw for comments, xmlns:dc for additional metadata, and xmlns:sy for information on how often the feed is refreshed.

<?xml version="1.0" encoding="UTF-8"?> <rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#">   <channel>     <title>CSS-Tricks</title>     <atom:link href="https://css-tricks.com/feed/" rel="self" type="application/rss+xml" />     <link>https://css-tricks.com</link>     <description>Tips, Tricks, and Techniques on using Cascading Style Sheets.</description>     <lastBuildDate>Fri, 19 Nov 2021 15:13:49 +0000</lastBuildDate>     <language>en-US</language>     <sy:updatePeriod>   hourly  </sy:updatePeriod>     <sy:updateFrequency>   1 </sy:updateFrequency>     <generator>https://wordpress.org/?v=5.8.2</generator>     <image>       <url>https://i1.wp.com/css-tricks.com/wp-content/uploads/2021/07/star.png?fit=32%2C32&ssl=1</url>       <title>CSS-Tricks</title>       <link>https://css-tricks.com</link>       <width>32</width>       <height>32</height>     </image>     <site xmlns="com-wordpress:feed-additions:1">45537868</site>     <item>       <title>Parallax Powered by CSS Custom Properties</title>       <link>https://css-tricks.com/parallax-powered-by-css-custom-properties/</link>       <comments>https://css-tricks.com/parallax-powered-by-css-custom-properties/#respond</comments>       <dc:creator>         <![CDATA[Jhey Tompkins]]>       </dc:creator>       <pubDate>Fri, 19 Nov 2021 15:13:46 +0000</pubDate>       <category>         <![CDATA[Article]]>       </category>       <category>         <![CDATA[animation]]>       </category>       <category>         <![CDATA[custom properties]]>       </category>       <category>         <![CDATA[GSAP]]>       </category>       <guid isPermaLink="false">https://css-tricks.com/?p=357192</guid>       <description>         <![CDATA[ ]]>       </content:encoded>       <wfw:commentRss>https://css-tricks.com/parallax-powered-by-css-custom-properties/feed/</wfw:commentRss>       <slash:comments>0</slash:comments>        <post-id xmlns="com-wordpress:feed-additions:1">357192</post-id>     </item>   </channel> </rss>

3. JSON feed

This is actually my personal feed and I just so happen to use JSON for it. It’s pretty bare bones and less cluttered than the other examples because, as far as I know, there are no JSON extensions like the RSS ones we saw in Example 2.

I find that JSON is much easier to read and understand all that’s needed is an object with the feed data rather than writing out the entire template.

{   "author": {     "name": "Farai Gandiya"   },   "feed_url": "https://codelab.farai.xyz/feed.json",   "home_page_url": "https://codelab.farai.xyz/",   "icon": "https://codelab.farai.xyz/fcl-logo.png",   "items": [     {       "content_html": "...",       "date_modified": "2021-11-13T05:26:07+02:00",       "date_published": "2021-11-13T05:26:07+02:00",       "id": "https://codelab.farai.xyz/1636773967",       "summary": "...",       "title": "Don't be afraid of the Big Long Page by Amy Hupe, content designer.",       "url": "https://codelab.farai.xyz/links/long-content-ok/"     }   ] }

Web Feed Implementations Across CMSs and Static Site Generators

Many CMSs and static site generators support web feeds, though it’s usually RSS as it has the widest support. Here are some CMSs that support web feeds:

And here’s some resources on adding web feeds (again mostly RSS) to various static site generators

Wrapping up

And there you have it! This is what I believe be nearly everything you need to consider when implementing a web feed. We looked at three different formats (RSS, Atom, JSON), covered best practices for creating a user-friendly feed reading experience, walked through validating a feed, covered the possibility of authenticating feeds, looked at three real-world examples of feeds in the wild, and provided some implementations across various technologies.

(Oh, and there was that thing where the first rule of the thing is not to talk about the thing.)

I hope these guidelines empower you to make resilient web feeds. If you have any questions on implementing a web feed, or you just feel like sharing your RSS feed, please do leave a comment!

CSS-Tricks

, , , ,

Equal Columns With Flexbox: It’s More Complicated Than You Might Think

You get a nice-looking design handed to you and it has this nice big hero section, followed by one of those three-up columns right beneath it. You know, like almost every other website you’ve ever worked on.

You bang through the hero section and get to work on the three-column section. It’s time to pull out our trusty friend flexbox! Except, you write display: flex and you get this mess instead of getting the three equal columns you’d expect.

This happens because of how flexbox calculates the base size of an element. You’ve probably read lots of flexbox tutorials, and many of them (including my own) are an overly simplistic example of what flexbox does without really digging into the complex things that flexbox does for us that we take for granted.

I’m positive you’ve seen examples and tutorials that look at something like this, where three divs shrink down around the content that’s inside them:

In other words, we get some block-level elements shrinking down and slotting next to one another. It feels like flex wants things to be as small as possible. But in reality, flexbox actually wants things to be as big as possible.

Wait, what? Flex shrinks things by default — that can’t be right! Right?

As awesome as flexbox is, what it’s doing under the hood is actually a little strange because, by default, it is doing two things at once. It first looks at the content size which is what we would get if by declaring width: max-content on an element. But on top of that, flex-shrink is also doing some work allowing the items to be smaller, but only if needed.

To really understand what’s going on, let’s break those two down and see how they work together.

Diving into max-content

max-content is a pretty handy property value in certain situations, but we want to understand how it works in this particular situation where we are trying to get three seemingly simple equal columns. So let’s strip away flexbox for a moment and look at what max-content does on its own.

MDN does a good job of explaining it:

The max-content sizing keyword represents the intrinsic maximum width of the content. For text content this means that the content will not wrap at all even if it causes overflows.

Intrinsic might throw you off here, but it basically means we’re letting the content decide on the width, rather than us explicitly setting a set width. Uri Shaked aptly describes the behavior by saying “the browser pretends it has infinite space, and lays all the text in a single line while measuring its width.”

So, bottom line, max-content allows the content itself to define the width of the element. If you have a paragraph, the width of that paragraph will be the text inside it without any line breaks. If it’s a long enough paragraph, then you end up with some horizontal scrolling.

Let’s revisit that overly-simplistic example of three block-level elements that shrink down and slot next to one another. That isn’t happening because of flex-shrink; it’s happening because that’s the size of those elements when their declared width is max-content. That’s literally as wide as they go because that’s as wide as the combined content inside each element.

Here, take a look at those elements without flexbox doing it’s flexbox stuff, but with a width: max-content on there instead:

So, when there’s just a small amount of text, the intrinsic max-content shrinks things down instead of flex-shrink. Of course, flexbox also comes in with it’s default flex-direction: row behavior which turns the flex items into columns, putting them right next to one another. Here’s another look but with the free space highlighted.

Adding flex-shrink to the equation

So we see that declaring display: flex pushes that max-content intrinsic size on flex items. Those items want to be as big as their content. But there is another default that comes in here as well, which is flex-shrink.

flex-shrink is basically looking at all the flex items in a flexible container to make sure they don’t overflow the parent. If the flex items can all fit next to each other without overflowing the flexible container, then flex-shrink won’t do anything at all… it’s job is already done.

But if the flex items do overflow the container (thanks to that max-content intrinsic width thing), the flex items are allowed to shrink to prevent that overflow because flex-shrink is looking out for that.

This is why flex-shrink has a default value of 1. Without it, things would get messy pretty quickly.

Here’s why the columns aren’t equal

Going back to our design scenario where we need three equal columns beneath a hero, we saw that the columns aren’t equal widths. That’s because flexbox starts by looking at the content size of each flex item before even thinking about shrinking them.

Using Firefox’s DevTools (because it’s got some unique flexbox visualizations that others don’t), we can actually see how flexbox is calculating everything.

For simplicity’s sake, as we dive deeper into this, let’s work with some nice round numbers. We can do this by declaring widths on our flex items. When we declare a width on a flex item, we throw that intrinsic size out the window, as we’ve now declared an explicit value instead. This makes figuring out what’s really going on a lot easier.

In the Pen below, we have a parent that’s a 600px wide flexible container (display: flex). I’ve removed anything that might influence the numbers, so no gap or padding. I’ve also switched out the border for an outline so we can still visualize everything easily.

The first and third flex items have a width: 300px and the middle one a width: 600px. If we add that all up, it’s a total of 1200px. That’s bigger than the the 600px available within the parent, so flex-shrink kicks in.

flex-shrink is a ratio. If everything has the same flex-shrink (which is 1 by default), they all shrink at the same rate. That doesn’t mean they all shrink to the same size or by the same amount, but they all shrink at the same rate.

If we jump back into Firefox DevTools, we can see the base size, the flex-shrink and the final size. In this case, the two 300px elements are now 150px, and the 600px one is now 300px.

The two elements that have a base width of 300px become 150px.

The larger element with a base width of 600px becomes 300px.

If we add up all the base sizes of all three flex items (the actual widths we declared on them), the total comes out to 1200px. Our flex container is 600px wide. If we divide everything by 2, it fits! They are all shrinking by the same rate, dividing their own widths by 2.

It’s not often that we have nice round numbers like that in the real world, but I think this does a nice job illustrating how flexbox does what it does when figuring out how big to make things.

Getting the columns to be equal

There are a few different ways to get the three columns we want to be equal in width, but some are better than others. For all the approaches, the basic idea is that we want to get all the columns base size to be the same. If they have an equal base size, then they will shrink (or grow, if we use flex-grow) at an equal rate when flexbox does it’s flex things, and in theory, that should make them the same size.

There are a few common ways to do this, but as I discovered while diving into all of this, I have come to believe those approaches are flawed. Let’s look at two of the most common solutions that I see used in the wild, and I’ll explain why they don’t work.

Method 1: Using flex: 1

One way we can try to get all the flex items to have the same base size is by declaring flex: 1 on all of them:

.flex-parent { display: flex; } .flex-parent > * { flex: 1; }

In a tutorial I made once, I used a different approach, and I must have had 100 people asking why I wasn’t using flex: 1 instead. I replied by saying I didn’t want to dive into the flex shorthand property. But then I used flex: 1 in a new demo, and to my surprise, it didn’t work.

The columns weren’t equal.

The middle column here is larger than the other two. It’s not by a ton, but the whole design pattern I’m creating is just so you have perfectly equal columns every single time, regardless of the content.

So why didn’t it work in this situation? The culprit here is the padding on the component in the middle column.

And maybe you’ll say it’s silly to add padding to one of the items and not the others, or that we can nest things (we’ll get to that). In my opinion, though, I should be able to have a layout that works regardless of the content that we’re putting in it. The web is all about components that we can plug and play these days, after all.

When I first set this up, I was sure it would work, and seeing this issue pop up made me want to learn what was really going on here.

The flex shorthand does more than just set the flex-grow: 1. If you don’t already know, flex is shorthand for flex-grow, flex-shrink, and flex-basis.

The default values for those constituent properties are:

.selector {   flex-grow: 0;   flex-shrink: 1;   flex-basis: auto; }

I’m not going to deep dive flex-basis in this article, as that’s something Robin has already done well. For now, we can think of it like width to keep things simple since we aren’t playing with flex-direction.

We’ve already seen how flex-shrink works. flex-grow is the opposite. If the size of all the flex items along the main axis is smaller than the parent, they can grow to fill that space.

So by default, flex items:

  • don’t grow;
  • if they would otherwise overflow the parent, they are allowed to shrink;
  • their width acts like max-content.

Putting that all together, the flex shorthand defaults to:

.selector {   flex: 0 1 auto; }

The fun thing with the flex shorthand is you can omit values. So, when we declare flex: 1, it’s setting the first value, flex-grow, to 1, which basically turns on flex-grow.

The strange thing here is what happens to the values that you omit. You’d expect them to stay at their defaults, but they don’t. Before we get to what happens, though, let’s first dive into what flex-grow even does.

As we’ve seen, flex-shrink allows elements to shrink if their base sizes add up to a computed value that’s bigger than the available width of the parent container. flex-grow is the opposite. If the grand total of the element base sizes is smaller than the value of the parent container’s width, then they will grow to fill the available space.

If we take that super basic example where we have three small divs next to one another and add flex-grow: 1, they grow to fill that leftover space.

But if we have three divs with unequal widths — like those ones we started with — adding flex-grow to them won’t do anything at all. They won’t grow because they’re already taking up all the available space —so much space, in fact, that flex-shrink needs to kick in and shrink them down to fit!

But, as folks have pointed out to me, setting flex: 1 can work to create equal columns. Well, sort of, as we saw above! In simple situations it does work though, as you can see below.

When we declare flex: 1 it works because, not only does this set the flex-grow to 1, but it also changes the flex-basis!

.selector {   flex: 1;   /* flex-grow: 1; */   /* flex-shrink: 1; */   /* flex-basis: 0%; Wait what? */ }

Yup, setting flex: 1 sets the flex-basis to 0%. This overwrites that intrinsic sizing we had before that behaved like max-content. All of our flex-items now want to have a base size of 0!

Looking at the expanded view of the flex: 1 shorthand in DevTools shows us that the flex-basis has changed to 0

So their base sizes are 0 now, but because of the flex-grow, they can all grow to fill up the empty space. And really, in this case, flex-shrink is no longer doing anything, as all the flex items now have a width of 0, and are growing to fill the available space.

FireFox’s DevTools showing an element with flex: 1 has a content size of 0 and is growing to fill the available space.

Just like the shrink example before, we’re taking the space that’s available, and letting all the flex items grow at an equal rate. Since they are all a base width of 0, growing at an equal rate means the available space is equally divided between them and they all have the same final size!

Except, as we saw, that’s not always the case…

The reason for this is because, when flexbox does all this stuff and distributes the space, whether it’s shrinking or growing a flex item, it’s looking at the content size of the element. If you remember back to the box model, we have the content size itself, then the padding, border, and margin outside of that.

And no, I didn’t forget * { box-sizing: border-box; }.

This is one of those strange quirks of CSS but it does make sense. If the browser looked at the width of those elements and included their padding and borders in the calculations, how could it shrink things down? Either the padding would also have to shrink or things are going to overflow the space. Both of those situations are terrible, so instead of looking at the box-size of elements when calculating the base size of them, it only looks at the content-box!

So, setting flex: 1 causes a problem in cases where you have borders or padding on some of your elements. I now have three elements that have a content-size of 0, but my middle one has padding on it. If we didn’t have that padding, we’d have the same math we did when we looked at how flex-shrink works.

A parent that is 600px and three flex items with a width of 0px. They all have a flex-grow: 1 so they grow at an equal rate, and they each end up 200px wide. But the padding mucks it all up. Instead, I end up with three divs with a content size of 0, but the middle one has padding: 1rem. That means it has a content size of 0, plus 32px padding as well.

We have 600 - 32 = 568px to divide equally, instead of 600px. All the divs want to grow at an equal rate, so 568 / 3 = 189.3333px.

And that’s what happens!

But… remember, that’s their content size, not the total width! That leaves us with two divs with a width of 189.333px, and another with a which of 189.333px + 32 = 221.333px. That’s a pretty substantial difference!

Method 2: flex-basis: 100%

I have always handled this like this:

.flex-parent {   display: flex; }  .flex-parent > * {   flex-basis: 100%; }

I thought this worked for the longest time. Actually, this was supposed to be my final solution after showing that flex: 1 doesn’t work. But while I was writing this article, I realized it also falls into the same problem, but it’s a lot less obvious. Enough so that I didn’t notice it with my eyes.

The elements are all trying to be 100% width, meaning they all want to match the width of the parent, which, again, is 600px (and in normal circumstances, is often much bigger, which further reduces the perceivable difference).

The thing is that 100% includes the padding in the computed values (because of * { box-size: border-box; }, which for the sake of this article, I’m assuming everyone is using). So, the outer divs end up with a content size of 600px, whereas the middle div ends up with a content size of 600 - 32 = 568px.

When the browser is working out how to evenly divide the space, it isn’t looking at how to evenly squish 1800px into a 600px space, but rather it’s looking at how to squish 1768px. Plus, as we saw earlier, flex items don’t shrink by the same amount, but at an equal pace! So, the element with padding shrinks slightly less in total than the others do.

This results in the .card having a final width of 214.483px while the others clock in at 192.75px. Again, this leads to unequal width values, though the difference is smaller than we saw with the flex: 1 solution.

Why CSS Grid is the better choice here

While all this is a little frustrating (and even a little confusing), it all happens for a good reason. If margins, padding, or borders changed sizes when flex gets involved, it would be a nightmare.

And maybe this means that CSS Grid might be a better solution to this really common design pattern.

I’ve long thought that flexbox was easier to pick up and start using than grid, but grid gives you more ultimate control in the long run, but that it’s a lot harder to figure out. I’ve changed my mind on that recently though, and I think not only does grid give us better control in this type of situation, but it’s actually more intuitive as well.

Normally, when we use grid, we explicitly declare our columns using grid-template-columns. We don’t have to do that though. We can make it behave a lot like flexbox does by using grid-auto-flow: column.

.grid-container {   display: grid;   grid-auto-flow: column; }

Just like that, we end up with the same type of behavior as throwing display: flex on there. Like flex, the columns can potentially be unbalanced, but the advantage with grid is that the parent has total control over everything. So, rather than the content of the items having an impact like they would in flexbox, we only need one more line of code and we can solve the problem:

.grid-container {   display: grid;   grid-auto-flow: column;   grid-auto-columns: 1fr; }

I love that this is all on the parent selector, and that we don’t have to select the children to help get the layout that we are after!

The interesting thing here is how fr units work. They are literally called flex units in the spec, and they work just like flexbox does in dividing up space;. The big difference: they’re looking at the other tracks to determine how much space they have, paying no attention to the content inside those tracks.

That’s the real magic here. By declaring grid-auto-columns: 1fr, we are in essence saying, “by default, all my columns should have an equal width,” which is what we’ve been after from the start!

But what about at small screens?

What I love with this approach is we can keep it super simple:

.grid-container {   display: grid;   gap: 1em; }  @media (min-width: 35em) {   grid-auto-flow: column;   grid-auto-columns: 1fr; }

And just like that, it works perfectly. And by declaring display: grid from the start, we can include the gap to maintain equal spacing, whether the children are rows or columns.

I also find this to be a lot more intuitive than changing the flex-direction within a media query to get a similar result. As much as I love flexbox (and I really do still think it has great use cases), the fact that declaring flex-direction: column creates rows, and vice versa, is a little counter-intuitive at first glance.

And of course, if you prefer rolling without media queries, there is nothing stopping you from taking this to the next level with the help of auto-fit, which would be similar to setting something up with flex-wrap (though not exactly the same):

.grid-container {   display: grid;   gap: 1em;   grid-template-columns: repeat(auto-fit, minmax(10em, 25em)); }

Making it work with flexbox

I realize that we can get around this with flexbox by nesting the element with the padding on it. We’ve done this since we started making layouts using floats, and Bootstrap really hammered home this type of design pattern.

<div class="container">   <div class="row">     <div class="col"> <div class="">... </div>     <div class="col"> <div class="element-with-padding">...</div> </div>     <div class="col"> ... </div>   </div> </div>

And there is nothing wrong with that. It works! But floats work too, and we’ve stopped using them for layouts as better solutions have been released in recent years.

One of the reasons that I love grid is because we can simplify our markup quite a bit. Just like we ditched floats for a better solution, I’d at least like to people to keep an open mind that maybe, just maybe, grid could be a better, and more intuitive solution for this type of design pattern.

Flexbox still has it’s place, of course

I still love flexbox, but I think its real power comes from times that we want to rely on the intrinsic width of the flex items, such as with navigations, or groups of elements, such as buttons or other items of varying width that you want to go next to one another.

In those situations, that behavior is an asset that makes things like even spacing between unequal items such a breeze! Flexbox is wonderful, and I have no plans to stop using.

In other situations though, when you find yourself fighting with how flexbox is trying to work, maybe you could turn to grid instead, even if it’s not a typical “2d” grid where you’re told you should be using it for.

People often tell me that they struggle to figure out grid because it’s too complicated, and while it can be, as we saw here, it doesn’t have to be.


The post Equal Columns With Flexbox: It’s More Complicated Than You Might Think appeared first on CSS-Tricks.

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

CSS-Tricks

, , , , , , , ,
[Top]

It’s always the stacking context.

In “What the heck, z-index??,” Josh Comeau makes the analogy of layer groups in design software like Photoshop or Figma to stacking contexts in CSS. If you’ve got an element in a layer group A in Photoshop that is below layer group B, there is nothing you can do to push a child of A on top of anything in B, aside from moving the whole layer group A above B, or getting rid of the groupings.

Nothing is going to put that moustache on top of the dog unless you get it out of that stacking context or move the whole stacking context.

Here’s a reduced case:

There is no z-index value that is going to get “Big Thing” on top of the tan <main> element there. But as Josh notes in the article, there are a variety of solutions, such as preventing a stacking context from triggering unnecessarily, or doing a little DOM shuffling to make things work. Like in the example above, “Big Thing” doesn’t need to be a child of the header — and if it wasn’t, the stacking context wouldn’t be as relevant.

If you’re a fan of your tools helping you diagnose this kind of thing, read to the bottom of Josh’s article for a few interesting ones.

Direct Link to ArticlePermalink


The post It’s always the stacking context. appeared first on CSS-Tricks.

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

CSS-Tricks

, , ,
[Top]

It’s Always Year Zero

In the short term, opinions about technology often follow a compressed form of Laver’s Law:

  • Everything just before me was completely broken.
  • Everything that comes after me is completely unnecessary.
  • Everything I use right now is perfectly fine; stop changing things.

We tend to judge things based on where we started, our personal “Year Zeros.” But what’s “Year Zero” for us isn’t “Year Zero” for others. And in the fullness of time, the good ideas win out and hindsight judges them retrospectively obvious.

In 2020, I learned that it’s always Year Zero when it comes to building websites.

In “The Third Age of JavaScript” I speculated about a new wave of web developer tools enabled by the confluence of multiple trends:

In this framing, 2020 was Year Zero of the Third Age. But what happens in 2021? 2022? What makes me so sure that 2020 was some clear dividing line?

Nothing. There’s always room for innovation. New libraries, new frameworks, new build tools, even new languages. Yes, most of these will go nowhere, and yes, we swing back and forth a lot. But it’s the people who believe that web development isn’t done yet that make the future happen. Not those who play armchair quarterback, nor those who see everything in an odious light. I’d rather side with the people who believe it can be Year Zero than the people who believe Year Zero has passed.

“Year Zero” to me also means keeping a beginner’s mindset and constantly re-examining what I think I know. When I first learned web development, I was told that React was the best framework to build sites, Presentational and Container Components was the right way to do React, and that BEM was the right way to structure CSS. As a newcomer at Year Zero, I assumed that any discomfort I felt with the orthodoxy was my fault. Flash forward to this year and and my most popular articles are about Svelte and Tailwind questioning that conventional wisdom. No one gave me permission to do that. It took years to learn that I could dare to disagree with my mentors and give that permission to myself.

I feel this most of all for the newcomers to our industry. Every year there are about ~350k freeCodeCamp, ~100k university and ~35k bootcamp grads. It’s Year Zero for them. Or how about our end users — the millions of non-developers who every year have more of their world consumed by the buggy, slow software we make? It’s Year Zero for them.

It’s also Year Zero for web development in the broader arc of human history. The web is only 30 years old. We’ve had over 300 years refining modern physics, and yet there are still things we know we don’t know. It is such early days for the web.

Let’s stop pretending what we know is absolute truth and that what we have is the end state of things. It’s Always Year Zero.


The post It’s Always Year Zero appeared first on CSS-Tricks.

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

CSS-Tricks

, , ,
[Top]

It’s all relative.

I remember sitting in the back seat of our family’s Subaru station wagon. I was six and this was long before child carseats were a thing. My dad was at the wheel and my mom played 20 Questions with me while we drove to some vacation spot I can’t even remember.

It was my mom’s turn as she and I played 20 Questions. She had an object in mind and I was asking the questions.

“Is it big?” I asked.

“Relative to what?” my mom replied.

This was the pattern throughout the entire game. I asked a question and my mom answered with a question about relativity.

“You can ask questions when it’s my turn to think of an object,” I’d say.

“If you’re asking if the thing is as big as a mountain, the answer is no. But next to ant, yes, it is big.”

This year has been a long stretch of re-learning what it means to think relatively. How long of a stretch? It’s relative, I suppose. But as 2020 comes to a close, I can almost hear my mom asking me the same question, whether it’s at work or in my personal life.

“Relative to what?” she asks.


My mind jumps to relative units in CSS when I hear the word “relative.” I’m sure many of you are the same. I reach for things like em, rem and % all the time in my work. I only started using them to be cool when I first learned about them (whenever that was). I didn’t even know there was a real difference between em and rem. I thought they had something to do with retina screens.

Of course, that was a long time ago. (How long? It’s relative.) I now know that relative units are relative to the thing they reference. 2rem is going to evaluate one way on a site with a root font size of 16px and another for a site at 24px. Same deal with percentages. 50% inside a 400px container means something different than 50% inside a 1200px container.

So, now, when I find myself assigning size values to elements, I first having a little dialogue with my mom.

“This element is 5.25em.”

“Relative to what?” she asks.


I’ve also learned that thinking relatively requires a little perspective. And, no, this has nothing to do with CSS perspective (although I could probably try to make that connection). Thinking in relative terms means momentarily stepping out of your own shoes and seeing things from something else’s vantage point.

I say “something” because I think about this most when writing code. Whenever I’m working on the pieces of a component, I have to be mindful of the context—or perspective—of where they sit. Why? Because the pieces mean different things in different contexts and those contexts are relative to the component that contains them.

When is an <h2> just an <h2>? Hardly ever. It might be the post name. Or perhaps the heading for a widget. Maybe it’s the heading for a card component. As front-enders, we name those things according to the perspective of the component. From the perspective of a post, an <h2> means (and probably looks) something different from the perspective of, say, a card.

.post {} .post__title {}  .widget {} .widget__title {}  .card {} .card__title {}

Naming things is hard. I often find myself thinking, “Ack! What the heck should I call this thing?”

“Relative to what?” my mom interjects.


I could go on and on. The truth is that thinking in terms of relativity is just as important to the code we write as it is to a game of 20 Questions, or even our personal lives. And in a year where we’ve been upended by so many competing forces, thinking along these lines can offer solace and wisdom in the midst of what has been stressful and frustrating for many of us—relatively, of course.

  • “This is stressing me out.” Relative to what?
  • “I have so much to do.” Relative to when?
  • “I suck as JavaScript.” Relative to whom?
  • “I hate the place I work.” Relative to where?

It’s easy to get caught up in absolutes. Relativity forces us to see things differently.


The post It’s all relative. appeared first on CSS-Tricks.

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

CSS-Tricks

,
[Top]

Create Diagonal Layouts Like it’s 2020

Nils Binder covers the ways:

1. Use an SVG in the form of a triangle. This technique is nicely described by Erik Kennedy on CSS-Tricks.

2. Hide part of your section using clip-path. Read Diagonal Containers in CSS by Sebastiano Guerriero or Sloped edges with consistent angle in CSS by Kilian Valkhof.

3. Using CSS Transforms

I would normally be a #2 kinda guy — slice off the top and bottom a bit, make sure there is ample padding, and call it a day. But Nils almost has me convinced this fancy math is better.

Here’s a kinda dumb clip-path way:

And Nils incredibly fancy playground:

Direct Link to ArticlePermalink

The post Create Diagonal Layouts Like it’s 2020 appeared first on CSS-Tricks.

CSS-Tricks

, , , , ,
[Top]

PSA: It’s That Time to Update the Copyright Year on Your Site

Every year about this time I see articles going around reminding people how to update the copyright on their websites. Usually somewhere in the footer. You know, a line like:

© Copyright 2007-2019 CSS-Tricks

I am very absolutely not a lawyer, but this is how I understand it:

  • You don’t actually need that if your goal is copyrighting blog posts. Blog posts are copyrighted (in the United States) the second you publish them, with or without a copyright notice. You just can’t sue anybody over infringement unless you register the copyright.
  • People say it may “defer” infringements (but I don’t buy it).
  • People say it may win you greater settlements should you sue and win (but I wouldn’t even know where to begin fact-checking that).

Personally, I usually don’t bother with it, but don’t take that advice. I feel like it’s usually included for a bit of swagger like, “lookie how long we’ve been around.” In that same tune, if you’re doing it, it makes a lot of sense to keep it up to date because having the incorrect or an outdated date definitely makes your site look stale.

So, sure, rock your <?php echo date("Y"); ?> or whatever you need to do to keep it up to date. Just be careful: I just saw a site going around that recommended an inline JavaScript document.write() technique. That’s probably not the worst thing in the world since it’s just injecting a string, but it’s usually something to avoid for various reasons, and I’d way rather see you do it server-side or pre-rendered.

The post PSA: It’s That Time to Update the Copyright Year on Your Site appeared first on CSS-Tricks.

CSS-Tricks

, , , , ,
[Top]

It’s my job, and yours.

The role of ethics in our modern web space has been on my mind for the past few years and I suspect it will occupy my thoughts increasingly as I move forward. With each encounter of a questionable feature or setting on a website, I can’t help but think of all of the people involved and the discussions that may (or may not) have taken place.

Marketing has always straddled the line between promoting a product to an open and willing target audience and outright manipulating those who don’t need it (have you watched toy commercials with a young child lately?). For better or worse, persuasion in marketing has proven to be effective. Fortunately, it is fairly easy to spot an advertisement, even when disguised as sponsored content or product placement. This is what sets marketing apart from some of the more hidden aspects that are built into the apps and sites we use every day.

Many of the discussions surrounding design ethics are focused on privacy, data collection, and analysis by mega-companies and social networks. While there are many unsolved issues in this space, I hope we don’t limit our thoughts and conversations to these global apps. In fact, the smaller the product or company for which you are working, chances are the bigger impact you will have. With that in mind, let’s explore some ways we can be more mindful when creating our next product.

Research and Communication

Fundamental to the design and development of anything we publish is research and communication. Asking yourself or your team a series of questions may help facilitate important conversations and decisions. These may include:

  • Why are we creating this?
  • Who is most affected by this?
  • What outcomes should we consider?
  • Could we do better? How?
  • Could this cause harm?

While unintended consequences are unavoidable by nature, thinking through these questions upfront could help avoid negative impacts later.

Consider Your Team

A team of people with diverse backgrounds and life experiences can contribute to building a more thoughtful product. When creating something for a wide variety of people, it is best to include a wide variety of people throughout that build process. If your team is small (I was a team of 1 for many years), then try to do usability testing and research with people who don’t necessarily have your same background, interests, and career.

Consider Your Role

Ethics in design isn’t only about the things you create, but it is also carried out in the conversations you have. Informing your boss or client that the feature they requested isn’t ideal can be undesirable, but it is your responsibility to tell them why and what, if anything, could be done to make it better. It is almost always easier to complete a list of requests rather than explore options and present a case for why and how something else should be considered. You were hired for your expertise.

What’s Your Legacy?

While not everyone has the luxury of having their dream job or working on an ideal project, it is important for me to be able to look back at the end of the day and be proud of the work I have done. Is your work helping others? Are you creating something that makes this world a better place? If so, I’d love to hear more about it.

So, when asked what about building websites has you interested this year? the role of ethics in the design and development of the things we use every day weighs heavy on my thoughts.

Also, variable fonts.


If you are interested in learning more about Ethic in Design, here are some resources that I recommend:

The post It’s my job, and yours. appeared first on CSS-Tricks.

CSS-Tricks

,
[Top]

It’s All In the Head: Managing the Document Head of a React Powered Site With React Helmet

The document head might not be the most glamorous part of a website, but what goes into it is arguably just as important to the success of your website as its user interface. This is, after all, where you tell search engines about your website and integrate it with third-party applications like Facebook and Twitter, not to mention the assets, ranging from analytics libraries to stylesheets, that you load and initialize there.

A React application lives in the DOM node it was mounted to, and with this in mind, it is not at all obvious how to go about keeping the contents of the document head synchronized with your routes. One way might be to use the componentDidMount lifecycle method, like so:

componentDidMount() {   document.title = "Whatever you want it to be"; }

However, you are not just going to want to change the title of the document, you are also going to want to modify an array of meta and other tags, and it will not be long before you conclude that managing the contents of the document head in this manner gets tedious pretty quickly and prone to error, not to mention that the code you end up with will be anything but semantic. There clearly has to be a better way to keep the document head up to date with your React application. And as you might suspect given the subject matter of this tutorial, there is a simple and easy to use component called React Helmet, which was developed by and is maintained by the National Football League(!).

In this tutorial, we are going to explore a number of common use cases for React Helmet that range from setting the document title to adding a CSS class to the document body. Wait, the document body? Was this tutorial not supposed to be about how to work with the document head? Well, I have got good news for you: React Helmet also lets you work with the attributes of the <html> and <body> tags; and it goes without saying that we have to look into how to do that, too!

View Repo

One important caveat of this tutorial is that I am going to ask you to install Gatsby — a static site generator built on top of React — instead of Create React App. That’s because Gatsby supports server side rendering (SSR) out of the box, and if we truly want to leverage the full power of React Helmet, we will have to use SSR!

Why, you might ask yourself, is SSR important enough to justify the introduction of an entire framework in a tutorial that is about managing the document head of a React application? The answer lies in the fact that search engine and social media crawlers do a very poor job of crawling content that is generated through asynchronous JavaScript. That means, in the absence of SSR, it will not matter that the document head content is up to date with the React application, since Google will not know about it. Fortunately, as you will find out, getting started with Gatsby is no more complicated than getting started with Create React App. I feel quite confident in saying that if this is the first time you have encountered Gatsby, it will not be your last!

Getting started with Gatsby and React Helmet

As is often the case with tutorials like this, the first thing we will do is to install the dependencies that we will be working with.

Let us start by installing the Gatsby command line interface:

npm i -g gatsby-cli

While Gatsby’s starter library contains a plethora of projects that provide tons of built-in features, we are going to restrict ourselves to the most basic of these starter projects, namely the Gatsby Hello World project.

Run the following from your Terminal:

gatsby new my-hello-world-starter https://github.com/gatsbyjs/gatsby-starter-hello-world

my-hello-world-starter is the name of your project, so if you want to change it to something else, do so by all means!

Once you have installed the starter project, navigate into its root directory by running cd [name of your project]/ from the Terminal, and once there, run gatsby develop. Your site is now running at http://localhost:8000, and if you open and edit src/pages/index.js, you will notice that your site is updated instantaneously: Gatsby takes care of all our hot-reloading needs without us even having to think of — and much less touch — a webpack configuration file. Just like Create React App does! While I would recommend all JavaScript developers learn how to set up and configure a project with webpack for a granular understanding of how something works, it sure is nice to have all that webpack boilerplate abstracted away so that we can focus our energy on learning about React Helmet and Gatsby!

Next up, we are going to install React Helmet:

npm i --save react-helmet

After that, we need to install Gatsby Plugin React Helmet to enable server rendering of data added with React Helmet:

npm i --save gatsby-plugin-react-helmet

When you want to use a plugin with Gatsby, you always need to add it to the plugins array in the gatsby-config.js file, which is located at the root of the project directory. The Hello World starter project does not ship with any plugins, so we need to make this array ourselves, like so:

module.exports = {   plugins: [`gatsby-plugin-react-helmet`] }

Great! All of our dependencies are now in place, which means we can move on to the business end of things.

Our first foray with React Helmet

The first question that we need to answer is where React Helmet ought to live in the application. Since we are going to use React Helmet on all of our pages, it makes sense to nest it in a component together with the page header and footer components since they will also be used on every page of our website. This component will wrap the content on all of our pages. This type of component is commonly referred to as a “layout” component in React parlance.

In the src directory, create a new directory called components in which you create a file called layout.js. Once you have done this, copy and paste the code below into this file.

import React from "react" import Helmet from "react-helmet"  export default ({ children }) => (   <>     <Helmet>       <title>Cool</title>     </Helmet>     <div>       <header>         <h1></h1>         <nav>           <ul>           </ul>         </nav>         </header>       {children}       <footer>{`$  {new Date().getFullYear()} No Rights Whatsoever Reserved`}</footer>     </div>   </> )

Let’s break down that code.

First off, if you are new to React, you might be asking yourself what is up with the empty tags that wrap the React Helmet component and the header and footer elements. The answer is that React will go bananas and throw an error if you try to return multiple elements from a component, and for a long time, there was no choice but to nest elements in a parent element — commonly a div — which led to a distinctly unpleasant element inspector experience littered with divs that serve no purpose whatsoever. The empty tags, which are a shorthand way for declaring the Fragment component, were introduced to React as a solution to this problem. They let us return multiple elements from a component without adding unnecessary DOM bloat.

That was quite a detour, but if you are like me, you do not mind a healthy dose of code-related trivia. In any case, let us move on to the <Helmet> section of the code. As you are probably able to deduce from a cursory glance, we are setting the title of the document here, and we are doing it in exactly the same way we would in a plain HTML document; quite an improvement over the clunky recipe I typed up in the introduction to this tutorial! However, the title is hard coded, and we would like to be able to set it dynamically. Before we take a look at how to do that, we are going to put our fancy Layout component to use.

Head over to src/pages/ and open ìndex.js. Replace the existing code with this:

import React from "react" import Layout from "../components/layout"  export default () =>    <Layout>     <div>I live in a layout component, and life is pretty good here!</div>   </Layout>

That imports the Layout component to the application and provides the markup for it.

Making things dynamic

Hard coding things in React does not make much sense because one of the major selling points of React is that makes it’s easy to create reusable components that are customized by passing props to them. We would like to be able to use props to set the title of the document, of course, but what exactly do we want the title to look like? Normally, the document title starts with the name of the website, followed by a separator and ends with the name of the page you are on, like Website Name | Page Name or something similar. You are probably right, in thinking, we could use template literals for this, and right you are!

Let us say that we are creating a website for a company called Cars4All. In the code below, you will see that the Layout component now accepts a prop called pageTitle, and that the document title, which is now rendered with a template literal, uses it as a placeholder value. Setting the title of the document does not get any more difficult than that!

import React from "react" import Helmet from "react-helmet"  export default ({ pageTitle, children }) => (   <>     <Helmet>       <title>{`Cars4All | $  {pageTitle}`}</title>     </Helmet>     <div>       <header>         <h1>Cars4All</h1>         <nav>           <ul>           </ul>         </nav>         </header>       {children}       <footer>{`$  {new Date().getFullYear()} No Rights Whatsoever Reserved`}</footer>     </div>   </> )

Let us update ìndex.js accordingly by setting the pageTitle to “Home”:

import React from "react" import Layout from "../components/layout"  export default () =>    <Layout pageTitle="Home">     <div>I live in a layout component, and life is pretty good here!</div>   </Layout>

If you open http://localhost:8000 in the browser, you will see that the document title is now Cars4All | Home. Victory! However, as stated in the introduction, we will want to do more in the document head than set the title. For instance, we will probably want to include charset, description, keywords, author and viewport meta tags.

How would we go about doing that? The answer is exactly the same way we set the title of the document:

import React from "react" import Helmet from "react-helmet"  export default ({ pageMeta, children }) => (   <>     <Helmet>       <title>{`Cars4All | $  {pageMeta.title}`}</title>              {/* The charset, viewport and author meta tags will always have the same value, so we hard code them! */}       <meta charset="UTF-8" />       <meta name="viewport" content="width=device-width, initial-scale=1.0" />       <meta name="author" content="Bob Trustly" />        {/* The rest we set dynamically with props */}       <meta name="description" content={pageMeta.description} />              {/* We pass an array of keywords, and then we use the Array.join method to convert them to a string where each keyword is separated by a comma */}       <meta name="keywords" content={pageMeta.keywords.join(',')} />     </Helmet>     <div>       <header>         <h1>Cars4All</h1>         <nav>           <ul>           </ul>         </nav>         </header>       {children}       <footer>{`$  {new Date().getFullYear()} No Rights Whatsoever Reserved`}</footer>     </div>   </> )

As you may have noticed, the Layout component no longer accepts a pageTitle prop, but a pageMeta one instead, which is an object that encapsulates all the meta data on a page. You do not have to do bundle all the page data like this, but I am very averse to props bloat. If there is data with a common denominator, I will always encapsulate it like this. Regardless, let us update index.js with the relevant data:

import React from "react" import Layout from "../components/layout"  export default () =>    <Layout     pageMeta={{       title: "Home",       keywords: ["cars", "cheap", "deal"],       description: "Cars4All has a car for everybody! Our prices are the lowest, and the quality the best-est; we are all about having the cake and eating it, too!"     }}   >     <div>I live in a layout component, and life is pretty good here!</div>   </Layout>

If you open http://localhost:8000 again, fire up DevTools and dive into the document head, you will see that all of the meta tags we added are there. Regardless of whether you want to add more meta tags, a canonical URL or integrate your site with Facebook using the Open Graph Protocol, this is how you about about it. One thing that I feel is worth pointing out: if you need to add a script to the document head (maybe because you want to enhance the SEO of your website by including some structured data), then you have to render the script as a string within curly braces, like so:

<script type="application/ld+json">{` {   "@context": "http://schema.org",   "@type": "LocalBusiness",   "address": {   "@type": "PostalAddress",   "addressLocality": "Imbrium",   "addressRegion": "OH",   "postalCode":"11340",   "streetAddress": "987 Happy Avenue"   },   "description": "Cars4All has a car for everybody! Our prices are the lowest, and the quality the best-est; we are all about having the cake and eating it, too!",   "name": "Cars4All",   "telephone": "555",   "openingHours": "Mo,Tu,We,Th,Fr 09:00-17:00",   "geo": {   "@type": "GeoCoordinates",   "latitude": "40.75",   "longitude": "73.98"   }, 			   "sameAs" : ["http://www.facebook.com/your-profile",   "http://www.twitter.com/your-profile",   "http://plus.google.com/your-profile"] } `}</script>

For a complete reference of everything that you can put in the document head, check out Josh Buchea’s great overview.

The escape hatch

For whatever reason, you might have to overwrite a value that you have already set with React Helmet — what do you do then? The clever people behind React Helmet have thought of this particular use case and provided us with an escape hatch: values set in components that are further down the component tree always take precedence over values set in components that find themselves higher up in the component tree. By taking advantage of this, we can overwrite existing values.

Say we have a fictitious component that looks like this:

import React from "react" import Helmet from "react-helmet"  export default () => (   <>     <Helmet>       <title>The Titliest Title of Them All</title>     </Helmet>     <h2>I'm a component that serves no real purpose besides mucking about with the document title.</h2>   </> )

And then we want to include this component in ìndex.js page, like so:

import React from "react" import Layout from "../components/layout" import Fictitious from "../components/fictitious"  export default () =>    <Layout     pageMeta={{       title: "Home",       keywords: ["cars", "cheap", "deal"],       description: "Cars4All has a car for everybody! Our prices are the lowest, and the quality the best-est; we are all about having the cake and eating it, too!"     }}   >     <div>I live in a layout component, and life is pretty good here!</div>     <Fictitious />   </Layout>

Because the Fictitious component hangs out in the underworld of our component tree, it is able to hijack the document title and change it from “Home” to “The Titliest Title of Them All.” While I think it is a good thing that this escape hatch exists, I would caution against using it unless there really is no other way. If other developers pick up your code and have no knowledge of your Fictitious component and what it does, then they will probably suspect that the code is haunted, and we do not want to spook our fellow developers! After all, fighter jets do come with ejection seats, but that is not to say fighter pilots should use them just because they can.

Venturing outside of the document head

As mentioned earlier, we can also use React Helmet to change HTML and body attributes. For example, it’s always a good idea to declare the language of your website, which you do with the HTML lang attribute. That’s set with React Helmet like this:

<Helmet>    /* Setting the language of your page does not get more difficult than this! */   <html lang="en" />        /* Other React Helmet-y stuff...  */ </Helmet>

Now let us really tap into the power of React Helmet by letting the pageMeta prop of the Layout component accept a custom CSS class that is added to the document body. Thus far, our React Helmet work has been limited to one page, so we can really spice things up by creating another page for the Cars4All site and pass a custom CSS class with the Layout component’s pageMeta prop.

First, we need to modify our Layout component. Note that since our Cars4All website will now consist of more than one page, we need to make it possible for site visitors to navigate between these pages: Gatsby’s Link component to the rescue!

Using the Link component is no more difficult than setting its to prop to the name of the file that makes up the page you want to link to. So if we want to create a page for the cars sold by Cars4All and we name the page file cars.js, linking to it is no more difficult than typing out <Link to="/cars/">Our Cars</Link>. When you are on the Our Cars page, it should be possible to navigate back to the ìndex.js page, which we call Home. That means we need to add <Link to="/">Home</Link> to our navigation as well.

In the new Layout component code below, you can see that we are importing the Link component from Gatsby and that the previously empty unordered list in the head element is now populated with the links for our pages. The only thing left to do in the Layout component is add the following snippet:

<body className={pageMeta.customCssClass ? pageMeta.customCssClass : ''}/>

…to the <Helmet> code, which adds a CSS class to the document body if one has been passed with the pageMeta prop. Oh, and given that we are going to pass a CSS class, we do, of course, have to create one. Let’s head back to the src directory and create a new directory called css in which we create a file called main.css. Last, but not least, we have to import it into the Layout component, because otherwise our website will not know that it exists. Then add the following CSS to the file:

.slick {   background-color: yellow;   color: limegreen;   font-family: "Comic Sans MS", cursive, sans-serif; }

Now replace the code in src/components/layout.js with the new Layout code that we just discussed:

import React from "react" import Helmet from "react-helmet" import { Link } from "gatsby" import "../css/main.css"  export default ({ pageMeta, children }) => (   <>     <Helmet>       {/* Setting the language of your page does not get more difficult than this! */}       <html lang="en" />             {/* Add the customCssClass from our pageMeta prop to the document body */}            <body className={pageMeta.customCssClass ? pageMeta.customCssClass : ''}/>              <title>{`Cars4All | $  {pageMeta.title}`}</title>              {/* The charset, viewport and author meta tags will always have the same value, so we hard code them! */}       <meta charset="UTF-8" />       <meta name="viewport" content="width=device-width, initial-scale=1.0" />       <meta name="author" content="Bob Trustly" />        {/* The rest we set dynamically with props */}       <meta name="description" content={pageMeta.description} />              {/* We pass an array of keywords, and then we use the Array.join method to convert them to a string where each keyword is separated by a comma */}       <meta name="keywords" content={pageMeta.keywords.join(',')} />     </Helmet>     <div>       <header>         <h1>Cars4All</h1>         <nav>           <ul>             <li><Link to="/">Home</Link></li>             <li><Link to="/cars/">Our Cars</Link></li>           </ul>         </nav>         </header>       {children}       <footer>{`$  {new Date().getFullYear()} No Rights Whatsoever Reserved`}</footer>     </div>   </> )

We are only going to add a custom CSS class to the document body in the cars.js page, so there is no need to make any modifications to the ìndex.js page. In the src/pages/ directory, create a file called cars.js and add the code below to it.

import React from "react" import Layout from "../components/layout"  export default () =>    <Layout     pageMeta={{       title: "Our Cars",       keywords: <a href="">"toyota", "suv", "volvo"],       description: "We sell Toyotas, gas guzzlers and Volvos. If we don't have the car you would like, let us know and we will order it for you!!!",       customCssClass: "slick"     }}   >     <h2>Our Cars</h2>     <div>A car</div>     <div>Another car</div>     <div>Yet another car</div>     <div>Cars ad infinitum</div>   </Layout>

If you head on over to http://localhost:8000, you will see that you can now navigate between the pages. Moreover, when you land on the cars.js page, you will notice that something looks slightly off… Hmm, no wonder I call myself a web developer and not a web designer! Let’s open DevTools, toggle the document head and navigate back to the ìndex.js page. The content is updated when changing routes!

The icing on the cake

If you inspect the source of your pages, you might feel a tad bit cheated. I promised a SSR React website, but none of our React Helmet goodness can be found in the source.

What was the point of my foisting Gatsby on you, you might ask? Well, patience young padowan! Run gatsby build in Terminal from the root of the site, followed by gatsby serve.

Gatsby will tell you that the site is now running on http://localhost:9000. Dash over there and inspect the source of your pages again. Tadá, it’s all there! You now have a website that has all the advantages of a React SPA without giving up on SEO or integrating with third-party applications and what not. Gatsby is amazing, and it is my sincere hope that you will continue to explore what Gatsby has to offer.

On that note, happy coding!

The post It’s All In the Head: Managing the Document Head of a React Powered Site With React Helmet appeared first on CSS-Tricks.

CSS-Tricks

, , , , , , ,
[Top]

Tabs: It’s Complicated™

I’ve said before one quick and powerful thing you can learn as a front-end developer just getting starting with JavaScript is changing classes.

const button = document.querySelector(".my-button"); const element = document.querySelector(".content");  button.addEventListener("click", function() {   element.classList.toggle("sparkles"); });

We could use that skill to build some tabs, right? Right.

We got this.

Say we have this changing classes ability in our skillset now and we need to build a tabbed interface. If we just add a little more code that deals with click handlers, we could probably wire up some simple tabs, like this:

See the Pen
XQpqZV
by Chris Coyier (@chriscoyier)
on CodePen.

Totally functional tabs. I might pat myself on the back a little here. See how I used those anchor links to create jump links between the link and the tabbed section? That’s mighty semantic, don’t you think? The tabs are accessible with a keyboard, have focus styles, and can be activated with the Return key.

Did we win? Case closed? Perfect tabs?

Nothing is ever so easy, is it?

One issue here is that we didn’t do anything special with keyboard handling, which tabbed interfaces may require. Heydon Pickering wrote about this:

Unlike a same-page link, a tab does not move the user to the associated section/panel of content. It just reveals the content visually. This is advantageous to sighted users (including sighted screen reader users) who wish to flit between different sections without having to wade back up the page each time they want to choose a new one.

This comes with an unfortunate side effect: If the user wishes to move to a section by keyboard and interact with its internal content, they have to step through any tabs to the right of the current tab, which are in focus order.

Turns out there is a whole checklist of other behavioral things tabs interfaces can and should be doing. In Heydon’s explanation, the Tab key actually acts as a way to jump from the tab itself to the content related to that tab, actually moving the focus. Shift+Tab brings them back. Then the arrow keys are used to change tabs. All this requires more JavaScript and even some HTML to allow for the focus state… plus a sprinkle of aria-* attributes which I lack the expertise to explain you why they are important at all.

In the end, like this:

See the Pen
Tab Interface (PE)
by Heydon (@heydon)
on CodePen.

So the question becomes: are our class-changing skills actually a detriment to the web because they don’t account for things like this? Is doing things with whatever basic tools we have a net loss for web accessibility? I dunno. Too big of a question for my little brain. It’s interesting to consider, though.

Part of it comes down to muscle memory.

If we learn to code tabs like that first demo there, we’ll tend to reach for that over and over so long as nobody bites our fingers off for doing it. I coded that demo in about three minutes because I’ve done it so many times. Creating those tabs is certainly part of my muscle memory.

There is plenty of talk about JavaScript frameworks being a scourge across the web because they seem to be ushering in an era of worst-in-class accessibility. But what if your muscle memory for building tabs was reaching for a pre-built tabs UI that brings along all the right functionality and left styling largely to you?

That’s what Reach UI tabs are (which assumes we’re working with React…).

I’m not telling you to go out and switch your projects to React so you can get some free tabs, but React is already massive. If good patterns like this become the defacto choice, then it’s possible that the effect is a net gain on accessibility. Seems possible to me, anyway. It might just stop me from poorly hand-coding a tabbed interface for the 359th time.

The post Tabs: It’s Complicated™ appeared first on CSS-Tricks.

CSS-Tricks

, ,
[Top]