---
sidebar_position: 61
tags: [Web, CSS, a11y]
---

# Accessibility

## Screen Reader

```css
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  white-space: nowrap;
  border-width: 0;
  clip-path: polygon(0 0, 0 0, 0 0);
}

.not-sr-only {
  position: static;
  width: auto;
  height: auto;
  padding: 0;
  margin: 0;
  overflow: visible;
  white-space: normal;
  clip-path: none;
}
```

## Focusable Areas

Focusable areas:

- Elements whose `tabindex` value is not null.
- The shapes of area elements in an image map.
- The sub-widgets of elements: e.g. video controls.
- The scrollable regions of elements.
- The viewport of a `Document`.
- User agent focusable area.

## Keyboard

添加键盘访问样式:

- `outline`.
- `:focus-visible`.
- `:focus`.

:::tip[HTML Order vs CSS Order]

[HTML source order vs CSS display order](https://adrianroselli.com/2015/10/html-source-order-vs-css-display-order):

`float`/`absolute`/`flex`/`grid` CSS display order
can't change HTML source `tab` order.

:::

## Touch

WCAG standard for [touch targets](https://www.sitepoint.com/touch-targets-and-web-accessibility):

- [Level AA](https://www.w3.org/TR/WCAG22/#target-size-minimum):
  Least 24x24 CSS pixels or space between targets.
- [Level AAA](https://www.w3.org/WAI/WCAG21/Understanding/target-size.html):
  Least 44x44 CSS pixels.

```css
.icon-button {
  width: 48px;
  height: 48px;
  padding: 12px;
  background: none;
  border: none;
}
```

## DPR

Device pixel ratio (DPR):

一般情况下,
PC 屏幕 DPR 为 1,
1 个逻辑像素 = 1 个物理像素,
移动端 DPR 为 2 或 3,
1 个逻辑像素 = 2 或 3 个物理像素,
由此产生
`移动端/Retina 屏幕 1px 边框 (pixel border)`
问题:

- 伪元素 + `scale` 变换.
- `border-image`.
- `background-image`.
- `background` gradient.
- `box-shadow`.
- `viewport` + `rem`.

```css
.scale-1px {
  position: relative;
  border: none;
}

.scale-1px::after {
  position: absolute;
  bottom: 0;
  width: 100%;
  height: 1px;
  content: '';
  background: #000;
  transform: scaleY(0.5);
  transform-origin: 0 0;
}

.border-image-1px {
  border-width: 0 0 1px;
  border-bottom: none;
  border-image: url('../img/line.png') 0 0 2 0 stretch;
}

.background-image-1px {
  background: url('../img/line.png') repeat-x left bottom;
  background-size: 100% 1px;
}

.background-gradient-1px {
  background:
    linear-gradient(#000, #000 100%, transparent 100%) left / 1px 100% no-repeat,
    linear-gradient(#000, #000 100%, transparent 100%) right / 1px 100% no-repeat,
    linear-gradient(#000, #000 100%, transparent 100%) top / 100% 1px no-repeat,
    linear-gradient(#000, #000 100%, transparent 100%) bottom / 100% 1px no-repeat;
}

.box-shadow-1px {
  box-shadow: inset 0 -1px 1px -1px #c8c7cc;
}
```

```ts
// Change viewport scale
const scale = 1 / window.devicePixelRatio
const viewport = document.querySelector('meta[name="viewport"]')
viewport.setAttribute(
  'content',
  `width=device-width,user-scalable=no,initial-scale=${scale},maximum-scale=${scale},minimum-scale=${scale}`
)

// Set root font size
const docEl = document.documentElement
const fontsize = `${10 * (docEl.clientWidth / 320)}px`
docEl.style.fontSize = fontsize
```

## Graceful Degradation

Write old browser css code,
then write modern browser css code:

```css
.grid {
  display: flex;

  /* old browser will ignore this rule */
  display: grid;
}
```

## ARIA

- W3C official ARIA [examples](https://github.com/w3c/aria-practices).
