Reading Online?

One thing that has always intrigued me is how people read online and how it affects the way we structure web content. Most of my influence comes from Jakob Nielsen and the Nielsen Norman group’s research on how people read online.

Back in 1997, Nielsen reported that:

As a result, Web pages have to employ scannable text, using

  • highlighted keywords (hypertext links serve as one form of highlighting; typeface variations and color are others)
  • meaningful sub-headings (not “clever” ones)
  • bulleted lists
  • one idea per paragraph (users will skip over any additional ideas if they are not caught by the first few words in the paragraph)
  • the inverted pyramid style, starting with the conclusion
  • half the word count (or less) than conventional writing

We found that credibility is important for Web users since it is unclear who is behind information on the Web and whether a page can be trusted. Credibility can be increased by high-quality graphics, good writing, and use of outbound hypertext links. Links to other sites show that the authors have done their homework and are not afraid to let readers visit other sites.

Users detested “marketese”; the promotional writing style with boastful subjective claims (“hottest ever”) that currently is prevalent on the Web. Web users are busy: they want to get the straight facts. Also, credibility suffers when users clearly see that the site exaggerates.

Even in the web early days there was a need for compact and clear writing. Perhaps what’s more important is to write with the user in mind.

10 years later in write for reuse, Nielsen further refines his point by suggesting how we should write for web audiences.

This is particularly interesting to me because it forces me to be succinct in what I write and stay consistent in my writing style throughout the document.

No matter your medium, it’s fairly standard advice to simply write for your readers and their tasks. For old media, reader goals are well known, ranging from being entertained (when reading a mystery novel) to getting investment ideas (when reading the Wall St. Journal ‘s “Markets” section).

Writing for the Web differs, however, because various users might approach a given piece of content in different ways:

  • Reading the page. Although thorough reading is a fairly rare behavior for Web users, it certainly does happen.
  • Scanning the page to judge whether it’s worth reading (or, indeed, whether the site was worth visiting in the first place).
  • Scanning the page to locate specific information, which can differ by user. For example, when looking at digital cameras on an e-commerce product page, sophisticated users might look for sensor size, whereas less knowledgeable users might be interested in megapixel count.
  • Picking items from a list, such as on a SERP (search engine results page), an e-commerce category page, or a news feed. (News feeds are also called RSS, but please remember to avoid this acronym; this year’s usability studies confirm once again that many users have no idea what “RSS” means.)

In some of these scenarios, users see only a small portion of the content displayed out of context. They might, for example, see only a headline, or perhaps a headline, summary, and a thumbnail photo.

Writing for Different Contexts

The first challenge is to write content that will make sense when taken out of context. Fortunately, you can personally assess your content’s usability in the most common out-of-context scenarios:

  • Does the headline make sense if it’s all you see? Does it have sufficient information scent to attract those users who would be interested in the full story? (Note: it shouldn’t be misleadingly attractive to users who’d be disappointed if they clicked; yes, you’d gain extra clicks, but you’d lose customers when they left your site in disgust.)
  • Does the summary work to supplement the headline when the two pieces of microcontent are displayed together?
  • Is the lead picture clear? Lists use small images to represent products or articles; if your image isn’t clear, crop it if possible.

Writing Accessible Content

How you write may also have accessibility implications. WebAIM’s Cognitive Disabilities: Design Considerations puts it very succinctly:

Short, simple, unambiguous phrases are easier to understand than long, complex, ambiguous ones. People with more profound cognitive disabilities need sentences that are extremely short, simple, and unambiguous. In some cases, they will not be able to understand sentences at all, relying completely on graphics, illustrations, and other non-text visual materials. This does NOT mean that you have to create image-only sites for general audiences, though adding high-quality supplemental illustrations is certainly a good idea. If, however, your primary audience is individuals with more severe cognitive disabilities you may need to create an image-only site.

To the extent possible, try to avoid non-literal content such as sarcasm, parody, and metaphors. Also make sure to give readers all necessary background information about the topic at hand. (See also the article on writing clearly and simply.)

Text content must be as concise as possible and they need to add relevant images, audio, video or other non-textual content. We also need to be mindful that when we work with multiple audiences (and we all do whether we realize or not) the content needs to be even more concise than we would normally make it (if we make it concise, to begin with).

It also takes some work to figure out when it’s a good idea to support the text with images and what images to use or, if necessary, what images to create for the content we’re writing.

As with many other aspects of accessibility, we all benefit from the work we do for accessibility. In this case, we all get better and easier to understand the text, not just the people who we are primarily doing this for.


Colors in CSS, Contrast and, Testing

When we talk about visual disabilities we usually concentrate on color blindness without realizing that that are other visual accessibility issues that we tend to ignore.

This came to bite me when I was testing a page using Chrome Dev Tools accessibility Test (process fully described in Accessibility: Test your content) where the color of my code blocks (using Prism and the Solarized light theme) were not providing enough contrast between text and background.

At an instinctual level I understand why this is important but how much contrast is too little and how do I measure it? What role does color play in contrast and accessibility?

The contrast between the text and background colors and Luminosity (how bright the colors are on the page) are important for people with colorblindness or low vision.

The bright light from a screen or other sources prevents some people with low vision (including those with photophobia and with reading disabilities such as dyslexia) from reading and causes pain for some people. Some people turn down the brightness of their screen or use an overlay. For other people, it is easier to read with a bright screen, and they sometimes increase the brightness, especially on mobile devices.

Other people need high contrast between text and background, including many older people who lose contrast sensitivity from aging. Some read better with dark text on light background.

For some people, common color combinations or colors from a limited color palette work fine, for example, black text on white background or the inverse with white text on black background. Other people need to select a more specific background and text colors. For example, people who need low brightness overall, need to select the specific background and text colors that provide sufficient contrast for them yet not too high brightness. Readable and optimal color combinations differ vastly among individuals and can even vary for one individual depending on conditions such as fatigue and lighting.

Some modern designs, however, are so “subtle” that the contrast can actually be insufficient for some readers. Examples include contrasting light grey versus middle grey, middle pastels versus darks, or white versus light cyan (blue-green).

Testing for contrast

The WCAG has the following recommendations for contrast ratio and font sizes:

  • Text that is considered small – approximately equivalent to 1.2em or 120% of the default body text size – should have a contrast ratio of at least 4.5 : 1 to its background
  • Text that is 1.2 ems or higher and bolded, or normal text that is 1.5 em / 150% in size or greater, should have a contrast ratio of at least 3 : 1

How do we test these values? How do we know if they pass WCAG testing?

There are tools to test contrast between text and background colors but, until recently, they relied solely on hexadecimal colors. With designers increasingly using rgb, and hsl CSS color systems combined with transparency make the testing harder. Newer tools allow you to test the contrast level of your web pages versus WCAG guidelines even with transparency or when using different types of colors. Out of the tools, I found I chose to use Lea Verou’s easy color contrast tool. It also supports working with transparent colors using HSLA and RGBA. I’ve provided links to other tools in the links section at the end of the post.


Unfortunately, this is an area where we can’t really provide a one size fits all solutions because there are different types of visual disabilities that we have to account for.

So we need to work together with users when it comes to providing a good experience for people with visual disabilities. Some of the ideas below are things for the designers/developers to do and others are for users to implement and use.

Manual Testing for Color Contrast

The best way to test color contrast is to actually test the colors you want to use. I’ve chosen to use Lea Verou’s Contrast Testing Tool as my primary testing tool. This will give us both color contrast and the possibility of playing with other color combinations.

It also works with colors outside the 3 or 6-color hexadecimal values. It works with HSL, HSLA, and, RGBA. So the playground for experimentation grows even bigger.

Lea Verou’s Contrast Testing Tool

This is the first tool in our testing arsenal.

Automatic Color Contrast Testing

The easiest way is to test your site for accessibility using automated tools. Tools like Lighthouse, aXe and aXe Coconut will get you started with accessibility testing.

I put it after manual testing rather than as the first idea about how to test contrast because I use manual testing is to decide what colors to use (foreground versus background).

I use the accessibility testing integrated into Dev Tools Audits menu. Figure 2 (below) shows the result of the accessibility testing.

Image of Lightouse testing tool in Chrome showing results for a page in
Lighthouse Accessibility Testing Report

Automated tools are awesome but they are far from complete. There are many accessibility checks that you must perform manually, either because it’s hard to get the values programmatically or because it requires human judgment whether the rule passes or not.

Links and Resources

Alternate and User Style Sheets

We normally work with the stylesheets we develop for the content we create. This is one of the style sheets available and that interact in the CSS cascade:

  • The browser has a basic style sheet that gives a default style to any document. These style sheets are named user-agent style sheets
  • The author of the Web page defines styles for the document. These are the most common style sheets
  • The reader, the user of the browser, may have a custom style sheet to tailor its experience

The user-agent is outside our control and it should stay that way. It’s the browser’s default that will apply to all content.

Alternate style sheets allow for theming without having to write additional code to switch styles. But you still have to create the themes.

Reader style sheets allow end-users to override user-agent and alternate style sheets to accommodate their needs and provide different styles to do so.

In this post, we’ll talk about alternate and reader style sheets.

Alternate Stylesheets

Alternate style sheets give you a way to deploy multiple stylesheets for the same app or site.

As far as I know, only Firefox supports alternate stylesheets using the syntax below.

In this example, we have four link elements. The first one will always run and will not show on your page styles menu.

The next three are the ones for the actual page styles. Pay attention to the rel attribute in the links, that’s what makes the magic happens.

The first stylesheet, the one with the rel="stylesheet" attribute is the default stylesheet that will load when the page is first loaded.

The other two stylesheets, with rel="alternate stylesheet" attribute are optional and the user can load them on demand. One of these alternate stylesheets could be a high contrast version of the site or one with a different color scheme for people whom bright colors are a problem.

<link href="reset.css" rel="stylesheet" type="text/css">

<link href="default.css" rel="stylesheet" type="text/css" title="Default Style">
<link href="fancy.css" rel="alternate stylesheet" type="text/css" title="Fancy">
<link href="basic.css" rel="alternate stylesheet" type="text/css" title="Basic">

Firefox (screenshot from Firefox 57.0.1) has a menu under View that gives you access to all alternate style sheet available for the page.

Accessing Alternate Stylesheets In Firefox 57

User Stylesheets

So far we’ve only dealt with Stylesheets we create as part of the website. If we choose to provide high contrast or no background image stylesheets, it’s still our best guess as to what will users with disabilities need from our sites/apps. Because of this, we will never be able to cover all bases.

Users who need them probably have created custom stylesheets that will override a site’s styles with rules that make more sense for their disabilities. In the case of color or contrast, they may completely remove background images or make background colors solid rather than semi-transparent or use fonts specially designed for their needs.

Unfortunately, only Microsoft Edge supports adding reader style sheets directly but we can target other browsers, Chrome and pre-Quantum versions of Firefox with Extensions that will accomplish the same goal.

Understanding The CSS Cascade

When working on my piece about contrast I found myself writing about the CSS cascade. The more I realized I didn’t understand the cascade itself. So this is my attempt at understanding the cascade, different types of style sheets and how they interact with each other.

I’m also coming to the realization that this is one of the main issues that attract people to CSS in Javascript. The cascade is complicated and, sometimes, the interaction between user-agent and author style sheets can be a real PITA so any option that removes the cascade from the equation seems attractive.

So rather than move everything to Javascript I thought I would try to understand the cascade and how to figure out what value will be shown to the user.

Different kinds of style sheets

According to MDN, browsers can handle 3 different kinds of style sheets.

  • The browser has a basic style sheet that gives a default style to any document. These style sheets are named user-agent style sheets
  • The author of the Web page defines styles for the document. These are the most common style sheets
  • The reader, the user of the browser, may have a custom style sheet to tailor its experience

Most of the time we only have to deal with author style sheets because we don’t have access to the user-agent style sheet (and shouldn’t change it even if we did) and don’t see if the reader has a stylesheet.

It is still important to know what stylesheets are available to avoid confusion in understanding the cascade and specificity rules that follow.

The cascade

How the browser sorts which rule to apply to an element is known as the cascade (which gives CSS the Cascading part of its name) and helps figure out which rule to use when rules from multiple style sheets affect the same element.

  1. It first filters all the rules from the different sources to keep only the rules that match the given element and which are part of an appropriate media at-rule
  2. Then it sorts the matching rules according to their importance, whether or not they are followed by !important, and by their origin
  3. In case of equality, the specificity of a value is considered to choose one or the other


When the cascading rules in the prior section refer to specificity they mean the weight of a selector based on the number of different kinds of selectors that apply.

Whenever I have to explain this I’ve fallen back to Estelle Weyl’s CSS SpeciFISHity chart. It has helped me figure out specificity issues many times and it’s a fun way to look at the values for different element combinations.

specificity chart indicating css specificity for different combinations
CSS Specifishity chart from Estelle Weyl

I’ve also extracted the text at the bottom of the image that explains in more detail what the different specificity rules are

  • X-0-0: The number of ID selectors, represented by Sharks
  • 0-Y-0: The number of class selectors, attributes selectors, and pseudo-classes, represented by Fish
  • 0-0-Z: The number of type selectors and pseudo-elements, represented by Plankton a la Spongebob
  • *: The universal selector has no value
  • +, >, ~: combinators, although they allow for more specific targeting of elements, they do not increase specificity values
  • :not(x): The negation selector has no value, but the argument passed increases specificity

Order of precedence

We have one more thing to talk about to, hopefully, get a better idea of how the cascade works. That’s the order of precedence for stylesheets from different origins.

The origin of a declaration is based on where it comes from and its importance is whether or not it is declared !important. As our work with CSS becomes more complex we need to figure out if our rules will be pre-empted by a stylesheet with higher precedence.

The precedence of the various origins is, in descending order:

  • Transition declarations
  • Important user-agent declarations (!important)
  • Important user declarations (!important)
  • Important author declarations (!important)
  • Animation declarations. At any given time a CSS animation takes values from only one @keyframes element, and never mixes multiple @keyframes together
  • Normal author declarations
  • Normal user declarations
  • Normal user-agent declarations

Declarations from origins earlier in this list win over declarations from later origins.


The cascade is a central part of working with CSS. Yes, it can be a nightmare to figure out. Yes, it can cause problems of specificity. But if you use it carefully it can give you awesome results.

Links and Resources


Mavo is an extension to HTML created by Lea Verou as part of her work at MIT CSAIL. It caught my attention because it’s a minimal setup system that does all of the heavy lifting for you (as we’ll see when we look at how it works) and it can do fairly sophisticated projects.

To test Mavo I will use it to create a project listing for a portfolio. It will test Mavo’s storage capabilities, how to create multiple entries in a single application and Mavo scripting features built into the platform.

What it is

Mavo adds attributes to HTML that describe Web applications that manage, store, and transform data.

You can store data in the cloud, locally, or not at all by just changing an HTML attribute

With Mavo you can edit data right on the website, with an intuitive, auto-generated, customizable interface. No more wrestling with CMSes and servers!

There’s a lot more you can do. Check the documentation and demos to get a feel for what Mavo is and what it can do.

How it works

To go in-depth into Mavo we’ll look at a full-blown Mavo application and break it down as needed to explain Mavo concepts and ideas… The portfolio app, taken from the Mavo Demos

<!DOCTYPE html>
<html lang="en">

<meta charset="UTF-8">
<title>Artist Portfolio</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="">
<script src=""></script>
<link rel="stylesheet" href="style.css">


To start create an empty HTML document and insert the following code in the head element:

<script src=""></script>
<link rel="stylesheet" href="">

This will get the latest stable version of Mavo. If you want to get an uncompressed version, an ES5 version for older browsers or a specific version (other than the latest) head to get Mavo select from the options given and copy the code that will appear.

Questions to answer and links to appropriate Mavo resources download

This will load Mavo but won’t do anything with it… yet.

To start using Mavo add the following attributes to the root element of the Mavo application: mv-app="name-here" mv-storage="". If you’ve worked with Angular or Vue in the past this should look familiar.

<body mv-app="portfolio" mv-storage="">

These two attributes tell Mavo that this is a Mavo application with the given name and to use the indicated Github repository for data storage. Of course, you should have write access to the repository to save data there. If you don’t you’ll generate a Pull Request for the Repo owner with the changes you suggest.

We continue writing HTML for the header.

  <h1><a href="">
  <img src=""
    alt="Jules Muck"
    class="logo" />

Then we move to the individual paintings that are part of the portfolio. This is where the Mavo magic happens.

property names elements that will be saved, edited or used in expressions. This is how we tell Mavo that this is an element we want to work with.

typeof is what we use to tell Mavo the actual value of the element. It’s not just an attribute or its text content, but the union of the values of the properties inside it. We can use it to force an element to be a group, or to declare the type of the group (e.g. typeof=”Person”) for richer semantic value

mv-multiple makes the element repeatable.

mv-attribute overrides the defaults for which attribute holds the data for this element. For no attribute (element content), specify “none”.

mv-default gives the default value for the property. If you provide no value then the content becomes the default.

    <a property="painting" typeof="Painting" mv-multiple mv-attribute="none">
        <img property="image" />
        <p property="name" mv-default="[readable(to(filename(image), '.'))]"></p>

Then we add the rest of the HTML content including the closing body and html tags.

<footer>All art belongs to the awesome <a href="">Jules Muck</a>, used
  here with permission.</footer>


That’s it… this is a fully-working Mavo application that will store its data in the Github repository you indicated in the root element of the application.

Projects project

So now that we got an idea of how Mavo works let’s see how well it works for our own projects.

I have a list of projects at different stages of completion that I would like to use Mavo, in its default configuration to create a list of project in different stages of completion.

The structure of the data is like this:

  • Name of the project
  • Description
  • Date Started
  • Date Ended (if applicable)
  • Type of project. One of
    • Code
    • Writing
    • Research Report
    • Mixed
    • Other
  • Stage of the project. One of
    • Idea
    • Draft
    • In Development
    • Completed
    • Published
  • URLs
    • Writing
    • Code
    • Other
  • Additional Notes

The project had some baffling aspects (that I’m still working on understanding) and some very easy parts of the code. The full code is shown below, broken by sections to make sure that I cover some of the more baffling aspects of it.

The opening is similar to the example we used in the last section. I compiled Mavo from source to make sure I had the latest version instead of depending on the version hosted by the CDN.

I’ve also downloaded a plugin to use Markdown in the text areas. I’ll come back to this because it was one of the areas that bit me when working on this project.

<!DOCTYPE html>
<html lang="en">
    <meta charset="UTF-8">
    <meta name="viewport"
    <script src="scripts/mavo.js"></script>
    <script src="scripts/mavo-markdown.js"></script>
    <link rel="stylesheet" href="styles/mavo.css">
    <link rel="stylesheet" href="styles/main.css">

As normal we give the app a name and a location for storage.

  <body mv-app="portfolio"

In the following sections, we begin defining the layout and data structure for the application using the structure we defined earlier.

Project name and description are self-explanatory.

In Project Chronology we use a few tricks to save typing. For the Date Started field, I’m assuming that if you didn’t enter the starting date then the date is today. To represent this date we use some MavoScript to do so.

MavoScript is Mavo’s expression language. More details at To generate the date value in a human-readable format we use $now (number of seconds since 1/1/1970) and date() to generate the date itself.

If you don’t enter a date for dateEnded I’m assuming that the project is still in progress.

Under Project Description came the first surprise. The original version of the code used textarea elements to hold the text to edit but, to my surprise, the plugins did not work. They only worked when I changed the elements to div.

    <div class="projects">
      <section typeof="Project"

        <h2 property="name"
          mv-default="Default Project Name"></h2>

          <legend>Project Description</legend>
          <div property="description"
            mv-default="Project Description"

          <legend>Project Chronology</legend>
          <label for="dateStarted">Date Started</label>
          <input type="text" id="dateStarted"
            name="dateStarted" value=""
            property="Date Started">

          <label for="dateEnded">Date Ended</label>
          <input type="text" id="dateEnded"
            mv-default="In Progress"
            property="Date Ended">

This is where I got stuck for a while until I looked to a similar example (the talks demo in the demo section of the Mavo website). Looking at other people’s code helps, really 🙂

          <legend>Project Status</legend>
            <select property="status">
              <option selected>Idea</option>
              <option>In Development</option>

          <legend>Project Type</legend>
            <select property="type">
              <option selected>Code</option>
              <option>Research Report</option>

In most other versions of this project, I’ve created nested structures for the URLs. With Mavo that was not necessary. The JSON structure is flat so I can save myself from having to do, or ask Mavo to do, weird acrobatics to get the JSON the way I want it.

        <fieldset class="links">

          <label for="codeURL">Code</label>
          <input type="text" id="codeURL" name="codeURL"
            value="" mv-default="N/A" property="Code URL">

          <label for="writeupURL">Writeup URL</label>
          <input type="text" id="writeupURL" name="writeupURL"
            value="" mv-default="N/A" property="Writeup URL">

          <label for="otherURL">Other URL</label>
          <input type="text" id="otherURL" name="otherURL"
            value="" mv-default="N/A" property="Other URL">

Project Notes is the last item in each individual project card before we close the page.

          <legend>Project Notes</legend>
          <div property="notes"
            mv-default="Project Notes"


I used some CSS to make the cards responsive using Flexbox. We also make some items flex horizontally to increase readability but, as you can see below, there is not that much CSS to use to tweak the Mavo-enhanced code to look the way I want it to.

.projects {
  display: flex;
  flex-flow: row;
  flex-wrap: wrap;

.project-card {
  margin: 2em;
  padding: 1em;
  border: 1px solid navy;
  border-radius: 10px;

label {
  font-weight: 700;

.links {
  display: flex;
  flex-direction: column;

.links input {
  width: 100%;
  margin-bottom: 1em;

Conclusions And What’s Next

Mavo Projects Current Version
Mavo Projects Current Version

I love Mavo.

Once you figure it out and learn to play by its rules it becomes second nature to create fully editable content without having to worry about configuring and customizing a CMS or having to learn a whole new syntax to create your content and structure.

It’s not perfect, no tool is. While it’s true that you don’t have to learn a whole new interface to build your apps, you still have to learn the additional attributes that Mavo uses… but it’s still a more gentle learning curve. One of the most confusing aspects is that the documentation shows more than one way to assign properties to an element.

There are some aspects that I’m still trying to figure out that will go into a future iteration of the project. Some of the things I’m looking at after MVP:

  • Pagination: Because there are many cards on the page, it would be nice to show them 6 at a time and then have a pagination system to move between the pages. According to a tweet from Mavo there is a way to do pagination. Trying to figure out if it’s worth it or whether I should wait until Mavo provides an easier way to do it
  • Moving the backend to Firebase using a plugin
  • Test the application for accessibility
  • Hide URLs without a value… N/A works for now but it doesn’t convey the fact that if we don’t have a value then the link shouldn’t be there. This should be possible to do with Mavo Script, still trying to figure out how