Responsible Web Applications

Responsive Web Design
Do we really need responsive web design for our web application? We will only use our web application on desktop computers!
I've heard this argument many times, but in the long term, it has never turned out to be true. For this reason, I've created Joy's two laws of web development:
Joy’s First Law of Web Development
There is no such thing as a non-responsive web application
Your web application WILL be opened in a mobile phone or tablet at some time in the future and your users WILL expect it to work correctly.
Joy’s Second Law of Web Development
Any work you do now to ensure that your web application behaves responsively WILL be appreciated in the future.
When it comes to the technical implementation of responsive design, there are two main categories of components that we need to develop:
I want to cover these two aspects in the next sections
Responsive Layout Containers
We firstly need to make sure that we put a lot of thought into designing layout containers which adjust themselves based on the size of our viewport.
In the following demo, we can see how we can define a layout conceptually using different grid areas.
The demo shows five content areas: Header, Sidebar, Main Content, Second Sidebar, and Footer. On a mobile device, these areas are shown vertically stacked. On larger viewports, the example layout now has three rows and three columns. The Header area spans the full width of the top of the viewport in the first row. In the middle row, the Sidebar, Main Content, and Second Sidebar areas are positioned next to each other in a three column layout, with the Main Content area expanding to take up as much space as it can. The Footer area then spans the full width of the viewport in the bottom row of the layout.
How can we implement this? To do this, I like to use the following technique.
Explicit CSS Grid Layout with Breakpoints
Using CSS Grid, I like to use the following technique to declaratively define a default CSS grid for our content. This is then the CSS which is used for smaller devices.
CSS for Mobile Devices
.layout {
display: grid;
grid-template-areas:
"header"
"sidebar"
"main"
"sidebar-right"
"footer";
grid-template-rows: auto auto 1fr auto auto;
}
.layout > header {
grid-area: header;
}
.layout > aside:nth-of-type(1) {
grid-area: sidebar;
}
.layout > main {
grid-area: main;
}
.layout > aside:nth-of-type(2) {
grid-area: sidebar-right;
}
.layout > footer {
grid-area: footer;
}
Note that this markup explicitly references the
main,
header,
footer, and
aside semantic HTML elements in the CSS code.
This was intentional here, because it forces us to then use the semantic HTML elements and add important landmarks to our web application which improves its accessibility.
With the CSS child combinator operator (>) we ensure that this element targeted is the direct child of the parent with my layout class (which we would probably add directly to our HTML body).
CSS for tablets or larger devices
Since we have already defined the grid-areas for our HTML elements, we can now declaratively change the layout using a relatively short CSS snippet within a media query:
@media (min-width: 40rem) { /* Breakpoint Tablet portrait up */
.layout {
grid-template-areas:
"header header header"
"sidebar main sidebar-right"
"footer footer footer";
grid-template-rows: auto 1fr auto;
grid-template-columns: 20% 1fr 20%;
}
}
Note that when you are defining your breakpoints for your application, you should consider the correct way to do CSS breakpoints.
Squishy Components
After we have a responsive layout, the next step is to make sure that all of our components are "squishy". This means that when we place a component into a designated area of a layout, it should never push itself outside of its designated area. Instead it should "squish" down to fit inside of the available space.
This is especially important because our layout container assumes that all of its content is going to fit, and if this assumption is not true, this could cause the whole layout to be wider than the viewport and make it necessary for the user to scroll horizontally.
Flexbox + Flex Wrap
.container {
display: flex;
flex-wrap: wrap;
}
We can use the display: flex; rule to make the container
a flexbox and
then use the flex-wrap: wrap; rule to wrap content within the flexbox.
When there is not enough space for the items to be placed horizontally, they will begin to wrap and be shown stacked vertically instead.
flex-wrap to wrap content in a flexbox.
The demo shows a flexbox containing two blocks: a block containing a title and a description, and a block containing a price, time, and amount. On a larger devices, these block can be positioned next to each other horizontally. On smaller devices with flex-wrap activated, the second block containing the price, time and amount will wrap onto the next line and be positioned underneath the first block.
Nested Flexboxes
It is also possible to nest flexboxes inside each other to create more advanced responsive behavior. This next example shows the same flex container from our last example, but highlights the inner flexbox instead of the outer flexbox.
The demo shows the same demo as the one in the previous example, but in this instance, the price, time, and amount items are highlighted because they are also contained within an inner flexbox. This adds an extra layer to the responsiveness: when the viewport gets so small that there is no longer space for these three items to be positioned next to each other horizontally, they will begin to wrap as well.
Intrinsic Grid
.container {
display: grid;
grid-template-columns:
repeat(auto-fill, minmax(var(—col-width), auto));
}
We can use the CSS repeat function
with grid-template-columns in order to create an intrinsic grid which will generate as
many columns as fit in the given space. An example using this type of grid is available in
my demo for live-coding css layout.
The demo shows a grid with 6 different content blocks that are positioned within an intrinsic CSS grid. On mobile devices, there is only enough space for a single column, so the blocks are all positioned within this column. When there is enough space for two columns, the layout will shift and the elements will be positioned within the grid in two columns and end up filling three rows. When there is enough space for three columns, the layout will shift again and the elements will be positioned within the grid in three columns and will end up filling two rows. This layout pattern will continue, and a grid will always be generated with as many columns as fit within the viewport size.
Horizontal Scrolling
.horizontal-scroll {
overflow-x: auto;
}
When we talk about creating an application which is responsive, this doesn't mean that we need to optimize all of our layouts for small device screens. In certain contexts, we will have larger data representations (e.g. tables or code examples), which we also want to be available for smaller devices even if they are not optimized for that layout.
For this, I like to use a wrapper around tables and code examples which make them able to be scrolled horizontally when there is not enough space for them in the current layout.
In the example, a large table with twenty columns is shown. On smaller devices, there is not enough space for the whole table to be shown. In this case, the large table is shown within a container that fits within the viewport, and the user can scroll within that container in order to view all of the contents.
Squishy Text
.squishy-text {
word-break: break-word; /* Samsung browser */
word-wrap: break-word; /* IE 11 */
overflow-wrap: anywhere;
-webkit-hyphens: auto;
-ms-hyphens: auto;
hyphens: auto;
}
The following example is a CSS meme now. By default, long words in an HTML document will not be hyphenated by default, so they will break out of their containing box instead of squishing to fit inside of it. This is especially important when we are dealing with a language which has a lot of long words (*cough* German *cough*).
The previous CSS snippet is one I have successfully used to make my text squishy in different contexts.
CSS is awesome
CSS is awesome
Accessible Web Design
We now come to accessibility. Here I feel that I can only scratch the surface of the different things that we should consider. I also am learning new things all the time, so I'm sure that this list is not exhaustive. But I do think it is a good starting off point.
Headings
Don’t skip heading levels.
In your HTML Document, you need to ensure that your document hierarchy is complete and doesn't skip levels. Otherwise, users who depend on assistive technologies will get confused because it will seem like content is missing.
This is a mistake that many developers make,
because we pay attention to how the heading appears visually without making sure that an h2 is always
directly followed by a h3.
Landmarks
We should make sure that we use elements like main and header because then we get HTML landmarks out of the box. This makes the page much easier to navigate.
Note that the main element is not well supported for IE11, so if you have to
support older browsers, you should also consider using skip links.
nav Element
When you are providing links for a user to navigate within your page (e.g. a navbar or a table of contents), you should wrap them in a nav.
label Element
Always add a label to let assistive technologies know which data is supposed to be entered in an input field.
<label>
First Name
<input type="text" value="name" placeholder="Jane" />
</label>
Here we either wrap the input field directly in the label,
or we can use the for attribute and link it to a specific input field.
Here it is important to not use the placeholder attribute to label the input field.
The placeholder attribute should be used to show an example of how the data we expect should appear.
This is particularly important for users who have congnitive disabilities, because when the instructions
in the placeholder disappear, they may not remember what they were supposed to enter into the field.
Please also read this article about why placeholder are problematic.
List Elements
Using lists (an unordered list, an ordered list, or a description list) for things in a UI will also add extra context for assistive technologies. For instance, it will tell assistive technologies how many elements are contained in a list.
In practice, description lists can be difficult to style because we are not allowed to add an extra div as a wrapper around the dt and dd elements.
For this reason, I've also done some experiments about how to best group information in the UI.
Here there isn't a single correct solution.
You will have to find out what works best for your UI.
Update: Originally, I discussed having difficulties styling description lists.
This statement is no longer correct for modern browsers which implement the
HTML 5.2 Recommendation
because they now allow a div as a wrapper around the dt and dd elements.
Accordions
If we need an accordion, or an element which shows/hides a content area, we can use the HTML details element.
<details>
<summary>Toggle Button</summary>
Content which will be expanded/collapsed when clicking the
summary element
</details>
We can also implement this in JavaScript using a button and the
aria-expanded attribute.
The aria-expanded attribute adds context information to the button which will tell the screenreader
if the area that the button is toggling is currently collapsed or expanded.
I have seen incorrect implementations of this where the developer thought that the attribute was intended to be added to the content block which is expanded or collapsed, but this is not the case and that implementation would be confusing to any user of an assistive technology. If we do spend the effort to set aria roles in our application (which we should), we need to test our application and make sure they are used correctly! No aria usage is better than incorrect aria usage.
I have implemented this behavior many times, and when I do, I prefer to use a custom element and activate the toggle with progressive enhancement. This means that my toggle button is hidden by default before JavaScript is activated, and the content area that is to be collapsed/expanded will only be hidden once JavaScript is activated.
The contract for the toggle-button component that I usually end up writing therefore usually looks something like this:
<button is="toggle-button" data-target="#section2"
aria-expanded="false" hidden>
Toggle Section 2
</button>
aria-expanded is an attribute of the BUTTON which tells assistive technologies if the content area that is being expanded/collapsed is currently visible or not.
And my toggle-button implementation usually looks a lot like the following
(I really need to standardize this and publish a custom element one of these days...):
class ToggleButton extends HTMLButtonElement {
connectedCallback () {
this.removeAttribute("hidden");
if (this.getAttribute("aria-expanded") !== "true") {
this.setAttribute("aria-expanded", "false");
this.target.classList.add("hide");
}
this.addEventListener("click", this.toggle.bind(this));
}
toggle () {
let classList = this.target.classList;
if (classList.contains("hide")) {
classList.remove("hide");
this.setAttribute("aria-expanded", "true");
} else {
classList.add("hide");
this.setAttribute("aria-expanded", "false");
}
}
get target () {
return document.querySelector(this.getAttribute("data-target"));
}
}
customElements.define("toggle-button", ToggleButton, { extends: "button" });
Here is a code demo of this component.
aria-label and aria-labelledby
Sometimes we have visual elements which add information to the UI, but are missing in the UI. For these cases, we can use an aria-label attribute with a textual description of what the visual element is showing. If there is already a UI element available, we can also use aria-labelledby and reference the HTML id of the existing element. The HTML title element is not well supported by assistive technologies, so it should not be used to do this.
Here it really helps to test your UI in a screenreader so that you can figure out where extra labels would be helpful
Advertising by Adpathway




