That Time I Tried Browsing the Web Without CSS

CSS is what gives every website its design. Websites sure aren’t very fun and friendly without it! I’ve read about somebody going a week without JavaScript and how the experience resulted in websites that were faster, though certain aspects of them would not function as expected.

But CSS. Turning off CSS while browsing the web wouldn’t exactly make the web far less usable… right? Or, like JavaScript, would some features not work as expected? Out of curiosity, I decided to give it a whirl and rip the CSS flesh off the HTML skeleton while browsing a few sites.

Why, you might ask? Are there any non-masochistic reasons for turning off CSS? Heydon Pickering once tweeted that disabling CSS is a good way to check some accessibility standards:

  1. Common elements like headings, lists, and form controls are semantic and still look good.
  2. A visual hierarchy is still established with default styles.
  3. The content can still be read in a logical order.
  4. Images still exist as <img> tags rather than getting lost as CSS backgrounds.

A WebAIM survey from 2018 reported that 12.5% of users who rely on any sort of assisted technology browse the web with custom stylesheets, which can include doing away with every CSS declaration across a site. And, if we’re talking about slow internet connections, ditching CSS could be one way to consume content faster. There’s also the chance that CSS is disabled for reasons outside our immediate control, like when a server has hiccups of fails to load assets.

As an experiment, I used five websites and a web app without CSS, and this post will cover my experiences. It wound up being a rather eye-opening adventure for me personally, but has also informed me professionally as a developer in ways I hope you’ll see as well.

But first, here’s how to disable CSS

You’re absolutely welcome to live vicariously through me in the form of this post. But for those of you who are feeling up to the task and want to experience a style-less web, here’s how to disable CSS in various browsers:

  • Chrome: There’s actually no setting in Chrome to disable CSS, so we have to resort to an extension, like disable-HTML.
  • Firefox: View > Page Style > No Style
  • Safari: Safari > Preferences... > Show Develop menu in menu bar. Then go to the Develop dropdown and select the “Disable Styles” option.
  • Opera: Like Chrome, we need an extension, and Web Developer fits the bill.
  • Internet Explorer 11: View > Style > No style

I couldn’t find a documented way to disable CSS in Edge, but we can remove CSS from it and any other browser programmatically via the CSS Object Model API in the DevTools console:

var d = document; for (var s in S = d.styleSheets) S[s].disabled = true; for (var i in I = d.querySelectorAll("[style]")) I[i].style = "";

The first loop disables all external and internal styles (in <link> and <style>), and the second eliminates any inline styles. The caveat here, however, is that elements can still dynamically be given new inline styles. To instantly erase them, the best workaround is adding a timer. Something like this:

(f = function(){ // Remove CSS ... setTimeout(f, 20);
})();

Alternatively, there are text-only browsers — such as the ancient Lynx — but expect to be living without video, images (including SVGs), and JavaScript.

Through the style-less looking glass…

For each site I surfed without CSS — Amazon, DuckDuckGo, GitHub, Stack Overflow, Wikipedia and contrast checker called Hex Naw — I’ll share my first impressions and put some suggestions out there that might help with the experience.

Get ready, because things might get a bit… appalling. 😱


Website 1: Amazon.com
The Amazon.com homepage with and without CSS
The Amazon.com homepage with CSS (left) and without CSS (right).

There’s no real need for an introduction here. Not only is Amazon a household staple for so many of us, it also powers a huge chunk of the web, thanks to their ubiquitous Amazon Web Services platform.

There’s a vast number of things going on here, so I’ll explore the style-less stuff that gets in my path while finding a product and pretending to purchase it.

The Amazon.com results for a “mac mini” search query
The Amazon.com results for a “mac mini” search query.

On the homepage, I immediately see a sprite sheet used by the site. It’s really in place of where the logo could be, thus making it tough to know whether or not those images are intended to be there. Each sprite contains multiple versions of the logo, and even if I could see the “Amazon” word mark in it, it’s surprisingly that it’s not the global home link. If you’re curious where the home link really is, it’s this structure of spans where the logo is served up as background image… in CSS:

<a href="/ref=nav_logo" class="nav-logo-link" aria-label="Amazon" tabindex="6"> <span class="nav-sprite nav-logo-base"></span> <span class="nav-sprite nav-logo-ext"></span> <span class="nav-sprite nav-logo-locale"></span>
</a>

The next problem that arises is that the “Skip to main content” link doesn’t look like a typical skip link, yet it works like one. It turns out to be an <a> element without an href, and JavaScript (yes, I did leave that enabled) is used to mimic anchor functionality.

When I start a search, I have to look further below the “Get started” link to see the suggestions. Under the “Your Lists” and “Your Account” items, it becomes difficult to tell the links apart. They appear all strung together as if they were one super long mega link. I believe it would have been more effective to use a semantic unordered list in this scenario to maintain a sense of hierarchy.

Under all those search suggestions, however, the account and navigation links are easier to read since they’re separated by some space.

Interestingly, the carousel lower down the page is still somewhat functional. If I click the “Previous page” or “Next page” options, the order of the images is changed. However, hopping between those options required me to scroll.

A split view of the carousel on the amazon.com homepage. First is initial state, second shows previous page on top, and third shows next page on top.
The carousel appears with its pages stack on top of another. The previous or next page shows up on top.

Skipping down a bit further, there’s an advertisement element. It contains an “Ad feedback” string that looks static just like what we saw with the “Skip to main content” link earlier. Well, I clicked it anyway and it revealed a form for sharing feedback on the advertisement relevance.

Blue curvy arrow showing destination to ad feedback form when clicking Ad Feedback text under ad
To make the call to action clearer, “Ad feedback” should be a link or button.

You may have missed it, but there’s a blank button above the two groups of form labels and the radios buttons are out of place. The structure is confusing because I don’t know which labels belong to which radio buttons. I mean, I guess I could assume that the first label goes with the first radio input, but that’s exactly what it is: a guess.

What’s also confusing is that there are Submit buttons between the “Close Window,” “Cancel,” and “Send Feedback” options at the bottom of the form. If I press any of these, I’m taken back to the ad. Now, suppose I were blind and using a screen reader to navigate this same part, even with the presence of CSS. I would be told “Submit, button” for two of the buttons and would therefore have zero clue what to do without guessing. It’s another good reminder about the importance of semantics when handling markup (button labels in this case) and being mindful of how much reliance is placed on JavaScript to override web defaults.

Doing a search — let’s say for “Mac Minis” — I can still access and understand the product ratings since they are displayed as text (instead of the tooltips they are otherwise) in place of stars. This is a good example of using a solid textual fallback when an image is used as visual content, but is served as a background image in CSS.

Messy results page displaying sponsored products on top of normal products
The page required me to scroll a while to get to the actual search results. Notice that ginormous overlay of a sponsored product.

Having chosen the Mac Mini with Intel Core i3, I’m greeted by other Mac products above the product I’ve selected and have to navigate beyond them to select the quantity I want to purchase.

Part of product page showing Amazon Prime membership info
The product page displays Amazon Prime membership info slapped between the quantity selection and purchase buttons.

Scroll down, and an “Add to Cart” button is displayed next to a label bearing the same content. That’s redundant and probably unnecessary since a <button> element is capable of holding its own label:

<button>Add to Cart</button>

Next up, we have an offer for an Amazon Prime membership. That’s all fine and dandy, but notice that it’s inserted between the product I’m purchasing and the “Buy Now” button. I have a really hard time knowing whether clicking “Buy Now” is going to add the Mac Mini to checkout, or whether I’m purchasing Amazon Prime instead.

I also wanted to play around a bit, so I tried removing the Mac Mini from my cart once I figured out how to add it. It took me like ten seconds to locate the cart so I could edit it. Turns out it was directly next to “Proceed to checkout (1 item)” link but rams right up alongside it so it all looks like a single link.

Part of shopping cart page showing a Mac Mini added, Cart and Proceed to Checkout links together, and gift card offer with cost after deduction

Overall, it wasn’t difficult to find a product. On the other hand, the path to checkout became more of a headache as I proceeded. There was some poor semantic- and accessibility-related practices that caused confusion, and important buttons and links became more difficult to find.

👍 What the Site Does Well 💡 What the Site Can Improve
Carousels are functional even without styling. The logo relies on a background image, obscuring the path back home.
The content hierarchy is still generally helpful for knowing where we are on a page. Many links and anchors rely on JavaScript and do not appear to be interactive.
The order of elements remains roughly in tact. Links often bump up against each other or are placed outside where they would be relevant.
Great use of fallbacks for product rating that rely on background images. Button labels are either misleading or repetitive.
Form elements fail to align themselves properly.
There’s a rough journey to check out.
Website 2: DuckDuckGo
The DuckDuckGo homepage with and without CSS
The DuckDuckGo homepage with CSS (left) and without CSS (right).

Have you used DuckDuckGo before? I assume many folks reading CSS-Tricks have, but for those who may be hearing of it for the first time, it’s an alternative to Google search with an emphasis on user privacy.

So, getting started with this is a little misleading because the DuckDuckGo homepage is super simple. Not much can go wrong there, right? Well, it’s a little more involved than that since we’re dealing with search results, content hierarchy and relevance once we get into making search queries.

Top of DuckDuckGo homepage

Right off the bat, what I’m greeted with is a lot more content than I would have expected for such a simple lander. At it’s not totally clear what website this is by scanning the website. The first mention of the product name is the fourth item in the first unordered list and it’s a call to action to “Spread DuckDuckGo.” The logo is totally missing, which obviously means it’s used as a background… in CSS.

Speaking of that unordered list, I assume what I’m seeing belongs in the header, and there’s no skip navigation. We have a triple arrow icon (is that a mobile menu or a menu to hide the least important items, or something else?), followed by privacy-related content, social media links, something that looks like one link but is actually two links for “About DuckDuckGo” and “Learn More.”

Finally, toward the very bottom is where the primary use case for the site actually comes up: the search bar. I assume the “S” label means “Search” and the “X” label is shorthand to clear the search field.

Alright, onto performing a search. It’s super cool that I can still see auto-suggestions and use the up and down arrow keys to highlight each one. Clearing the field though, the suggestions don’t disappear until after I refresh the page.

Performing a search and checking out the auto-suggestions
Performing a search and checking out the auto-suggestions.

Everything in the Settings menu are items in a list including what should be headings — “Settings,” “Privacy Essentials,” “Why Privacy,” “Who We Are,” and “Keep in Touch.” These are very likely part of a mobile men if CSS was enabled, perhaps triggered by that triple arrow link thing at the top. In that menu, I see four blank bullet points between “Settings” and “More Themes.”

Orange arrows pointing to run-on links, unclear button labels, and empty list items
The DuckDuckGo homepage exposed a few glaring usability issues right off the bat.

Coming here as a new user, I have no idea what those empty list items are, but the bullets I highlighted in the screenshot above are actually the theme buttons. To clarify the intent, some fallback text would be helpful, and these should be radio or normal buttons instead of list items (considering their functionality).

Every block of content with an “X” — including the “Settings” — cannot be dismissed; however, clicking the “X” above an image of a hiker image does cause a chunk of content to clear off the screen — thanks to JavaScript still being enabled. What I really find awkward is the redundant numeration in the ordered list under “Switch to DuckDuckGo…” We see this:

1. 1We don’t store your personal info
2. 2We don’t follow you around with ads
3. 3We don’t track you. Ever.

Looks like some mixed use case of semantic markup with some other way to display list item numbers.

Clicking each X to find that only the third has functionality
The third “X” down has functionality.

There’s a colossal amount of white space under the hiker image until the first <h1> element. Assuming they’re either links or buttons, clicking every instance of “Add DuckDuckGo to [browser]” does nothing. Each section’s illustration causes some unnecessary horizontal scrolling, which is a common issue we’ll see in the other sites we look at.

Scrolling through white space between hiker image and first-level heading
Scrolling through white space between hiker image and first-level heading. Wheee!

After those sections, there’s a blank box and I have no idea what it is.

A blank box at the bottom of the page
A blank box that appears to have no purpose.

I cracked open DevTools and it turns out to be a <body> element in an <iframe> that holds only JavaScript for something related to POST requests. It might as well be one of those elements we should leave alone.

Following that, I see two repeated instances of “Set as Default Search Engine” wrapped around a “Set as Homepage” section.

Instructions in Safari to set the search engine as your default or your homepage
The instructions in Safari to set the search engine as your default or your homepage. Instructions may differ from one browser to another.

These must have been the instructions that popped up when I clicked the “Add DuckDuckGo…” actions, but it shows the impact hiding and showing content can have when we’re dealing with straight markup. Instead of repeating content, the corresponding links or buttons should point to one instance. That would cut the redundancy here.

OK, time to finally get into search. The first thing I see in the search results is an empty box with an instruction to ignore the box. Okey-dokey then.

Orange arrow pointing at a tiny box on the search results page saying “Sure, OK.”
DuckDuckGo wants me to ignore a box.

Moving on, did you see that DuckDuckGo link? That must be the logo, and I wonder why this was not on the homepage. Seems like low-hanging fruit for improvement.

The search bar still functions normally with the exception of the “S” and “X” buttons that have swapped places from where they were on the homepage.

Onto the search results. I could easily distinguish one result from another. What I found quite unnecessary, yet funny, is that the “Your browser indicates if you’ve visited this link” messaging that’s located at the end of each page title. That would be super annoying from a screen reading perspective. Imagine hearing that repeated at the end of every page title. That messaging is there to be displayed alongside checkmarks that contain tooltips that hold that messaging. But, with CSS disabled, well, no checkmarks and no tooltips. As a result, all I get is an extra long heading.

Comparison of search results page with and without CSS. Extra text appears next to titles in the non-CSS version.
Search results on DuckDuckGo are still well structured with CSS disabled, but notice the messaging that is appended to each result title.

The navigation bar that is normally displayed as tabs to filter by different types of results (e.g. Images) seems to do nothing at this point because it’s hard to tell that they are filters without styling. But if I click on the Images filter, the image results are actually loaded lower down onto the page, piled right on top of the Web results, and the page becomes mega long as a result. Oh, and you might think that scrolling all the way back up (and it’s a long way up) then clicking another filter, say Videos, would replace the images, but that simply inserts video thumbnail images below the images making an already mega long page a super mega long page. Imagine the page weight of all those assets!

Well, you don’t have to. According to DevTools, images alone account for 831 requests and a total weight of 23.7 MB. Hefty!

Orange outline box encircling feedback on requests and total image weight in DevTools
The real kicker is that it’s not immediately clear that all those images have loaded visually.

The last couple of items are worth noting. Clicking the “Send feedback” link apparently does nothing. Maybe that triggered a modal with CSS? And, although the “All Regions” link does not resemble a link and I could’ve easily ignored it, I was curious enough to click it and was taken to an anchor point of a list of countries. The last two links just made their corresponding contents appear under the list country options.

Blue arrow showing destination to list of regions after clicking All Regions
The “All Regions” option is secretly acting as an anchor.

There’s a lot going on here and there are clearly opportunities for improvement. For example, there are calls to action that display as normal text that should be either be links or buttons instead. Also, we’d think the performance of a site would get better with CSS disabled, but all those loaded assets in the search results are prohibitive. That said, the search experience isn’t painful at all… that is, unless you’re digging into images or videos while doing it.

👍 What the Site Does Well 💡 What the Site Can Improve
Search is consistent and works with or without CSS. A “skip” link for would help with keyboard browsing.
The content hierarchy makes content easy to read and search results a clean experience. Non-link items in the “Settings” menu should be headings for separate unordered lists so there is a clear hierarchy for how the options are grouped.
Good use of a homepage link at the top of the search results page. Some content is either duplicated or repeated because the site relies on conditionally showing and hiding content.
Make sure that all calls to action render as links instead of plain text.
Use a fallback solution to filter the types of search results to prevent items stacking and help control hefty page weight.
Website 3: GitHub
The GitHub homepage with and without CSS
The GitHub homepage with CSS (left) and without CSS (right).

Hey, here’s a site many of us are well familiar with! Well, many of us are used to being logged into it all the time, but I’m going to surf it while logged out.

Already, there’s a skip link (yay). There’s also a mobile navigation icon that I expect will do nothing, and am proven right when I try.

Wide gap after Why GitHub? dropdown
That big gap of white? It’s an SVG icon with a white fill, according to DevTools.

Between some of the navigation items, there are unnecessarily giant gaps. If you click on these, they still function as dropdown menus. They are <details> and <summary> elements… but something feels semantically wrong. It is nice that the menu items are actually unordered list items and that native browser functionality can still take place by using a semantic way to expand content. But that SVG icon messes with me.

Before typing anything into the field, I see three instances of “Search All GitHub” and “Jump to” links. I have no idea which to click, but if I do a search, the keyword shows up in the third group.

Orange outline boxes around groups of search links
There is no clear connection between the search input and the three groups of links.

Everything else on the homepage seems fine except for a number of overly large images horizontally overflowing the window.

Scrolling down to see large images overflowing the browser window
Scrolling down to see large images overflowing the browser window.

Let’s go back to the search bar and navigate to any repo we can find. Right under the Search button, we have two nearly identical secondary navigation bars that return the repository counts, code, commits, and other meta. Without looking at the source, I have no clue what the purpose is for having two of these.

Search results for a “javascript tips” query.
Search results for a “javascript tips” query.

Repository pages still have an easy-to-follow structure and a logical hierarchy for the most part. While logged out and having my cache cleared before coming, the “Dismiss” button for the “Join GitHub today” block still performs as I’d expect. Like we saw earlier on Amazon, the tag links are difficult to tell apart because they run together as a single line.

A repository page in a logged out state.

The next two buttons — “JavaScript” and “New Pull Request” — don’t seem to do anything when I click them. I’d imagine the pull request button should be disabled while viewing as a guest since, unless it’s intended to take a user to a log in screen first… but even that doesn’t feel right. Turns out that the button is indeed disabled when CSS is active, though. Then the rest of the page is fairly easy to understand.

If you’re here mainly for managing, contributing to, or checking out repositories, you won’t face a whole lot of friction since the hierarchy plays out well. You’ll experience pretty much the same elsewhere, whether you’re looking at pull requests, issues, or individual files. Most of the hurdles live in less prominent pages on the site.

👍 What the Site Does Well 💡 What the Site Can Improve
The hierarchy and structure of many pages are really easy to follow and make logical sense. Use the height and width attributes on <img> elements and SVGs to prevent them from blowing up.
Most of the SVG icons embedded on the page are appropriately sized. Watch for empty list items.
Nice use of a skip link in the header. Ensure that button labels use full words.
Make sure links have whitespace or line breaks between them to prevent run-ons.
Website 4: Hex Naw
The Hex Naw tool with and without CSS
The Hex Naw homepage with CSS (left) and without CSS (right).

This next site is an online tool I use often to check color contrasts for accessibility. And for a site that is so big on color, there’ s probably a lot happening here with CSS, so it should get interesting.

There’s immediately a large amount of space above the navigation and no skip links. The hamburger and close buttons for the mobile layout and “X” buttons next to each color to test are oversized.

Scrolling to find missing skip links and excessive space above the navigtion
We’re missing skip links and there is excessive space above the navigation.

Oh, and check out this giant gap between the “Test Colors” button and the next section of content.

Scrolling to show large gap between Test Colors button and “yeah” and “naw” counters
It would be nice to close this gap so the “yeah” and “naw” counters are visible in the test.

One of the many nice features of this site is a checkbox that allows you to see only the colors that passed the test, rather than viewing all of the tested colors. Unfortunately, that button does nothing with CSS disabled. However, I can still see which colors work and get the definitions for contrast ratio, large text, and small text directly in the result table.

Test result section showing “Show passing colors” checked, legend for C, L, and S letters, table of results, and feedback for all failed colors

Hiding and showing the terms is probably what the button does with CSS. The bummer is that I won’t know the purpose of those single letters (e.g. S and R) after the table headers. It’s also both ironic and confusing to see that message for all failing colors after the table because, well, there are passing colors in this list. What could be done is have hide it by default but conditionally inject it later if all the colors in a single test fail.

Pulling out DevTools, it turns out some of the white space at the top is the Hex Naw logo as a SVG file. The space above that is associated with other SVG symbols used for the page. By using a default color of black for the logo, this would help reduce some of the space. I made that quick change in DevTools and it makes a noticeable difference.

Hex Naw logo colored black and highlighted in DevTools
The size of the mobile menu and “X” icons can easily be reduced and be proportional to their viewBox attributes.
The menu and X icons given a width and height of 44 pixels using the attributes
Here’s one way to reduce the size of the mobile menu and “X” icons.

The second gap of space is caused by an SVG loader that appears while calculating color contrasts. This could be helped by specifying a much smaller, yet proportional, width and height exactly like the mobile menu and “X” icons.

SVG loader icon resized to 25px by 25px
I was able to reveal and resize the SVG loader icon in DevTools.

Adding an initial width and height to each SVG would definitely reduce the need to scroll. This is also what we can do to fix the gaps we saw in GitHub’s navigation as well.

Ultimately, Hex Naw remains pretty useful without CSS. I can still test colors, get passing and failing color results, and navigate around the page. It’s just too bad I wasn’t able to work with actual colors and had to work around those extra large SVG icons.

👍 What the Site Does Well 💡 What the Site Can Improve
The site maintains good content hierarchy throughout the site. SVGs should be use a fallback fill color and use the height and width attributes.
All of the elements are written semantically. Feedback for all failing colors could be dynamically added and removed to prevent awkward messaging.
The tests themselves function properly with the exception of being able to show or hide information. Consider an alternative way to display color for the values being tested, like table cells with the background color attribute.
Website 5: Stack Overflow
The Stack Overflow homepage with and without CSS
The Stack Overflow homepage with CSS (left) and without CSS (right).

Like GitHub, Stack Overflow is one of those resources that many (if not most) of us keep in our back pocket because it helps find whether someone has already asked a development question and the answers to them.

On the page to ask a question, I see a bunch of blank bullet points above the main <textarea> element. I have no idea why those empty list items are there. I don’t see any of the formatting buttons either, but after messing around a bit, I found that they happen to be nothing more than blank list items. Perhaps fallback text or an SVG icon for each item would help identify what these are and do. They should be turned into real buttons as well.

It’s also still possible to get a list of similar questions while entering text into the title field. Every works here as expected, which is nice. Although, it is strange that the vote counts for each suggested question appears twice, once above the title as a link and again next to the title without being linked.

The “Ask a Question” page showing blank bullets and questions that may already have an answer. Strong tag tooltip is displayed for one of the bullets.
The “Ask a Question” page has a little awkward formatting, but the overall functionality is in tact and the page is relatively easy to navigate.

One of the key elements we all look for when landing on a Stack Overflow question page is that big green checkmark that indicates the correct answer out of all the submitted answers. But with CSS turned off, it’s hard to tell which answer was accepted because each answer in the list has a black checkmark. Even if the accepted answer is always at the top, there’s still no alternative or fallback indication without having to interact with the page. Additionally, there’s no indication if you have already up voted or down voted the question or any of the answers.

Answered question with black checkmarks next to an accepted answer and other answers
The question (left) next to the list of provided answers (right). We lose a lot of hierarchy when styles are taken away.

To sum up my experience on Stack Overflow, I was able to accomplish what I normally come to the site for: finding answers to a programming problem. That said, there were indeed a few opportunities for improvement and this site is a prime example of how design often relies on color to indicate hierarchy or value on a page, which was sorely missing from the question pages in this experiment.

👍 What the Site Does Well 💡 What the Site Can Improve
Almost every element is written semantically. Use clear controls to identify editing tools while asking or answering questions.
SVG icons use the width and height attributes. Consider a visual icon to distinguish the accepted answer from any other answers to a question.
Lists of answers are clear and easy to scan. Consider a different method to indicate an up vote or a down vote besides color alone.
Website 6: Wikipedia
The Wikipedia homepage with and without CSS
The Wikipedia homepage with CSS (left) and without CSS (right).

Wikipedia, the web’s primary point of reference! It’s an online staple and one of its appealing qualities is a sort of lack of design. This should make for an interesting test.

A few links down, we have a skip navigation option for the real navigation and search. The homepage header containing the globe image maintains its two column layout, and you may have guessed why: this is a table layout. While it may not be a usability issue, we know it isn’t semantic to rely on tables to create a layout. That was a relic of the way past when we didn’t have floats, flexbox, grid or any other way to handle content placement. That said, there are no noticeable usability issues or confusing elements on the page.

Let’s move on to what many of us spend the most time on in Wikipedia: an article entry. This is often the entry point to Wikipedia, especially for those of us that start by typing something into a search engine, then click on the Wikipedia search result.

Top of Wikipedia article
Notice how similar the style-less page is to the styled page, even though it becomes a single column.

The bottom line is that this page is still extremely usable and hierarchical with CSS disabled. The layout goes down to a single column, but the content still flows in a logical order and even maintains bits of styling, thanks again to a reliance on tables and inline table properties.

One issue I bumped up against is the navigation. There is a “Jump to navigation” link in the header which indeed drops me down to the navigation when I click it. In case you’re wondering, the navigation is contained in the footer, which is the reason for needing to jump to it.

Navigation menu with stranded checkboxes above “Variants” and “More”
Navigation menu with stranded checkboxes above “Variants” and “More.”

There are seemingly random checkboxes above a couple of the navigation headings (specifically for “Variants” and “More”) and they appear to serve no purpose, although the checkbox above “More” becomes displays at a certain viewport width when CSS is enabled.

There actually is one odd thing in the navigation, and it’s a label-less button between the “In other projects” and “Languages” headings.

Part of navigation showing blank button with “Language settings” tooltip and some of the languages
Hovering over the button provides a hint that it’s for language settings, but the button should at least have a title to make that clear up front.

Clicking that button, I’m still able to access the language settings, and it mostly works as expected. For example, the layout maintains a tabbed layout which is super functional.

The CSS-less possibility of switching back and forth between Display and Input tabs

In the Display tab, however, the “Language” and “Fonts” buttons do nothing. They probably are tabs as well, but at least I can see what they offer. Beside those buttons are two empty select menus that do absolutely nothing (the first one does become populated with ComicNeue, OpenDyslexic, and System font options when you check the checkbox). Looking at the “Input” tab, the writing language buttons still happen to function as tabs. I’m still able to select options other than English, Spanish, and Chinese.

Blue arrow pointing out the jump to a list of languages at the top of the page when pressing the [...] button
Pressing the […] button takes me to a list of languages at the top of the page.

The articles aren’t difficult to read at all without CSS and that’s because nearly every element is semantically correct and follows a consistent document hierarchy. One thing I did wonder was where the “Show/Hide” button that’s normally in the table of contents went. It turns out to be a lone checkbox, and the label is fake — it uses the content property on a pseudo-element in CSS to display the label.

Another issue in articles is that you have to spend time hunting images down when previewing them. Normally, clicking an image in the article sidebar will trigger a full-screen modal that contains a carousel of images. Without CSS, that carousel is gone and, in its place, is the image with a row of unlabeled buttons above it. That’s a bummer, but would be perfectly OK if the carousel wasn’t all the way down the page, opposite of where the clicked image is at the top of the page without an ability to jump down to it.

Orange arrow pointing to blank buttons above carousel, which are the controls
The image carousel is no longer contained in a modal, but at the end of the page.

I’d be careless if I didn’t mention that the Wikipedia logo was nowhere to be found on the article! It’s not even a white SVG on white. The link contains actually nothing:

<a class="mw-wiki-logo" href="/wiki/Main_Page" title="Visit the main page"></a>

Thankfully, the “Main page” link under “Navigation” is the another way back home without pressing the browser Back button. But, still feels odd to have no branding on the page when it does such a great job of it on the homepage.

Wikipedia’s HTML issues exist mostly in features I expect to be less often used rather than articles. They never hampered my reading experience in the long run.

👍 What the Site Does Well 💡 What the Site Can Improve
The site maintains a clean structure and hierarchy. The logo placement could be moved (or added, in some cases) to the top of the page without a CSS background image.
Skip links are used effectively for search and navigation. Buttons should include labels.
The article content is semantic and easy to read. The image carousel on pages could load where the trigger occurs and use proper button labels for the controls.

Ways to make CSS-less a better experience

CSS is a key component to the modern web. As we’ve seen up to this point, there are a number of sites that become next to un-unusable without it — and we’re counting some of the most recognizable and used sites in that mix. What we’ve seen is that, at best, the primary purpose for a site can still be accomplished, but there are hurdles along the way. Things like:

  • missing or semantically incorrect skip links
  • links that run together
  • oversized images that require additional scrolling
  • empty elements, like list items and button labels

Let’s see if we can compile these into a sort of list of best practices to consider for situations where CSS might be disabled or even unavailable.

Include a skip navigation link at the top of the document

Having a hidden link to skip the navigation is a must. Notice how most of the sites we looked at contained navigation links directly in the header. With CSS turned off, those navigations became long lists of links that would be so hard to tab or scroll through for any user. Having a link to skip that would make that experience much better.

The most basic HTML example I’ve seen is an anchor link that targets an ID where the main content begins.

<a href="#main">Skip to main content</a>
<!-- etc. -->
<main id="main"></main>

And, of course, we can throw a class name on that link to hide it visually so it is not displayed in the UI but still available for both keyboard users and when CSS happens to be off.

.skip-navigation { border: 0; clip: rect(1px, 1px, 1px, 1px); overflow: hidden; padding: 0; position: absolute; height: 1px; width: 1px;
} /* Bonus points for adding :focus styles */
Leave whitespaces where they make sense

Another pain point we saw in a few cases were text links running together. Whether it was in the navigation, tags, or other linked up meta, we often saw links that were “glued together” in such a way that several individual links appeared to be one giant link. That’s either the result of hand-coding the links like that or an automated build task that compresses HTML and removes whitespaces in the process. Either way, the HTML winds up like this:

<a href="#">CSS</a><a href="#">JavaScript</a><a href="#">Python</a><a href="#">Swift</a>

We can keep the freedom to use spaces or line breaks though, even with CSS disabled. One idea is to lean on flexbox for positioning list elements when CSS is enabled. When CSS is disabled, the list items should stack vertically and display as list items by default.

If the items are tags and should still be separated, then traditional spacing methods like margins and padding are still great and we can rely on natural line breaks in the HTML to help with the style-less formatting. For example, here are line breaks in the HTML used to separate items, flexbox to remove spaces, then styled up in CSS to re-separated the items:

See the Pen
Handling Links in HTML Separated by Spaces or Line Breaks
by Jon Kantner (@jkantner)
on CodePen.

Use width and height attributes liberally

The biggest nuisance in this experiment may have been images exploding on the screen to the point that they dominate the content, take up an inordinate amount of space, and result in a hefty amount of scrolling for all users.

The fix here is rather straightforward because we have HTML attributes waiting for us to define them. Both images and SVG have methods for explicitly defining their width and height.

<img src="/path/to-image.jpg" width="40" height="40" /> <svg width="40px" height="40px" viewBox="0 0 200 200"> <polygon points="80,0 120,0 120,80 200,80 200,120 120,120 120,200 80,200 80,120 0,120 0,80 80,80" />
</svg>
Prepare SVGs for a white background

Many of the large gaps on the sites we looked at looked like empty space, but they were really white SVGs that blew up to full size and blended into the white background.

So, yes, using the proper width and height attributes is a good idea to prevent monstrous icons, but we can also do something about that white-on-white situation. Using properties like fill and fill-rule as attributes will work here.

<!-- Icon will be red by default -->
<svg viewBox="-241 243 16 16" width="100px" fill="#ff0000"> <path d="M-229.2,244c-1.7,0-3.1,1.4-3.8,2.8c-0.7-1.4-2.1-2.8-3.8-2.8c-2.3,0-4.2,1.9-4.2,4.2c0,4.7,4.8,6,8,10.6 c3.1-4.6,8-6.1,8-10.6C-225,245.9-226.9,244-229.2,244L-229.2,244z"/>
</svg>
/* ...and it’s still red when CSS is enabled */
svg { fill: #ff0000;
}

See the Pen
Define SVG Width Attribute
by Geoff Graham (@geoffgraham)
on CodePen.

Label those buttons!

Lastly, if buttons are initially empty, they need to have visible fallback content. If they use a background image and a title for what the do, use a span containing the title text then add aria-hidden="true" so it doesn’t sound like the screen reader is reading the button label twice (e.g. VoiceOver says, “Add button Add” instead).

<button class="btn-icon" title="Add"> <span class="btn-label" aria-hidden="true">Add</span>
</button>

Then the CSS can be something like this:

.btn-icon { background: url(path/to/icon.svg) 0 0 / 100% 100%; height: 40px; width: 40px;
} .btn-label { display: block; overflow: hidden; height: 0;
}

If there are <li> elements acting as buttons, they can remain, but they should be static, and the contents should be placed in a button.

Now, if the icon is an SVG, we can ensure the title tooltip can still be seen by using aria-labelledby and assigning the id to the title.

<button> <svg width="40px" height="40px" viewBox="0 0 200 200" aria-labelledby="btn-title"> <title id="btn-title">Add</title> <polygon points="80,0 120,0 120,80 200,80 200,120 120,120 120,200 80,200 80,120 0,120 0,80 80,80" /> </svg>
</button>

Conclusion

It can be easy to either forget or be afraid to check how a site appears when CSS isn’t available to make the UI look as good as intended. After a brief tour of the Non-CSS Web™, we saw just how important CSS is to the overall design and experience of sites, both small and large.

And, like any tool we have in our set, leaning too heavily on CSS to handle the functionality and behavior of elements can lead to poor experiences when it’s not around to do its magic. We’ve seen the same be true of sites that lean too heavily on JavaScript. This isn’t to say that we should not use them and rely on them, but to remember that they are not bulletproof on their own and need proper fallbacks to ensure an optimal experience is still available with or without our tooling.

Seen in that light, CSS is really a layer of progressive enhancement. The hierarchy, form controls, and other elements should also remain intact under their user agent styles. The look and feel, while important, is second when it comes to making sure elements are functional at their core.

The post That Time I Tried Browsing the Web Without CSS appeared first on CSS-Tricks.

Could Grouping HTML Classes Make Them More Readable?

You can have multiple classes on an HTML element:

<div class="module p-2"></div>

Nothing incorrect or invalid there at all. It has two classes. In CSS, both of these will apply:

.module { }
.p-2 { }
const div = document.querySelector("div");
console.log(div.classList.contains("module")); // true
console.log(div.classList.contains("p-3")); // false

But what about grouping them? All we have here is a space-separated string. Maybe that’s fine. But maybe we can make things more clear!

Years ago, Harry Roberts talked about grouping them. He wrapped groups of classes in square brackets:

<div class="[ foo foo--bar ] [ baz baz--foo ]">

The example class names above are totally abstract just to demonstrate the grouping. Imagine they are like primary names and variations as one group, then utility classes as another group:

<header class="[ site-header site-header-large ] [ mb-10 p-15 ]">

Those square brackets? Meaningless. Those are there to visually represent the groups to us developers. Technically, they are also classes, so if some sadist wrote .[ {}, it would do stuff in your CSS. But that’s so unlikely that, hopefully, the clarity from the groups outweighs it and is more helpful.

That example above groups the primary name and a variation in one group and some example utility classes in another group.

I’m not necessarily recommending that approach. They are simply groups of classes that you might have.

Here’s the same style of grouping, with different groups:

<button class="[ link-button ] [ font-base text-xs color-primary ] [ js-trigger ]" type="button" hidden>

That example has a single primary name, utility classes with different naming styles, and a third group for JavaScript specific selectors.

Harry wound up shunning this approach a few years ago, saying that the look of it was just too weird for the variety of people and teams he worked with. It caused enough confusion that the benefits of grouped classes weren’t worth it. He suggested line breaks instead:

<div class="media media--large testimonial testimonial--main"> 

That seems similarly clear to me. The line breaks in HTML are totally fine. Plus, the browser will have no trouble with that and JSX is generally written with lots of line breaks in HTML anyway because of how much extra stuff is plopped onto elements in there, like event handlers and props.

Perhaps we combine the ideas of line breaks as separators and identified groups… with emojis!

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

Weird, but fun. Emojis are totally valid there. Like the square brackets, they could also do things if someone wrote a class name for them, but that’s generally unlikely and something for a team to talk about.

Another thing I’ve seen used is data-* attributes for groups instead of classes, like…

<div class="primary-name" data-js="js-hook-1 js-hook-2" data-utilities="padding-large"
>

You can still select and style based on attributes in both CSS and JavaScript, so it’s functional, though slightly less convenient because of the awkward selectors like [data-js="js-hook-1"] and lack of convenient APIs like classList.

How about you? Do you have any other clever ideas for class name groups?

The post Could Grouping HTML Classes Make Them More Readable? appeared first on CSS-Tricks.

Using Artificial Intelligence to Generate Alt Text on Images

Web developers and content editors alike often forget or ignore one of the most important parts of making a website accessible and SEO performant: image alt​ text. You know, that seemingly small image attribute that describes an image:

​​​<img src="/cute/sloth/image.jpg" alt="A brown baby sloth staring straight into the camera with a tongue sticking out." >

A brown baby sloth staring straight into the camera with a tongue sticking out.
📷 Credit: Huffington Post

If you regularly publish content on the web, then you know it can be tedious trying to come up with descriptive text. Sure, 5-10 images is doable. But what if we are talking about hundreds or thousands of images? Do you have the resources for that?

Let’s look at some possibilities for automatically generating alt text for images with the use of computer vision and image recognition services from the likes Google, IBM, and Microsoft. They have the resources!

Reminder: What is alt text good for?

Often overlooked during web development and content entry, the alt​ attribute is a small bit of HTML code that describes an image that appears on a page. It’s so inconspicuous that it may not appear to have any impact on the average user, but it has very important uses indeed:

  • ​​Web Accessibility for Screen Readers: Imagine a page with lots of images and not a single one contains alt​ text. A user surfing in using a screen reader would only hear the word “image” blurted out and that’s not very helpful. Great, there’s an image, but what is it? Including alt​ enables screen readers to help the visually impaired “see” what’s there and have a better understanding of the content of the page. They say a picture is worth a thousand words — that’s a thousand words of context a user could be missing.
  • Display text if an image does not load: The World Wide Web seems infallible and, like New York City, that it never sleeps, but flaky and faulty connections are a real thing and, if that happens, well, images tend not to load properly and “break.” Alt text is a safeguard in that it displays on the page in place of where the “broken” image is, providing users with content as a fallback.
  • ​​SEO performance: Alt text on images contributes to SEO performance as well. Though it doesn’t exactly help a site or page skyrocket to the top of the search results, it is one factor to keep in mind for SEO performance.

Knowing how important these things are, hopefully you’ll be able to include proper alt​ text during development and content entry. But are your archives in good shape? Trying to come up with a detailed description for a large backlog of images can be a daunting task, especially if you’re working on tight deadlines or have to squeeze it in between other projects.

What if there was a way to apply alt​ text as an image is uploaded? And! What if there was a way to check the page for missing alt​ tags and automagically fill them in for us?

There are available solutions!

Computer vision (or image recognition) has actually been offered for quite some time now. Companies like Google, IBM and Microsoft have their own APIs publicly available so that developers can tap into those capabilities and use them to identify images as well as the content in them.

There are developers who have already utilized these services and created their own plugins to generate alt​ text. Take Sarah Drasner’s generator, for example, which demonstrates how Azure’s Computer Vision API can be used to create alt​ text for any image via upload or URL. Pretty awesome!

​​See the Pen
​​Dynamically Generated Alt Text with Azure's Computer Vision API
by Sarah Drasner (@sdras)
​​on CodePen.
​​

There’s also Automatic Alternative Text by Jacob Peattie, which is a WordPress plugin that uses the same Computer Vision API. It’s basically an addition to the workflow that allows the user to upload an image and generated alt​ text automatically.

​​Tools like these generally help speed-up the process of content management, editing and maintenance. Even the effort of thinking of a descriptive text has been minimized and passed to the machine!

Getting Your Hands Dirty With AI

I have managed to have played around with a few AI services and am confident in saying that Microsoft Azure’s Computer Vision produces the best results. The services offered by Google and IBM certainly have their perks and can still identify images and proper results, but Microsoft’s is so good and so accurate that it’s not worth settling for something else, at least in my opinion.

Creating your own image recognition plugin is pretty straightforward. First, head down to Microsoft Azure Computer Vision. You’ll need to login or create an account in order to grab an API key for the plugin.

Once you’re on the dashboard, search and select Computer Vision and fill in the necessary details.

Starting out

Wait for the platform to finish spinning up an instance of your computer vision. The API keys for development will be available once it’s done.

​​Keys: Also known as the Subscription Key in the official documentation

Let the interesting and tricky parts begin! I will be using vanilla JavaScript for the sake of demonstration. For other languages, you can check out the documentation. Below is a straight-up copy and paste of the code and you can use to replace the placeholders.

​​var request = new XMLHttpRequest();
request.open('POST', 'https://[LOCATION]/vision/v1.0/describe?maxCandidates=1&language=en', true);
request.setRequestHeader('Content-Type', 'application/json');
request.setRequestHeader('Ocp-Apim-Subscription-Key', '[SUBSCRIPTION_KEY]');
request.send(JSON.stringify({ "url": "[IMAGE_URL]" }));
request.onload = function () { var resp = request.responseText; if (request.status >= 200 && request.status < 400) { // Success! console.log('Success!'); } else { // We reached our target server, but it returned an error console.error('Error!'); } console.log(JSON.parse(resp));
}; request.onerror = function (e) { console.log(e);
};

Alright, let’s run through some key terminology of the AI service.

  • Location: This is the subscription location of the service that was selected prior to getting the subscription keys. If you can’t remember the location for some reason, you can go to the Overview screen and find it under Endpoint.
  • ​​

Overview > Endpoint : To get the location value
  • ​​Subscription Key: This is the key that unlocks the service for our plugin use and can be obtained under Keys. There’s two of them, but it doesn’t really matter which one is used.
  • ​​Image URL: This is the path for the image that’s getting the alt​ text. Take note that the images that are sent to the API must meet specific requirements:
    • File type must be JPEG, PNG, GIF, BMP
    • ​File size must be less than 4MB
    • ​​Dimensions should be greater than 50px by 50px

Easy peasy

​​Thanks to big companies opening their services and API to developers, it’s now relatively easy for anyone to utilize computer vision. As a simple demonstration, I uploaded the image below to Microsoft Azure’s Computer Vision API.

Possible alt​ text: a hand holding a cellphone

​​The service returned the following details:

​​{ "description": { "tags": [ "person", "holding", "cellphone", "phone", "hand", "screen", "looking", "camera", "small", "held", "someone", "man", "using", "orange", "display", "blue" ], "captions": [ { "text": "a hand holding a cellphone", "confidence": 0.9583763512737793 } ] }, "requestId": "31084ce4-94fe-4776-bb31-448d9b83c730", "metadata": { "width": 920, "height": 613, "format": "Jpeg" }
}

​​From there, you could pick out the alt​ text that could be potentially used for an image. How you build upon this capability is your business:

  • ​​You could create a CMS plugin and add it to the content workflow, where the alt​ text is generated when an image is uploaded and saved in the CMS.
  • ​​You could write a JavaScript plugin that adds alt​ text on-the-fly, after an image has been loaded with notably missing alt​ text.
  • ​​You could author a browser extension that adds alt​ text to images on any website when it finds images with it missing.
  • ​​You could write code that scours your existing database or repo of content for any missing alt​ text and updates them or opens pull requests for suggested changes.

​​Take note that these services are not 100% accurate. They do sometimes return a low confidence rating and a description that is not at all aligned with the subject matter. But, these platforms are constantly learning and improving. After all, Rome wasn’t built in a day.

The post Using Artificial Intelligence to Generate Alt Text on Images appeared first on CSS-Tricks.

Why don’t we add a `lovely` element to HTML?

<person>, <subhead>, <location>, <logo>… It’s not hard to come up with a list of HTML elements that you think would be useful. So, why don’t we?

Bruce Lawson has a look. The conclusion is largely that we don’t really need to and perhaps shouldn’t.

By my count, we now have 124 HTML elements, many of which are unknown to many web authors, or regularly confused with each other—for example, the difference between <article> and <section>. This suggests to me that the cognitive load of learning all these different elements is getting too much.

Direct Link to ArticlePermalink

The post Why don’t we add a `lovely` element to HTML? appeared first on CSS-Tricks.

HTML elements, unite! The Voltron-like powers of combining elements.

Guides, resources and discussions about Semantic HTML are often focused around specific elements, like a heading, or a sectioning element, or a list. It’s not often that we talk specifically about how we can combine HTML elements to increase their effectiveness.

Normally, when we introduce HTML, we talk about how it is used to apply meaning to content in a document, and we do this by using examples like:

  • “Is it a paragraph?”
  • “Is it a heading?”
  • “Is it a numbered list”
  • “Is it a button”

We use these examples because they are easy to understand — it’s a single piece or chunk of the same content that needs to be represented in a particular way. This is useful, but it only scratches the surface of how we can use and combine elements to provide more context and meaning.

You remember Voltron, right? Each member of the Voltron force was powerful in their own right, but it was when they combined together to form a towering figure that their mighty powers became unstoppable.

The same is true of HTML elements. I have a few favorite combinations that I’ll take you through. They may seem obscure, but you’d be surprised at how often they come up when you take the time to think outside of divs and spans.

Abbreviations and Definitions

<abbr> and <dfn> are two of my favorite HTML elements. I particularly like them because they work really well together.

You can combine the abbreviation and definition elements to allow browsers, search bots, and other technologies to recognize that something is being defined and that the acronym is associated to that phrase.

<p> The <dfn><abbr title="International Good Dog Association">IGDA</abbr></dfn> is an international, not-for-profit organization responsible for determining that all dogs are good.
</p>

In the above example, I’m defining that the acronym “IGDA” as “International Good Dogs Association.” I do this by wrapping the acronym in an <abbr> element with a title attribute defining the full name. By adding the <dfn> element around the abbreviation, it indicates that the surrounding paragraph defines the term “International Good Dogs Association.”

The <abbr> element is useful because it can tell screen readers what they should read, while also providing a useful visual representation in the form of a tooltip explaining what the abbreviation is.

Visual representation of <abbr> and <dfn>.

Keyboard, Sample and Variable

If you haven’t heard of these elements, then get ready to have your socks blown off, because they are awesome.

First up, the <kbd> element is used to represent text for a textual user input (e.g. from a keyboard). You can also nest multiple <kbd> elements to represent multiple keystrokes. I love this because, as developers, we find ourselves (hopefully) writing documentation, blog posts, and guides on a regular basis and HTML provides us with native ways to represent this content straight out of the box!

If I wanted to tell someone how you copy and paste with the keyboard, I could mark it up like the code below.

<p>I like to <kbd><kbd>Ctrl</kbd>+<kbd>C</kbd></kbd> and <kbd><kbd>Ctrl</kbd>+<kbd>V</kbd></kbd> a lot.</p>

It looks a bit nuts but the above code, when rendered, looks like the following without any styling applied to it. If you are wondering why kbd is nested inside another kbd element, what this does is specify that the key or input is part of a larger input. Even more combined superpowers!

See the Pen rZpNPy by CSS-Tricks (@css-tricks) on CodePen.

You can further target the <kbd> elements with CSS to make it look more like little keyboard controls. (Note: Browsers tend to render this by default with a monospace font.)

See the Pen gdoOqE by CSS-Tricks (@css-tricks) on CodePen.

If you’re wondering what the difference is between using <kbd> versus a span, I believe it comes down to information. I will repeat this sentiment a lot: we do not know how someone is going to consume our HTML, so give your content it’s best chance by representing it in the most meaningful and contextual way possible. If you are still not on board, then please go read my post about HTML as told by TypeScript.

The <samp> element is really cool because you can nest it inside the <kbd> element and vice versa. WHAT? I know, so versatile! Let’s have a look at some examples from MDN.

The following code is an example of nesting a <samp> element inside a <kbd> element. This is used to mark up content that represents input based on the text displayed by the system (e.g. button names).

<p>To save the image file, select <kbd><kbd><samp>File</samp></kbd> - <kbd><samp>Save as...</samp></kbd></kbd>.
</p>

See the Pen YOYzbJ by CSS-Tricks (@css-tricks) on CodePen.

In the above code, we define our keyboard shortcuts the same as our previous example, but we also determine that the menu and menu item names (contained within both <kbd> and <samp>) are an input selected from something displayed by the system, e.g. a dialog or widget.

In other words, this piece of text is a message from the system which has some user inputs that you need to follow (like File and Save as…).

Whereas, when we nest <kbd> inside <samp>, we determine that the input has been echoed back to the user by the system.

<p><samp>yarn start:theproject does not exist, did you mean:</p>
<blockquote><samp><kbd>yarn start:the-project</kbd></samp></blockquote>

Finally, the <var> element! This is used to mark up the name of a variable in math or programming, for example:

<var>E</var> = <var>m</var><var>c</var><sup>2</sup>.
<samp>Error: <var>console<var> is undefined.</samp>

Here you can start to see how combining <var> with other elements like <pre>, <code>, <kbd> or <samp> starts to make your content’s markup more explicit by adding more context. Anything that interprets your HTML markup can start to derive more meaning from the elements you are using rather than just assuming that it’s all standard text.

If you put this content in a paragraph with some spans, there is no way for technology to distinguish this from any other old text on your page. You don’t have to resort to <span> or a <div> to represent this content because HTML already provides us with more semantically accurate elements we can use. HTML is not just about presentation; it’s about meaning. Various technologies outside of visual rendering engines rely on this meaning to make decisions about how to communicate our content in the most meaningful way (e.g. screen readers, text to voice, reading apps, bots, or the next big thing in the future).

Figures

Figures (<figure>) are a great example of a power combination element. Unfortunately, I think it is widely misused and under appreciated (much like <aside>, which I could talk about for hours). The obvious combination you are probably familiar with is using <figure> and <figcaption> together. We often use this duo to represent graphical content like images, illustrations and diagrams — but it can also be used for things like code, poems and quotes!

Because a figure is so flexible in what kind of content it represents, there are a bunch of different HTML elements you can use within a figure to provide more context around the type of content you are putting in your page.

Figcaption

The <figure> element is often seen with an optional <figcaption> which represents a caption or legend for a figure. It should be the first child or last child of the <figure> element. You can also use any flow content (e.g. paragraphs, headings, etc.) in the <figcaption> to provide more context and you can have multiple images inside a <figure> represented by a single <figcaption>.

<figure> <img src="jello.jpg" alt="Golden Retriever Puppy" /> <figcaption>Jello the Golden Retriever enjoying being carried home.</figcaption>
</figure>

Preformatted Text

The <pre> element is used to display preformatted text or code and is usually rendered using a monospace font. While <pre> can be used on its own, it can also be combined with <figure> and <figcaption>. By doing this, the content inside the <pre> element becomes more accessible to assistive technologies, like screen readers, since it allows us to use <figcaption> as a label for the text or code.

We can go even further by combining the <pre> and <code> elements to identify the pre- formatted content as code.

See the Pen QVaWVW by CSS-Tricks (@css-tricks) on CodePen.

Because <code> is considered flow content, it can also be used inside a <figcaption> to mark up inline references to code (i.e. a single phrase or line).

Cite and Blockquote

Quotations are something I use a lot and it honestly didn’t occur to me it could be used as part of a figure. But it still makes sense to use cite or quotation if the content they contain is relevant to the overall content, even if it is not part of the main document flow.

I like the example of using a figure for poems, mainly so I could share the amazing poem I wrote about my dog. Here I use the <cite> element inside the <figcaption>:

<figure> <p> Jello - A little fluffy dog. Hello! Squishy Jello - you little fluffy fellow. BOUNCY yellow Jello. A very mellow fellow. EATING MY MARSHMALLOW. </p> <figcaption><cite>Eating my Marshmallow by Mandy Michael</figcaption>
</figure>

It’s easy to fall into the trap of thinking that the figure element is just for images or image-like content, but you can use it for content like audio, video, charts, poems, quotations or even tables of statistics. Because the element is so versatile you can combine it with so many other elements to provide more and more context about the figure for assistive technology, browsers, and other technologies consuming your website.

Wrapping Up

These are just some of the ways HTML elements can be combined for better context. HTML elements are indeed useful and valuable on their own when used as isolated pieces — and using them this way is a good first step. But, like Voltron, when you combine HTML elements together, the individual pieces form a greater whole and gain much more meaning and power. It’s important that we don’t think of HTML as individual pieces of code, but parts of a whole because HTML is really a mass of totally amazing combinations.

You can combine and use HTML elements in any number of ways to best represent your content. Don’t simply stick to the same old things you know; take the time to explore HTML and learn about all it has to offer. Like any language, we should make the most of it and use it to its full potential.

The more accurate you are in marking up your content, the better that content will be represented across technologies, and the more prepared it will be for any anything else that is used to interpret your HTML in the future.

So, go forth and HTML elements, unite!


Resources

In my opinion, the best resource for learning and understanding how to use HTML (outside of the spec itself) is the MDN Web Docs. It lists all the HTML elements you could ever need.

The following are among the elements covered in this post:

  • <abbr>
  • <cite>
  • <code>
  • <dfn>
  • <figure>
  • <figcaption>
  • <kbd>
  • <samp>
  • <var>

If you are a TypeScript fan and don’t understand why Semantic HTML is important, I wrote this post just for you: Understanding why Semantic HTML is important as told by TypeScript.

The post HTML elements, unite! The Voltron-like powers of combining elements. appeared first on CSS-Tricks.

Introducing Trashy.css

It began, as many things do, with a silly conversation. In this case, I was talking with our Front End Technology Competency Director (aka “boss man”) Mundi Morgado.

It went something like this…

Mundi Morgado I want you to build a visual screen reader.

Nathan Smith Who what now?

Mundi Morgado I want a CSS library that allows you to see the structure of a document. It shouldn’t use class so that you’re forced to focus on semantics. Also, make it theme-able.

Nathan Smith Sure, let me see what I can come up with.

Fast-forward a week, and we’ve got what we are now calling:

Trashy.css: The throwaway CSS library with no class

Why throwaway? Well, it’s not really meant to be a fully fledged, production-ready style framework. Rather, it’s like training wheels for document semantics, with some bumper lanes (think: bowling) to keep you on the right track.

It’s part of our ongoing effort at TandemSeven to promote code literacy throughout our organization. As more of our UX designers are beginning to share responsibility for the accessibility and semantics of a project, it makes sense that we would build in such a way that allows UX and development to be more collaborative.

There are four main aspects to Trashy.

Trashy: “Basic”

First is the base trashy.css file, which applies a passably basic look and feel to the majority of common HTML elements. Check out this example of a basic page.

Trashy: “Boxes”

Second, there is trashy.boxes.css. This visually distinguishes otherwise invisible semantic elements, such as: header, main, nav, etc. That way, one can see where those elements are (or aren’t) as a page is being authored. Here’s a page with semantic boxes outlined.

Trashy: “Theme”

Thirdly, theming is possible via trashy.theme.css. This is mostly just an example — inspired by PaperCSS) — of how to make UI look “hand drawn,” to prevent observers from being too fixated on the look and feel, rather than the semantics of a document. Here’s the example theme in action.

Trashy: “Debug”

Lastly, there is a trashy.debug.css file that highlights and calls out invalid and/or problematic markup. Here’s a gnarly example of “everything” going wrong on a single HTML page. This was inspired by a11y.css, though it diverges in what is considered noteworthy.

For instance, we call out “div-itis” when multiple div:only-child have been nested within one another. We’re also opinionated about type="checkbox" being contained inside of a <label>. This is for maximum click-ability within an otherwise dead whitespace gap, between a checkbox (or radio) and its textual label.

Any or all of these CSS files can be applied individually or in conjunction with one another. There is also a bookmarklet (labeled “GET TRASHY!”) on the Trashy home page you can use to get results for any webpage.

The bookmarklet will remotely pull in:

  • sanitize.css
  • trashy.css
  • trashy.boxes.css
  • trashy.debug.css

Our “reset” – Sanitize.css

A quick word on Santitize.css: It was created by my coworker Jonathan Neal (author of Normalize.css), as a way to have a semi-opinionated CSS “reset.” Meaning, it puts in a lot of defaults that we find ourselves writing as developers anyway, so it makes for a good starting point.

Technically speaking

Okay, so now that we’ve covered the “why,” let’s dig into the “how.”

Basically, it all revolves around using (abusing?) the ::before and ::after pseudo elements. For instance, to show the name of a block level tag, we’re using this CSS.

Semantic tags (using ::before)

Here is an abbreviated version of the trashy.boxes.css file, for succinctness. It causes the <section> tag to have a dashed border, and to have its tag named displayed the top left corner.

section { border: 1px dashed #f0f; display: block; margin-bottom: 2rem; /* 20px. */ padding: 2rem; /* 20px. */ position: relative;
} section > :last-child { margin-bottom: 0;
} section::before { background: #fff; color: #f0f; content: "section"; font-family: "Courier", monospace; font-size: 1rem; /* 10px. */ letter-spacing: 0.1rem; /* 1px. */ line-height: 1.3; text-transform: uppercase; position: absolute; top: 0; left: 0.3rem; /* 3px. */
}

Warning messages (using ::after)

Likewise, here’s a snippet of code from the trashy.debug.css file that drives the markup warning messages. This particular example causes <script> tags to be displayed, which may be further optimized or need the developer’s attention: inline JavaScript and/or external src without async.

In the case of inline JS, we set the font-size and line-height to 0 because we’re making the element visible. We yank the text off the page via text-indent: -99999px just to make sure it doesn’t show up. We wouldn’t want that random JS code displayed alongside legit page content.

(Please don’t ever do this for “real” content. It’s just a hack, mkay?)

To get our error message to show up though, we have to set the font-size and line-height back to non-zero values, and remove our text-indent. Then, with a bit more absolute positioning, we ensure the message is visible. This lets us see, amidst the rest of the page content, whereabouts to check (via DOM inspector) for the <script> insertion point.

script:not([src]),
script[src]:not([async]),
script[src^="http:"] { color: transparent; display: block; font-size: 0; height: 2rem; /* 20px. */ line-height: 0; margin-bottom: 2rem; /* 20px. */ position: relative; text-indent: -99999px; width: 100%;
} script:not([src])::after,
script[src]:not([async])::after,
script[src^="http:"]::after { background: #f00; color: #fff; display: inline-block; font-family: Verdana, sans-serif; font-size: 1.1rem; /* 11px. */ font-weight: normal; left: 0; line-height: 1.5; padding-left: 0.5rem; /* 5px. */ padding-right: 0.5rem; /* 5px. */ pointer-events: none; position: absolute; text-decoration: none; text-indent: 0; top: 100%; white-space: nowrap; z-index: 1;
} body script:not([src])::after,
body script[src]:not([async])::after,
body script[src^="http:"]::after { top: 0;
} script:not([src])::after { content: 'Move inline <script> to external *.js file' ;
} script[src]:not([async])::after { content: 'Consider [async] for <script> with [src="…"]' ;
} script[src]:not([src=""]):not([async])::after { content: 'Consider [async] for <script> with [src="' attr(src) '"]' ;
} script[src^="http:"]::after { content: 'Consider "https:" for <script> with [src="' attr(src) '"]' ;
}

Note: Some scripts do need to be loaded synchronously. You wouldn’t want your “app” code to load before your “framework” code. Heck, some inline JS is probably fine too, especially if you’re doing some super speed optimization for the critical rendering path. These warnings are “dumb” in the sense that they match only via CSS selectors. Take ‘em with a grain of salt, your mileage may vary, etc.

JS bookmarklet

The aforementioned JS bookmarklet finds all <link rel="stylesheet"> and <style> tags in the page, and causes them to be ineffective. This allows us to add in our own CSS to take over, so that the only styles applied are those provided directly via Trashy.

The magic is accomplished by setting rel="stylesheet" to rel="". If an external stylesheet is not identified as such, even if it’s cached, the browser will not apply its styles to the page. Similarly, we destroy the contents of any inline <style> tags by setting the innerHTML to an empty string.

This leaves us with the tags themselves still intact, because we still want to validate that no <link> or <style> tags are present within <body>.

We also check that there aren’t too many <style> tags being used in the <head>. We allow for one, since it could be used for the critical rendering path. If there’s a build process to generate a page with consolidated inline styles, then it’s likely they’re being emitted through a single tag.

<a href="javascript:( function (d) { var f = Array.prototype.forEach; var linkTags = d.querySelectorAll('[rel=\'stylesheet\']'); var styleTags = d.querySelectorAll('style'); f.call(linkTags, function (x) { x.rel = ''; }); f.call(styleTags, function (x) { x.innerHTML = ''; }); var newLink = d.createElement('link'); newLink.rel = 'stylesheet'; newLink.href = 'https://t7.github.io/trashy.css/css/bookmarklet.css'; d.head.appendChild(newLink); }
)(document);"> GET TRASHY!
</a>

Go forth, get Trashy!

Get Trashy

That pretty much covers it. It’s a simple drop-in to help you visualize your document semantics and debug possibly problematic markup.

I have also found it to be super fun to use. A quick click of the bookmarklet on any given site usually yields lots of things that could be improved upon.

For instance, here’s what CNN’s site looks like with Trashy applied…

P.S. Call security!

If you try this with Twitter’s site, you might wonder why it doesn’t work. We were initially perplexed by this, too. It has to do with the site’s Content Security Policy (CSP). This can be used to disallow CSS and/or JavaScript from being loaded externally, and can whitelist safe domains.

This can be set either at the server level, or by a <meta> tag in the <head>.

<meta http-equiv="Content-Security-Policy" content="…" />

Read more about CSP here.

I know what you’re thinking…

Can’t you just destroy that meta tag with JS?

In the case of Twitter, it’s emitted from the server. Even if it were in the HTML, destroying it has no effect on the actual browser behavior. It’s locked in.

Okay, so…

Can’t you insert your own security meta tag and override it?

You’d think so. But, thankfully, no. Once a CSP been accepted by the browser for that page, it cannot be overridden. That’s probably a good thing, even though it ruins our fun.

I suppose that’d be like wishing for more wishes. It’s against the genie rules!

The post Introducing Trashy.css appeared first on CSS-Tricks.

Understanding why Semantic HTML is important, as told by TypeScript

What a great technological analogy by Mandy Michael. A reminder that TypeScript…

makes use of static typing so, for example, you can give your variables a type when you write your code and then TypeScript checks the types at compile time and will throw an error if the variable is given a value of a different type.

In other words, you have a variable age that you declare to be a number, the value for age has to stay a number otherwise TypeScript will yell at you. That type checking is a valuable thing that helps thwart bugs and keep code robust.

This is the same with HTML. If you use the <div> everywhere, you aren’t making the most of language. Because of this it’s important that you actively choose what the right element is and don’t just use the default <div>.

And hey, if you’re into TypeScript, it’s notable it just went 3.0.

Direct Link to Article — Permalink

The post Understanding why Semantic HTML is important, as told by TypeScript appeared first on CSS-Tricks.

World wide wrist

After all the hubbub with WWDC over the past couple of days, Ethan Marcotte is excited about the news that the Apple Watch will be able to view web content.

He writes:

If I had to guess, I’d imagine some sort of “reader mode” is coming to the Watch: in other words, when you open a link on your Watch, this minified version of WebKit wouldn’t act like a full browser. Instead of rendering all your scripts, styles, and layout, mini-WebKit would present a stripped-down version of your web page. If that’s the case, then Jen Simmons’s suggestion is spot-on: it just got a lot more important to design from a sensible, small screen-friendly document structure built atop semantic HTML.

But who knows! I could be wrong! Maybe it’s a more capable browser than I’m assuming, and we’ll start talking about best practices for layout, typography, and design on watches.

I had this inkling for a long while that there wouldn’t ever be a browser in the Watch due to its constraints, but instead I hoped that there might be a surge of methods to read web content aloud via some sort of voice interface. “Siri, read me the latest post from James’ blog,” is probably nightmare fuel for most people but I was sort of holding out for devices like this to access the web via audio.

Another interesting aside is that both Safari OSX and iOS have had a reader mode for a long time now, but have it as an option enabled by the user while viewing the content. Bypassing the user-enabled option would be the difference on watchOS and where our structured, semantic chops are put to task.

Direct Link to Article — Permalink

The post World wide wrist appeared first on CSS-Tricks.