Left ArrowBack

notes / CSS / alignment click target

alignment click target

A web page design wireframe.

Alignment + Click Target

Last Tended

Status: seed

In the context of design, the use of straight lines & right angles communicate that it has been crafted by a human. That it has been designed. Nature doesn't use them. When creating a webpage, it is easy to create layouts constructed with straight lines & right angles. However, when we need to incorporate click-target size requirements, layouts can lose their alignment. Below defails an approach that fulfills these requirements without breaking alignment.

A web page design wireframe highlighting 16px gap between all elements.

1. Requirements

Imagine we need to code the layout for a web page. It will have 3 root elements:

  • a back link in the top left,
  • a list below the link &
  • a section for content to the right.

Elements should be positioned so:

  • the link & list items' text should align vertically,
  • the link & main's text baselines should align horizontally,
  • 16px space between elements & between elements and page border.
A web page design wireframe.

2. Add Content

Add the contents to the page & remove any excess white-space. To achieve this:

  • set all margins & padding to 0 &
  • use Capsize to generate the CSS required to trim unwanted vertical space above & below text.

The <body/> will be acting as a layout component. I believe a trait of a good layout component is it adapts to its contents. I'm using a CSS grid to position the root elements. The left column's width is set to auto, enabling it to adapt to the link & list's contents. The right is set to 1fr, filling the remaining width of the layout.

localhost:3000

Console

<a class="backLink capsizedText" href="">
   Back
</a>

<ol class="list">
   <li class="capsizedText">item 1</li>
   <li class="capsizedText">item 2</li>
   <li class="capsizedText">item 3</li>
</ol>

<main class="main">
   <p class="capsizedText">
      main content
   </p>
</main>

A web page design wireframe.

3. Add Space

Add space between elements:

  • padding: 16px; to <body/>
  • gap: 16px; to <body/>'s grid.
  • gap: 16px; to <ol/>'s flex container.

Visually, we are now fulfilling all requirements.

localhost:3000

Console

/* CSS reset ----------------------- */
*, *::before, *::after {
   box-sizing: border-box;
}

* {
   margin: 0;
   padding: 0;

   outline: 1px solid black;
   outline-offset: -1px;
}

a {
   text-decoration: none;
}

ol {
   list-style: none;
}

/* Text styles ---------------------- */
.capsizedText {
   font-family: sans-serif;
   font-size: 14.0659px;
   line-height: 25px;
}

.capsizedText::before {
  content: "";
  margin-bottom: -0.5195em;
  display: table;
}

.capsizedText::after {
  content: "";
  margin-top: -0.5469em;
  display: table;
}

/* Layout --------------------------- */
body {
   padding: 16px;

   display: grid;
   grid:
      "backLink main" auto
      "list main" auto
      / auto 1fr;
   gap: 16px;
}

.backLink { 
   grid-area: backLink; 
}

.list { 
   grid-area: list; 

   display: flex;
   flex-direction: column;
   gap: 16px;
}

.main { 
   grid-area: main; 
}
A web page design wireframe with 1 element highlighted in red.

4. Increase Click-Target

Unfortunatley, there is an accessibility problem with the link. The size of the clickable area is only 38 x 10px. The recommended minimums are:

  • 44 x 44px for AAA rating.
  • 24 x 24px for AA rating. This can be reduced to 20px if:
    • the area is inline (such as a a link within a paragraph) or
    • there is a minimum 4px gap between adjacent clickable areas.

1 approach to fix this is to add padding to the link:

localhost:3000

Console

/* CSS reset ----------------------- */
*, *::before, *::after {
   box-sizing: border-box;
}

* {
   margin: 0;
   padding: 0;

   outline: 1px solid black;
   outline-offset: -1px;
}

a {
   text-decoration: none;
}

ol {
   list-style: none;
}

/* Text styles ---------------------- */
.capsizedText {
   font-family: sans-serif;
   font-size: 14.0659px;
   line-height: 25px;
}

.capsizedText::before {
  content: "";
  margin-bottom: -0.5195em;
  display: table;
}

.capsizedText::after {
  content: "";
  margin-top: -0.5469em;
  display: table;
}

/* Layout --------------------------- */
body {
   padding: 16px;

   display: grid;
   grid:
      "backLink main" auto
      "list main" auto
      / auto 1fr;
   gap: 16px;
}

.backLink { 
   grid-area: backLink;
   padding: 8px; 
}

.list { 
   grid-area: list; 

   display: flex;
   flex-direction: column;
   gap: 16px;
}

.main { 
   grid-area: main; 
}

Although this has fixed the accessibility problem, it has broken the layout's alignment:

  • the link & list items' text no longer align vertically,
  • the link & main's text no longer align horizontally &
  • the space between the left & right columns has increased beyond 16px. Calculated from the right-most letter in the left column to the left-most letter in the right column.
A web page design wireframe with 1 square highlighted.

5. Alignment Fix

We can use a different approach that will solve both the accessibility problem while maintaining the layout's alignment. Instead of adding padding, add an absolutley positioned pseudo-element to the link. This allows setting a click target to any size without effecting the positioning of the link or its adjacent elements.

/index.css

...

.backLink { 
   grid-area: backLink;

   position: relative;
}

.backLink::after {
   --padding: 12px;
   --size: calc(100% + 2 * var(--padding)); 
   --offset: calc(-1 * var(--padding));

   content: "";

   width: var(--size);
   height: var(--size);

   position: absolute;
   top: var(--offset);
   left: var(--offset);
   
   background: hsla(0, 0%, 0%, 0.1);
}

...

As capsize makes use of pseudo-elements, the link's text is moved into a <span> to prevent styles interfering with each other.

localhost:3000

Console

/* CSS reset ----------------------- */
*, *::before, *::after {
   box-sizing: border-box;
}

* {
   margin: 0;
   padding: 0;

   outline: 1px solid black;
   outline-offset: -1px;
}

a {
   text-decoration: none;
}

ol {
   list-style: none;
}

/* Text styles ---------------------- */
.capsizedText {
   font-family: sans-serif;
   font-size: 14.0659px;
   line-height: 25px;
}

.capsizedText::before {
  content: "";
  margin-bottom: -0.5195em;
  display: table;
}

.capsizedText::after {
  content: "";
  margin-top: -0.5469em;
  display: table;
}

/* Layout --------------------------- */
body {
   padding: 16px;

   display: grid;
   grid:
      "backLink main" auto
      "list main" auto
      / auto 1fr;
   gap: 16px;
}

.backLink { 
   grid-area: backLink;

   position: relative;
}

.backLink::after {
   --padding: 12px;
   --size: calc(100% + 2 * var(--padding)); 
   --offset: calc(-1 * var(--padding));

   content: "";

   width: var(--size);
   height: var(--size);

   position: absolute;
   top: var(--offset);
   left: var(--offset);
   
   background: hsla(0, 0%, 0%, 0.1);
}

.list { 
   grid-area: list; 

   display: flex;
   flex-direction: column;
   gap: 16px;
}

.main { 
   grid-area: main; 
}

We now have a layout that adapts to its content, has alignment across all elements & passes accessibility requirements.

Where to Next?

A sci-fi robot taxi driver with no lower body