Introduction
The following are facts, just facts. Not a rant, not a political statement, not an appeal to novelty, just facts...
Unless your website is very unusual, the majority of your visitors view, or try to view, your website with a mobile device such as a cellphone. If they have to horizontal scroll to see the right side of your website they'll probably leave. If they leave, you lose business. Or mindshare. Or whatever drove you to put up the site in the first place.
But you can't design your website exclusively for mobile device users, because a significant minority view your website on a computer with a full sized display. If their view of your site is a skinny 500 pixel view that scrolls down and down forever, they'll probably leave. If they leave, you lose business. Or mindshare. Or whatever drove you to put up the site in the first place.
To optimize your site's success, you must take your visitor as you find him, whether on a 36 inch 4080p curved monitor, or a cell phone 400 pixels across, or something in between. This document gives suggestions for how to do this.
Because ability to customize the web page according to the screen width (often called responsiveness) is both important and involved, this document is long. It didn't need to be this long, but I felt it was important to split it into small sections and adopt the top documentation priority of eliminating ambiguity. I hope you enjoy it.
A Couple Buzzwords
The word responsive, whether it's used as "responsive design" or "a responsive web page" means the ability to accommodate different sized screens conveniently. There are a few ways to do this, as will be described in this document.
The phrase mobile-first means to design it for the mobile device on the theory that the majority of visitors come in on a mobile device. You can then later make it appropriate for full sized screens as well. It theoretically shouldn't matter which interface is designed first, as long as they're both top-notch. But it could be argued that if you design for mobile, your mobile interface will have less compromises. There are some challenges with mobile-first design, because most content creators use a full-sized screen and full sized keyboard to create content, which makes it much easier to design full-sized first. This will be discussed later in this document.
A Text Only Page
If every single thing on a web page were text, and I mean regular text, not source code wrapped in a <pre></pre> tag pair, the page would automatically be responsive. Text automatically wraps at spaces and hyphens on all browsers, shrinking to the available screen width.
Note:
You could theoretically disable breaking on hyphens by setting the CSS declaration hyphens to none. But why in the world would you do that on anything but pre elements?
The trouble is, most web pages have a lot more than just text, and those other things make responsiveness a challenge. All of this is discussed later in this document.
The Two Routes to Responsiveness
In the very broadest sense, there are two ways to achieve responsiveness:
- Design so elements collapse and fold under to fit the screen. This is done primarily by getting rid of the enemies of responsiveness, which is discussed later in this document.
- Make part or all of the web page completely different for different sized screens. This is done primarily via media queries, which is discussed later in this document.
The Enemies of Responsiveness
There are several enemies of responsiveness. These must be replaced by responsive-friendly elements to make your page responsive. Here are a few enemies of responsiveness:
Tables
Tables are meant for tabular data, nothing else. They have been misused since the dawn of the web. Tables should be used only for tabular data, and in order to fit on small screens, the number and width of columns should be kept to a minimum. If this isn't possible, find some other way to represent the material. If a large table is absolutely required to display your tabular material, put it on a page of its own and link to it so it doesn't destroy the responsiveness of an entire web page.
There was a time when the main way to get multiple columns on a web page was with tables, which of course was a misuse of tables. Not coincidentally, back in that time everyone viewed web pages on a full sized screen, so using tables to represent columns on a web page kinda-sorta worked, sort of. There are two correct ways to portray columns on a web page:
- Shrinkable, fold-under divs.
- A grid layout.
Shrinkable, fold-under divs.
Shrinkable, fold-under divs are the simpler method. They're discussed here and here later in this document.
A grid layout.
Grid layouts are a whole new science. They're discussed here later in this document.
Source code
Source code is one of the worst and least treatable of all responsive web pages' enemies. There are many ways to work around it, but all have unpleasant side effects.
By its very nature, source code in many languages cannot be word wrapped. This is certainly true in Python and Shellscripts, and many other languages have certain constructs in which lines count.
Even more challenging is representations of command line interface interactions, with long commands and longer responses. Trying to line break these in any way leads to massive confusion.There's no HTML silver bullet to get past this. The best that can be hoped for is to make use of the following workarounds:
- Use short names for variables, functions, classes and methods.
- Use very small indents.
- Manually split lines to keep everything short while still providing readability.
- Put Scrollbars On the <pre> Element Holding the Source Code
- Use a smaller font size.
- Put the source code in a separate file.
- Leave the wide source code out of your presentation.
- Make the decision not to be responsive.
Use short names for variables, functions, classes and methods.
I normally recommend long names in order to make self-documenting code, but when putting source code in a responsive web page, variable, function, class and method names should be as short as possible while still bestowing some degree of meaning to each name. However, used to anything but the most minor degree, this alternative is harmful to code readability and self-documenting code.
Use very small indents.
I normally like indents to be four spaces in my source code, for maximum readability. However, when horizontal space is at a premium, two space indentations are sufficient. Sort of. Small indents make code less readable and much less glancible.
Manually split lines to keep everything short while still providing readability.
As one example, use the following CSS representation instead of putting the whole CSS style in one line:
span.buzzword{ color: #770000; font-weight: bold; }
Many programming language and programs have places where lines of code can be conveniently and readably broken into lines. This can be a good alternative, but some source code and especially command line sessions don't lend themselves to this technique.
Put Scrollbars On the <pre> Element Holding the Source Code
Using a horizontal scrollbar on the source code containing <pre> confines horizontal scrolling only to that <pre>, sparing the document as a whole from the massive inconvenience of a document-wide scrollbar. This can be combined with some of the other techniques, such as slightly smaller font, slightly shorter indentations, and splitting of a few of the longest lines to achieve responsiveness on all reasonably sized devices. The following is an example of what is rendered, and will acquire a horizontal scrollbar if you sufficiently narrow the browser window or view on a narrow device:
[slitt@mydesk web]$ cat web_workmanship.css | tail -n40
ol.multiline li{margin-bottom: 0.7em;}
/* FOR TROUBLESHOOTING */
div.diag{background-color: #ffffcc;}
/* CHARACTER STYLES (SPANS) */
span.emph{font-size: 105%; font-style: italic; color: #003300;}
span.term{font-size:105%; font-style: italic; font-weight: bold; color: #770000;}
span.searchterm{font-size:95%; font-style: italic; font-weight: bold; color: #007700;}
span.userinput{color: #990066; font-family: monospace; font-weight: bold; font-size: 85%;}
span.cmdprompt{font-family: monospace; font-weight: bold; font-size: 90%}
span.term{font-family: serif; font-style: oblique;}
p.errorexample{font-size: 3em; color: brown}
span.code,span.tinycode{
background-color: #e0ffff;
font-family: monospace;
padding-left: 0.2em;
padding-right:0.2em;
margin-left: 0.1em;
margin-right: 0.1em;
hyphens:none;
}
span.tinycode{font-size: 60%; color: orange;}
code,code.tiny{
background-color: #e0ffff;
font-family: monospace;
padding-left: 0.2em;
padding-right:0.2em;
margin-left: 0.1em;
margin-right: 0.1em;
hyphens:none;
}
code.tiny{font-size: 60%; color: orange;}
[slitt@mydesk web]$
To achieve the preceding formatting, I added overflow-x: auto;
to my existing CSS definition of pre.code
, which is the styling I use on my source code. Notice the following three facts about the pre.code
addition:
overflow-x: auto;
is what adds the horizontal scrollbar when the browser window or device gets too narrow.- I could have used
overflow-x: scroll;
to add horizontal scrollbars to all code snippets, no matter how narrow they already are, but 80% to 90% of my code snippets don't require a horizontal scrollbar, so why should they be encumbered by an extraneous distraction? - I could have added a vertical scrollbar to
pre.code
. A lot of sites I've browsed do. I find them very inconvenient because, when using the mouse wheel to scroll the page, all of a sudden the window stops scrolling and it takes a second to realize that what's scrolling is the<pre>
, at which time if I want to get past the<pre>
I must either scroll to the bottom of the<pre>
, or find a place to the right of the<pre>
to land the mouse and scroll the wheel. Very inconvenient. Additionally, vertical scrolling of the page, in code or in other content, is not inconvenient. Horizontal scrolling of the page is inconvenient.
The following is the <pre.code> CSS I use on all my modern pages:
pre.code{ margin: 1ex; background-color: #e0ffff; margin-top: 0.0005ex; margin-bottom: 0.0005ex; padding-right: 0.001ex; padding-left: 0.2em; padding-top: 0.4em; padding-bottom:0.2em; border-style: ridge; font-family: monospace; font-size: 90%; font-weight:bold; line-height: 130%; hyphens: none; overflow-x: auto; }
If the preceding CSS is used to construct <pre class="code"></pre>
to contain all the page's source code, it's guaranteed that your source code won't cause the entire page to require scrolling horizontally, meaning your page remains responsive.
However, although being required to horizontally scroll the whole page is very much worse than having to horizontally scroll just the code, horizontally scrolling the code can be inconvenient. It's less inconvenient if you only need to scroll for a couple long lines of the source code, but it's still a good idea to use shorter (but still meaningful) names, use small indents, and manually split lines where you can, in addition to using horizontally scrollable code boxes. If this still isn't enough, some more drastic actions follow. Read on...
Use a smaller font size.
The smaller you make fonts, the more you screen out those with less than perfect vision, so this is a last ditch fix. If you opt to shrink fonts to fit the source code width onto a small screen, for gosh sakes use the highest contrast foreground/background combination you can possibly do, so that the code is legible to users with somewhat good visual acuity. Anything more than the most minor of font size reduction in source code are generally a bad idea.
Put the source code in a separate file.
Sometimes it's impossible or impractical to shrink the width of source code enough to accommodate a mobile device sized screen. In such a case you might put the source code in a separate file. When you do that, the source code isn't responsive, but your page that links to it will still be responsive. When you put the source code in a separate file, most browsers won't render it right unless it ends with .txt, so what I often do is hardlink example.py.txt to example.py. Or you can simply copy example.py to example.py.txt.
This can be an excellent alternative for HTML on a web browser, a ePub or other flowing text eBook, or a small device sized PDF eBook, as long as it's being read on a monitor. This technique doesn't lend itself to printing to paper.
Leave the wide source code out of your presentation.
How important is the source code? If there are no simple solutions to shrink the source code's width to a small device screen, is it worth putting in at all? Is the value of the source code worth annoying the armies of mobile device wielding visitors? If not, leave it out.
Make the decision not to be responsive.
The situation I encounter quite a bit is that my page discusses several instances of real code I've written for code readability, not short width. Or worse, discusses several command line interactions with long commands and longer responses. If shrinking to small screen width gets so cumbersome it starts to lessen the understanding of the visitor coming in on a full screen, I often forget about responsiveness.
I come to this decision with the following logic: Full sized screens and keyboards are for those who produce content or software. Tiny screens with tiny keyboards are for those who consume content and software. A page displaying source code is most likely of interest to those who produce content or software.
Graphics, pictures, videos
It's fun and sometimes profitable to place photos and other dimensionally large graphics your website. The trouble is, if the web page has a 7" by 12" picture of your cat sitting on your stereo receiver, and that bollixes up the whole page for those with small screens, you have a problem. This subsection has contains some right ways to put images into responsive web pages. These right ways include:
- Make the graphic shrinkable.
- Link it so clicking it pulls up a full sized, full quality version.
- Do both the preceding alternatives.
Let's first talk about making it shrinkable: The following CSS creates a img.rightsize style that's 600px on full sized screens, but shrinks in both dimensions to accommodate smaller width screens:
img.rightsize{ width: 100%; max-width: 600px; }
It's good to also have a special paragraph style to place text information below the picture. The following is the CSS for this:
p.graphic{ margin: 0px; color: darkgreen; }
The HTML that actually shows the image and also makes it a link follows:
<a href="images/cat.jpg"> <img class="rightsize" src="images/cat_comprs.jpg" alt="cat"\> </a> <p class="graphic">Click on preceding picture to see large version. Warning: 1.13MB download.<p/>
In the preceding, cat_comprs.jpg is the compressed, low quality version. I did that because the high quality version is a megabyte, and I don't want to put you through that if you have a low bandwidth connection. When you click on that shrinkable picture, you get the full sized, full bandwidth picture. The following is the result of the preceding code:
Click on preceding picture to see large version. Warning: 1.13MB download.
Note:
When you click the preceding picture to see the full sized, full quality version, that full version might not come up at 1 to 1 magnification, depending on various state/history factors. No problem, you can use your browser's zoom in and zoom out facilities to make it as big or small as you want it. And because you're looking at the graphic only, such zooming activities affect nothing but the full version of the graphic. Try it in the preceding picture of the cat.
Many multicolumn methods
From the dawn of time, people have split some of their web pages into vertical columns. Conceptually it's not a bad idea, because long lines on an extra wide page slows all but the most skillful readers, as they lose their vertical place when starting the next line, and need to figure out by context where they should be.
So web designers made a second column to hold advertisements or menus or pretty graphics for graphics sake, or whatever. And most of the time, the result was less than satisfying. If the visitor had poor eyesight and cranked up the fonts to clock-face size, it knocked half of one column off the screen, and horizontal scrolling became necessary, unless you could ignore one column and just read the other. Who can forget those left column menus whose text bled over into the right column's text, making reading difficult or impossible.
Long Words
Long words are a potent enemy of responsiveness. When the length of a word, plus left and right padding, exceeds the width of the screen or containing div, the right side of the long-word walks right off its div or screen, and causes a horizontal scrollbar to appear. This creates an ugly and readability killing situation. There are four solutions for this problem, each with its own advantages and disadvantages:
- Don't use long words
- Insert hyphens into the word
- Insert <wbr/> HTML element
- Insert spaces that don't look like spaces
Don't use long words
Can shorter words be used? Except for actual technical content, instructions are best written at a seventh grade level so everyone in your target age group can understand them, unless your target age group is below 9th grade. I wish I had a dime for every "author" who used gigantic, unusual words just to puff up his self image and baffle his readers with his bull-droppings. If shorter words can be used, use them.
Insert hyphens into the word
If you absolutely must have a long word, you can insert hyphens. Insert either hard hyphens or soft hyphens into the word at appropriate points. Use hard hyphens (an ascii hyphen character or -) when the word is a genuine hyphenated word, like able-bodied or high-spirited. Use soft hyphens (­) otherwise. Either way, the word will line break at the hyphens, if necessary, assuming that the CSS hyphens property is set to either manual or auto.
Tip:
Don't use hyphens: auto;. Doing so works inconsistently and introduces a browser dependency. Stick to hyphens: manual; (except on source code, where it should be hyphens: none;), and insert soft hyphens on known long words.
The following is an example of hard hyphens:
We sang fifteen-part harmony around my twenty-four-legged table.
And the following is an example of soft hyphens:
I don't believe in antidisestablishmentarianism!
The preceding line breaks, if necessary due to width concerns, at any necessary soft hyphens (­) within the word, and shows the hyphen to the right of the part before the line break, so it looks natural. The word "antidisestablishmentarianism" is HTML coded as follows:
anti­
Be careful!
Copying and pasting the preceding HTML source, either from the web page or from source, won't produce the desired outcome, because the preceding HTML source is displayed specifically for responsiveness, using <wbr/> HTML elements to enable necessary breaking, without a visible hyphen, within the displayed source. Just learn the fundamentals of soft hyphens and then use them.
DON'T use ­
­ has an alternative written as ­. Don't use ­, because doing so breaks the important XML Checker described in Xmlchecker.py later in Web Workmanship. Just use ­ to represent soft hyphens.
Insert <wbr/> HTML element
The <wbr/> HTML element is the "Line Break Opportunity" element. It's like a soft hyphen except it doesn't show a hyphen before breaks. Opportunities to correctly and productively use this element are rare, but I'm including it because the preceding subsection correctly and productively uses it. Most of the time, the soft hyphen is a much better choice.
Insert spaces that don't look like spaces
This is almost always a bad idea, because it can be browser, font size and magnification dependent, it can result in overwrites or excess space, and it will probably wreck havoc with text readers for the blind. So I'm not going to tell you how to do it except that it's based on a space inside a span that makes the space narrower. If you look soon, you might see that this page's "presents" line uses this space insertion technique. I'll soon be changing those narrow spaces to <wbr/> HTML elements.
Newspaper Columns
There's a way of making text flow down a column and then down the one to the right. This is a great way to flow text on a wide page PDF, but in my opinion a terrible practice for HTML because HTML doesn't have pages. Also note that these newspaper columns don't fold under, so the three columns get really squished on a small screen. If you really must do newspaper columns, and I advise not to, perform a web search on the combination of CSS and column-count.
Two Foldunder Columns
Once, most computer screens had width to height dimension ratios of 1.33 (640x480, 800x600, and 1024x768). Then, a couple decades ago, those 1.33 ratio screens were replaced with wider 1.77 screens (1920x1080, for instance), took over. The intervening years have brought even wider screens with 2.33 width to height ratios (2560 x 1080 for instance). This widening made us ask "what do I do with all that extra width?" With websites, the answer was often to put a navigator window or advertisements in the extra width, hence columns were needed.
Early web developers, who tended to slap anything together and call it a web page, often made a mess of these columns, with text and even column color of one bleeding into the other. These early web pages often featured partly unreadable columns for those using the "wrong" web browser or the "wrong" magnification. As time went on, web developers got smarter and used many browser, screen size and magnification independent method. One such method was foldunder columns.
Foldunder columns are really foldunder <div></div> elements with the property that they shrink for narrower screens, and for screens too narrow to contain both foldunder divs side by side, the rightmost foldunder div repositions itself under the leftmost. Foldunder divs therefore accommodate a very wide range of screen widths. The following, which you're encouraged to check with a browser's responsive view mode, is an example of two columns created with foldunder divs:
Lorem ipsum dolor sit amet consectetur, adipisicing elit. Totam dicta dolores eius laboriosam optio, quam at! Perspiciatis voluptatem repellat, velit facilis consequuntur porro perferendis a ad, dignissimos expedita aperiam asperiores.
Lorem ipsum dolor sit amet consectetur adipisicing elit. Accusantium, repellat consectetur aliquid molestiae odit perspiciatis soluta dolore, quidem fuga facere architecto error ipsa non. Ipsam facilis deserunt fugiat temporibus enim.
Pretty cool, right? This accommodates screens of pretty much any practical width. How does it do it? With a div element whose class is "foldunder_wide". Because later in the three column example we'll also use a narrower foldunder div called "foldunder_narrow", the "foldunder_narrow class is also defined. The only difference between the two is the max_width property. The CSS code follows:
div.foldunder_narrow, div.foldunder_wide{ display: inline-block; margin: auto; margin-bottom: 0.5ex; background-color: #ffffff; max-width: 32%; min-width: 200px; vertical-align: top; padding-left: 0.5em; border-style: solid; border-width: 1px; } div.foldunder_narrow{ max-width: 30%; } div.foldunder_wide{ max-width: 46%; }
And the following is the HTML code creating these foldunder divs:
<div class="foldunder_wide"> <p>A paragraph of Latin long enough to word wrap within the foldunder column, even at the widest widths. Note that this paragraph could be much shorter and still work just fine in a foldover column.</p> </div> <div class="foldunder_wide"> <p>A second paragraph of Latin long enough to word wrap within the foldunder column, even at the widest widths.</p> </div>
Benefits and Costs
- Benefits
- Very simple to use
- Don't require use of a containing
<div>
- Easier to debug.
- Costs
- Fails to properly display a contained responsive
<pre>
. - Fails to properly display a contained responsive
<img>
. - Requires pre-declaring
max-width
- Fails to properly display a contained responsive
Conclusion? If you use these simple foldunder divs at all, use them only when every foldunder div contains nothing but paragraphs of text. Even then, with foldunder grids you can get maximum screen real estate use for any number of "columns", without needing to pre-declare max-width
. For all others, use foldunder grids, which are described later in this document. It's also perfectly OK, and perhaps advisable, to use foldunder grids for text paragraphs if you want to keep everything consistent and not pre-declare max-width
or limit to just a certain number of columns.
Three Foldunder Columns
Same thing, but three columns, narrower max-width via a different class (foldunder_narrow instead of foldunder_wide).
In my opinion three foldunder columns are less advisable than two. When the rightmost column falls under the leftmost one, but the middle column is still next to the leftmost, it can be confusing about where to read next. Also, three columns become more challenging when long words prevent further word wrap.
I'd recommend using three column foldunders only limited to special cases. one might be where you have lots and lots of short links. For visitors with wide screens, they don't need to do as much vertical scrolling. For narrow mobile screens, they fold under each other, so lots of vertical scrolling, but no horizontal scrolling. Horizontal scrolling is much worse than vertical. The CSS, which is the same as the two column, follows:
div.foldunder_narrow, div.foldunder_wide{ display: inline-block; margin: auto; margin-bottom: 0.5ex; background-color: #ffffff; max-width: 32%; min-width: 200px; vertical-align: top; padding-left: 0.5em; border-style: solid; border-width: 1px; } div.foldunder_narrow{ max-width: 30%; } div.foldunder_wide{ max-width: 46%; }
And the following is the HTML code creating these foldunder divs:
<div class="foldunder_narrow"> <p>A paragraph of Latin long enough to word wrap within the foldunder column, even at the widest widths. Note that this paragraph could be much shorter and still work just fine in a foldover column.</p> </div> <div class="foldunder_narrow"> <p>A second paragraph of Latin long enough to word wrap within the foldunder column, even at the widest widths.</p> </div> <div class="foldunder_narrow"> <p>A third paragraph of Latin long enough to word wrap within the foldunder column.</p> </div>
Benefits and Costs
- Benefits
- Very simple to use
- Don't require use of a containing
<div>
- Easier to debug.
- Costs
- Fails to properly display a contained responsive
<pre>
. - Fails to properly display a contained responsive
<img>
. - Requires pre-declaring
max-width
- Fails to properly display a contained responsive
Conclusion? If you use these simple foldunder divs at all, use them only when every foldunder div contains nothing but paragraphs of text. Even then, with foldunder grids you can get maximum screen real estate use for any number of "columns", without needing to pre-declare max-width
. For all others, use foldunder grids, which are described later in this document. It's also perfectly OK, and perhaps advisable, to use foldunder grids for text paragraphs if you want to keep everything consistent and not pre-declare max-width
or limit to just a certain number of columns.
Lorem ipsum dolor sit amet consectetur, adipisicing elit. Totam dicta dolores eius laboriosam optio, quam at! Perspiciatis voluptatem repellat, velit facilis consequuntur porro perferendis a ad, dignissimos expedita aperiam asperiores.
Lorem ipsum dolor sit amet consectetur adipisicing elit. Accusantium, repellat consectetur aliquid molestiae odit perspiciatis soluta dolore, quidem fuga facere architecto error ipsa non. Ipsam facilis deserunt fugiat temporibus enim.
Lorem ipsum dolor sit, amet consectetur adipisicing elit. Odit quibusdam dolore sed deleniti mollitia perferendis quod facere, magnam ipsam blanditiis quasi aliquid quas impedit unde maiores nostrum aut ad iste.
Column Foldunder with Flex
You can get a similar outcome to foldunder divs by using divs inside a containing div with properties display: flex and flex-wrap: wrap. HTML and CSS follow:
CSS:
div.flex_container{ display: flex; flex-wrap: wrap; } div.flex_container > div.flex_client{ max-width: 22em; margin: 0.2em; padding: 0.1em; vertical-align: text-top; background-color:aquamarine; }
HTML:
<div class="flex_container"> <div class="flex_client"><p>A bunch of latin long enough to wrap within the column.</p> </div> <div class="flex_client"><p>More Latin long enough to wrap within the column.</p> </div> </div>
Notice how the preceding differs from the foldover div tactic in a few ways:
- Width is declared in units of em instead of percent. It won't work right if declared in percent.
- Themargin doesn't need to be set to auto.
- vertical-align works better as text-top rather than top.
There are also behavior differences, because the flex version:
- Miss-aligns vertically at some widths.
- Does not shrink at a narrower widths until all divs have folded under.
Now that everything's explained, the following is a sample of flex foldovers:
Lorem ipsum dolor sit amet consectetur, adipisicing elit. Totam dicta dolores eius laboriosam optio, quam at! Perspiciatis voluptatem repellat, velit facilis consequuntur porro perferendis a ad, dignissimos expedita aperiam asperiores.
Lorem ipsum dolor sit amet consectetur adipisicing elit. Accusantium, repellat consectetur aliquid molestiae odit perspiciatis soluta dolore, quidem fuga facere architecto error ipsa non. Ipsam facilis deserunt fugiat temporibus enim.
inline-flex Foldunder Flex
The Two Foldunder Columns and Three Foldunder Columns sections, both of which are earlier in this document, depend on
display="inline-block. You can also use
display="inline-flex instead. There will be various minor differences. Try it, see which you like better.
Leave Room For Thumbs
One essential and often forgotten mobile device design criteria is that all clickable links and buttons be spaced far apart enough to be operated with thumbs. Remember, the mobile device visitor has no mouse, and typically no stylus either. Imagine pressing a link with your thumb, hitting another link, and wondering which will activate.
Look at the line spacing on this web page. Not the paragraph spacing, the line spacing. It's quite high for readability's sake, but also to keep clickable links and elements farther away from each other. Use a long line height so a second link falling right under a first link won't create problems.The following CSS is how I got my high line spacing:
p{ margin-bottom:2.2ex; line-height: 160%; }
In the preceding, line-height governs the line spacing, and margin-bottom governs the spacing between paragraphs, which should, in my opinion, be recognizably longer than the line spacing so a single glance tells your visitor where paragraphs start and stop. Contrary to old, established text formatting conventions, I make recognizable paragraph spacing even if each paragraph starts with an indentation.
Another factor in thumbs-capable designs is keeping links apart horizontally. This typically comes up in <nav></nav> sections. Use few enough links and short enough links that they stay apart even with narrow screens.
Buttons are good at giving you extra thumb room, as long as they're reasonably separated.
If you use colored divs containing a link each, be sure the whole div is thumbable, not just the text. There's a special place in the devil's playground for web devs who surround clickable text with an unclickable div, just to confuse the user.
Media Queries
Media queries are a huge subject. Media queries give you immense power tailoring web pages for the visitor, but it's a little too tempting to use them excessively and go down the rabbit hole. This section gives you enough info to understand how media queries work, so you can use them for basics like screen size, and web search for the more esoteric ways to use them.
Media queries are like "if statements", based on various properties and capabilities of whatever is rendering the HTML. By "whatever is rendering", I mean it could be a screen, a printer, a television, or many other devices. If it's a screen, then the media query is against the browser.
If you use the Web, you've seen pages with underlying media queries. For instance, have you seen pages that give more information on a full computer screen than on a small device? This is accomplished by a media query against the screen size, where on small screens certain elements are set to display:none; so they don't show up at all.
Perhaps you've seen web pages that print completely differently than they look in a browser. Most likely, this was accomplished by a media query about whether it was a printer, and if it's a printer a lot of CSS is changed to accommodate the printer.
This section contains a simple example using a flexbox, but using it in a slightly different way than the Column Foldunder with Flex section you saw earlier. In this case, the media query does its magic by changing flex-direction from column, which puts flex clients under each other, to row, which puts them side by side, when the screen width exceeds 599px. First you'll see the code, then you'll see the example, complete with Latin.
The CSS and HTML code follows:
CSS
div.flex_container2{ display: flex; flex-direction: column; } @media (width > 599px){ div.flex_container2{ flex-direction: row; } } div.flex_container2 > div.flex_client2{ margin: 0.2em; padding: 0.1em; vertical-align: text-top; background-color: yellow; }
HTML
<div class="flex_container2"> <div class="flex_client2"> <p>Enough Latin to wrap around the flex client div.</p> </div> <div class="flex_client2">< p>And yet more Latin to wrap around the second client div.</p> </div> </div>
The key distinctions in the preceding code are:
- The default is for a screen under 600px, and the media query modifies this if 600px or over.
- The media query's sole action is to change flex-direction if width is 600px or greater. This is an example of mobile-first design.
The results of the preceding code (but with Latin) follows. If possible look at it with Firefox's responsive view, because Chromium's responsive view is defective. Some observations will be documented following the results:
Lorem ipsum dolor sit amet consectetur, adipisicing elit. Totam dicta dolores eius laboriosam optio, quam at! Perspiciatis voluptatem repellat, velit facilis consequuntur porro perferendis a ad, dignissimos expedita aperiam asperiores.
Lorem ipsum dolor sit amet consectetur adipisicing elit. Accusantium, repellat consectetur aliquid molestiae odit perspiciatis soluta dolore, quidem fuga facere architecto error ipsa non. Ipsam facilis deserunt fugiat temporibus enim.
Notice several things about the preceding:
- It doesn't suffer from vertical alignment instability the way flex-wrap flexbox setups do.
- Because it doesn't have a width or max-width specification, it fills whatever width it's given, whether two columns or one.
- Columns collapse horizontally, first as two columns, then as one.
The media query flex direction technique is a good, simple, practical example, but it's not without its drawbacks. Care must be taken when using flexboxes that an order property doesn't change the order from the DOM order, because if that happens, visually handicapped people using screen readers will be horribly misled. Also, media queries can be overused, to the point that the web page is difficult to maintain.
Other Uses of Media Queries
As previously mentioned, the example used in this section is a simple one, and one of many possible. Media queries can query for whether the device/browser (user agent is the buzzword) can hover. You can query whether there's a pointer device, and how precise it can be. This is handy if you want to accommodate a touchscreen-only visitor with larger click targets spaced farther apart.
Grid Layouts
Grid layouts are extremely powerful, and easy to abuse. Grid layouts are especially handy with web pages that are mostly images, or images with text at their side, top or bottom. Used properly, they can give a nice, airy, organized look to such web pages.
Another use of grid layouts is to implement the golden ratio, which is supposedly a very pleasing look. I'm not a fan of this because the page looks too busy, but your mileage may vary.
Check out this example of a non-responsive grid layout, and the HTML and CSS code used to implement it. div.grid-container contains each grid element. The key declarations that make it work are display: grid; and grid-template-columns: auto auto auto;. The former declares that its contents are a grid, and the latter declares that there will be three columns, each equal width, and that their sum consumes all available width.
The number of "auto" strings is the number of columns, so there are three columns. If you were to change the number of "auto" strings, with a media query for instance, you'd change the number of columns. Adding "auto" strings with increasing screen width, via media queries, is one way you could make this grid fold under, thereby making it responsive. There's another way to make an underfolding, responsive grid, which is discussed in the section after this one. But meanwhile, there's more you need to know about ordinary grid layouts...
The frUnit of Measure
Let's discuss the grid-template-columns attribute. To review, the grid-template-columns linked to in the preceding paragraph looks like the following:
grid-template-columns: auto auto auto;
The preceding CSS declaration splits the container's contained divs into three equal columns. The auto argument means the column it represents takes up all the width it can. Because there are three of them, each takes one third of the available width. You can achieve the same result with fr units, as shown in the following CSS declaration:
Now consider the following modification to the previous CSS declaration:
grid-template-columns: 1fr 1fr 1fr;
In the preceding, the total width available is divided between three equal 1fr widths. The meaning of this becomes clearer in the next couple paragraphs, but please take notice of the fact that converting each auto to 1fr doesn't change the web page one bit. Next, consider the following CSS declaration, which makes three columns of differing sizes:
grid-template-columns: 4fr 2fr 1fr;
The preceding CSS declaration proportions the size of each column. Specifically, the first column is 4/7 of the available width, the second column is 2/7, and the third column is 1/7. Although the first column is twice the width of the second column, and the second is twice the size of the third, the first column is more than half of the total width. It is 4/7, not 4/8 of the available width. When using fr units within a grid-template-columns declaration, the browser adds up all the fr unit quantities, uses that sum as a denominator, and uses each fr unit quantity as its numerator. You can have fractional quantities on fr units, so you can achieve any proportions you want.
Another fact, without much detail. There's a grid-template-rows that works the same way for rows that grid-template-columns works with columns. It can use fr units and auto specifiers and pretty much anything else grid-template-columns can do. The grid-template-rows property isn't used as much because scrolling downward on a web page is easy and pleasant, whereas scrolling horizontally is a real pain.
The CSS repeat()Function
If I didn't view CSS with awe before (actually I did), then after seeing the repeat() function, I'm totally sold.
The repeat() function is incredibly featureful, so this subsection and the rest of this document cover only some of the features. If you want to know everything about the repeat() function, see this Mozilla Developer website, but I recommend you save this for later, until you've learned the repeat() function capabilities detailed in the document you're now reading.
Let's take the simplest use of the repeat() function. If you remember, we split into three equal columns with either of the two following declarations:
grid-template-columns: auto auto auto;
grid-template-columns: 1fr 1fr 1fr;
The exact same layout can be achieved with the following declaration:
grid-template-columns: repeat(3,1fr);
The repeat() CSS function takes two arguments: The number of columns (or rows if inside grid-template-rows), and the thing(s) to be repeated. In the simple repeat(3,1fr) case, this means repeat a 1fr column three times.
Next, imagine needing the left column to contain several short links, each below the previous. Imagine needing two more columns of equal size. The following grid-template-columns does what you need:
grid-template-columns: 15em repeat(2, minmax(150px, 1fr));
In the preceding, the left column is 15em, and the remainder is divided equally between the other columns, with each of the rightmost columns collapsible to a size of the left and right padding plus the length of the longest indivisible word. If either of the two rightmost column has too long an indivisible word, the rightmost column gets clipped, and horizontal scrolling is needed.
The reason I expressed the left column's width in em units is to make it relative to font size, so it will work at all fonts and screen magnifications or shrinkages.
There are a zillion ways to use and misuse grids. You can do the same things with grid-template-rows as with grid-template-columns. You can make your web page into a patchwork quilt of differently sized areas, if you drive on that side of the road. You're now equipped to research these things to make the exact grid web page you want.
The grid subject not yet covered is responsive grids, where grid cells are capable of folding under each other, or if you think mobile-first, the capability of grid cells moving up to the next row as the screen gets wider. The next section covers this subject.
Responsive, Foldunder Grids
Generic Foldunder Grid
This generic example features multiple same-sized grid cells that fold under as needed, so the number of columns depend only on the cell width and the screen or containing div length. The following is an example that can be worked with via the "responsive design" tool of Firefox:
You can see the preceding was just a bunch of 100px wide divs, piled to the right where possible, piled under where necessary. You can use the Responsive Tool from Firefox to view what happens as the screen width widens and narrows. If you want the exact code that produced this, look at the source HTML and CSS of this page. As a short cut, the following CSS declaration is the main part of what got this job done:
grid-template-columns: repeat(auto-fit, minmax(100px,1fr));
In the preceding code, auto-fit is the numeric argument to repeat(), meaning "repeat as many times as you can fit". Now notice the minmax() function, that sets the width to somewhere between the lower number (100px and the higher number (1fr). Selecting the lower number (first argument) of minmax() is particularly important for the following reasons:
- If the lower number is higher than the width available at the screen or containing element, the text walks past its grid cell's right edge, and causes a horizontal scrollbar to appear, which is just what responsive web pages seek to avoid.
- If the lower number is lower than the sum of a the sum of cell's left padding plus the length of its longest indivisible word, that longest word walks past its grid cell's right border, even when there's plenty of room for cells to fold under.
This auto-fit methodology is a great way to display one column at small device widths that widens to perhaps 3 or at the most 4 columns on a full width screen. Beyond 4 columns, in my opinion it's more of a showpiece than something practical. It certainly proves the point that grid layouts can fold under without media queries.
Foldunder Grid With Specified Cell Widths
With specified cell widths, cells don't widen or narrow, so this effect can be done many different ways. This subsection demonstrates it being done with a grid and without media queries. First, take a look at the following display with Firefox's Responsive Design tool:
The preceding yields fixed-width columns that fold under each other as the width decreases, or thinking mobile-first, trickle up and to the right as the width increases. The following is the CSS declaration that facilitates this behavior:
display: grid; grid-template-columns: repeat(auto-fit, 200px);
Each column is 200px, so as many columns form as can be accommodated by the screen width. I suggest you take a look at this page's source code, at the CSS selectors fixed-width-foldunder-grid-container and fixed-width-foldunder-grid-container>div to see the details. You'll see demonstration of column-gap and row-gap, as well as some other things not introduced before now.
The fixed width foldunder grid's results are similar to those for flexboxes and just plain foldunder divs, but it's good to know about them.
Responsive, Foldunder Grids As a Replacement For Foldunder Divs
Foldunder grids perform better and more reliably and more universally than foldunder divs. The (slight) downside is that foldunder grids require an additional container div and quite a bit of CSS for contained elements. My advice is to use foldunder grids in most situations.
Benefits and Costs vs Responsive Divs
- Benefits
- Properly displays a contained responsive
<pre>
. - Properly display a contained responsive
<img>
. - Doesn't require pre-declaring
max-width
.
- Properly displays a contained responsive
- Benefits
- Not quite as simple to use
- Requires use of a containing
<div>
. - More difficult to debug.
Creating Responsive Grids to Replace Responsive Divs
This subsection describes how to set up and use responsive grids for side-by-side performance on wide screens. If you share one CSS file for all your pages, you only need to set it up once.
div.example_foldunder_grid_container { display: grid; grid-template-columns: repeat(auto-fit, minmax(360px, 1fr)); padding: 10px; } div.example_foldunder_grid_container>div { padding: 5px; margin: 3px; vertical-align: text-top; } div.example_foldunder_grid_container>div>p { margin-top: 0; } div.example_foldunder_grid_container>div>img { margin-top: 0; }
In the preceding (or to the left) CSS, div.example_foldunder_grid_container
uses display: grid;
to create a grid, and uses grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
to fill the available width with as many equal-width columns as possible. The minmax(360px, 1fr)
div.example_foldunder_grid_container>div
specifies that any contained div has certain lengths and widths. Because these divs are contained inside div.example_foldunder_grid_container
, they automatically display side by side, or if things get too narrow, under each other.
The one remaining problem is that different types of data, such as <p>
, <pre>
, <img>
, etc, start at different heights. This problem is solved by specifying that such elements, if they are contained in a div contained by the foldunder grid container, have a zero top margin.
The following shows the HTML to use the preceding CSS to put a <pre class="code"></pre>
and a text paragraph side by side.
<div> <pre class="code"> #include <stdio.h> int main(int argc, char * argv[]){ printf("Hello World.\n"); return 0; } </pre>
The preceding (or to the left) is the source code necessary to display the C code for a C Hello World. The actual C code starts with the #include
line and ends with the }
on the line after the return 0;
. Note that the code and the text paragraph are both wrapped in ordinary div elements, and those div elements are wrapped in a <div class="example_foldunder_grid_container"></div>
element.
Whenever you need to put an responsive element which solves a non-responsive problem such as source code or images, these foldunder grids are a great way to do it.
Going Whole-Hog With Grids
If you have the time and inclination, tremendous things can be done with grid layouts. You can toss images of different widths helter-skelter around the page. You can make your page look like Amazon or Ebay, although it must be said that, on 9/14/2022, running amazon.com through the W3 validator caught 141 errors and 96 warnings. Just saying. The importance and techniques of web page validation are detailed in the Validating and Debugging HTML and CSS Web Workmanship document.
One of the selling points of the Bootstrap tool is being able to lay out a complicated grid. However, a day or two's study of grid layouts, with some experimentation, can get you laying out complicated grid layouts.
Wrapup
This document has covered a lot of ground. If you didn't know before, you've learned what responsive and mobile-first mean. You've learned that the two ways of achieving responsiveness are 1) using media queries, and 2) writing CSS to collapse and fold under. The five enemies of responsiveness are tables, source code, graphics/pictures/video, many of the multicolumn methods being used today, and long words. Tables should be used only for tabular data and should be kept narrow. Tables should never be used to make multiple columns. This document has shown several correct methods to achieve multiple columns, without disenfranchising people with small screens or blurry vision.
Graphics can be made to render smaller on narrower screens. You can also make them links to full sized graphics. Long words can be defanged by not using them, or inserting hard or soft hyphens, or once in a while the wbr element.
Foldunder columns are simple if you use display: inline-block. This method doesn't require a parent container (other than body). When you need to fold under with shrinkable pre or img elements, foldunder grid layouts are a great way to do it.
Column foldunder is also available with a container having declaration display: flex; and flex-wrap: wrap;, in which case the container's children fold under. This method produces columns which don't compress horizontally until they're all folded under, which may or may not be what you want. To achieve the best result with flex, keep to the following three guidelines:
- Declare max-width in units of em instead of percent.
- The margin doesn't need to be set to auto.
- vertical-align works better as text-top rather than top.
Mobile-friendliness requires best practices for user input as well as output. Use a line spacing tall enough so that a person clicking with their thumbs won't simultaneously hit two links. Setting line-height: 160%; is an excellent line spacing setting. Buttons are a great way to guarantee thumb-friendliness. If you use divs containing a link, make sure that clicking anywhere in the div invokes the link.
Media queries change CSS according to screen width. They can be used to eliminate whole sections for those on mobile devices, or to create a one column display for narrow devices. Using media queries to change flex-direction on flex containers between column and row to achieve foldunder, while making maximum use of screen real estate at any screen width.
Grid layouts are a huge subject. They can be used with or without foldunder capability. Important things about grid layouts include the fr unit, the grid-template-columns property, and the repeat() function. Grid layouts can be used to produce complex code with a messy appearance, so don't go overboard.
Foldunder grid layouts are ideal for displaying at least one non-text display side by side with another. For instance, a collapsing/horizontal scrollbar pre and some paragraphs, or an img and some paragraphs, or two collapsing pre's, or several collapsible images.
Now that you've mastered responsiveness, it's time to learn one more thing about responsive web design: How to implement side notes in a responsive way.