JS Fest 2019. Mauricio Palma. You can’t read this sentence - A11y automation
15 years ago…
JS Fest 2019. Mauricio Palma. You can’t read this sentence - A11y automation
JS Fest 2019. Mauricio Palma. You can’t read this sentence - A11y automation
7 years ago…
2012
JS Fest 2019. Mauricio Palma. You can’t read this sentence - A11y automation
JS Fest 2019. Mauricio Palma. You can’t read this sentence - A11y automation
JS Fest 2019. Mauricio Palma. You can’t read this sentence - A11y automation
She had a long
history…
The
grandma
2012 From
To
They founded their
label and…
The Man
JS Fest 2019. Mauricio Palma. You can’t read this sentence - A11y automation
JS Fest 2019. Mauricio Palma. You can’t read this sentence - A11y automation
Today
Mauricio Palma
Co-founder and all kind of things @WDLK
Product Engineer @sinnerschrader
everywhere else @palmaswell
But
Why?
Back in
The Day
Way
harder!
opportunity
Nature
of the web
We use our
our abilities
JS Fest 2019. Mauricio Palma. You can’t read this sentence - A11y automation
You can’t read
this sentence
A11y automation
April, 2019
JS Fest 2019. Mauricio Palma. You can’t read this sentence - A11y automation
That was
awkward! Right?
JS Fest 2019. Mauricio Palma. You can’t read this sentence - A11y automation
Literally
hurts!
217 million
How to
fix the
numbers?
Blurry Vision
JS Fest 2019. Mauricio Palma. You can’t read this sentence - A11y automation
Key Takeaways
Publish all information and content from your site in your HTML
Use semantic HTML and the appropriate ARIA landmarks
Write screen reader friendly markup
Provide keyboard navigation
Partial vision loss
JS Fest 2019. Mauricio Palma. You can’t read this sentence - A11y automation
Key Takeaways
Besides the mentioned semantic HTML and screen reader friendly markup
You should follow a linear logical layout, that supports at least 200% magnification
Central vision loss
JS Fest 2019. Mauricio Palma. You can’t read this sentence - A11y automation
Key Takeaways
Always put form elements in context. Meaning putting buttons, inputs, and notifications
together in a logical manner
For action elements in your interface use a good combination of colors, shapes, and text
Do not rely on colors to convey meaning
Dyslexia
JS Fest 2019. Mauricio Palma. You can’t read this sentence - A11y automation
Key Takeaways
Align your text to the left and keep a consistent layout
Keep content short, clear and simple
Consider producing materials in other formats (for example audio or video)
Let the users change the contrast between background and text
Colorblindness
JS Fest 2019. Mauricio Palma. You can’t read this sentence - A11y automation
JS Fest 2019. Mauricio Palma. You can’t read this sentence - A11y automation
Key Takeaways
Make sure that colors are not your only method of conveying important information.
Sunlight
Bad lightning
Temporary disabilities
JS Fest 2019. Mauricio Palma. You can’t read this sentence - A11y automation
Persona spectrum
Permanent Temporary Situational
We usetechnologyto includemore people
A11y everywhere
You Your codeUnit testsShipCode Test
Friday night
deployment?
Color Contrast
Automation
AaAaAaAaAa
AA || AAA
O(n^2)
2500
Forward
A11y color contrast automation
github.com/palmaswell/forward
github.com/palmaswell/forward
Make it easier for users to see and hear content including
separating foreground from background.
Guideline 1.4 Distinguishable:
AA >= 4.5:1
AAA >= 7:1
AA >= 3:1
Large-scale text
AAA >= 4.5:1
Large-scale text
24px || 19px bold
Large-scale text
Logos and brand
Other exceptions
Inactive UI elements
Other exceptions
Can your read this?
Color contrast
1.6 ratio
Can your read this?
Color contrast
8.05 ratio AAA
Note 1: For the sRGB colorspace, the relative luminance of a color is defined as L =
0.2126 * R + 0.7152 * G + 0.0722 * B where R, G and B are defined as:
if RsRGB <= 0.03928 then R = RsRGB/12.92 else R = ((RsRGB+0.055)/1.055) ^ 2.4
if GsRGB <= 0.03928 then G = GsRGB/12.92 else G = ((GsRGB+0.055)/1.055) ^ 2.4
if BsRGB <= 0.03928 then B = BsRGB/12.92 else B = ((BsRGB+0.055)/1.055) ^ 2.4
WCAG definition of relative luminance
Excuse me?
Luminance
Relative
Luminance
0
1
Note 1: For the sRGB color space, the
relative luminance of a color is defined
as L = 0.2126 * R + 0.7152 * G + 0.0722
* B where R, G and B are defined as:
WCAG
definition
of relative
luminance
standardized by the
International Electrotechnical
Commission
sRGB
sRGB
Our visual
system
Works in a
similar way
Default
color space
Visual SystemWeb Browsers
Chromaticity
| Chromaticity | Red | Green | Blue | White point |
|--------------|---------|-----------|----------|--------------|
| x | 0.6400 | 0.3000 | 0.1500 | 0.3127 |
| y | 0.3300 | 0.6000 | 0.0600 | 0.3290 |
| Y | 0.2126 | 0.7152 | 0.0722 | 1.0000 |
export enum YValues {
r = 0.2126,
g = 0.7152,
b = 0.0722,
}
xyY color
space
Step 1
Y values represent the
luminance of a color entry
export function calculateRGBEntry(
entry: number,
y: Type.YValues): number {
const average = entry / 255;
return average <= 0.03928
? average / 12.92 * y
: ((average + 0.055) / 1.055 ) ** 2.4 * y;
};
Color
contrast
Step 2
Color
contrast
Step 2
export function luminance(
sRGB: Type.RGB
): number {
return calculateRGBEntry(sRGB[0], Type.YValues.r)
+ calculateRGBEntry(sRGB[1], Type.YValues.g)
+ calculateRGBEntry(sRGB[2], Type.YValues.b);
}
Color
contrast
Step 2
export function contrastRatio(
sRGB: Type.RGB,
sRGB2: Type.RGB): number {
const light = Math.max(luminance(sRGB), luminance(sRGB2));
const dark = Math.min(luminance(sRGB), luminance(sRGB2));
return +((light + 0.05) / (dark + 0.05)).toFixed(2);
}
N colors
Aa Aa Aa Aa
[ ]
A11y everywhere
Quicksort
fast sorting algorithm
SortStep 3
export function quickSort(
arr: Type.Color[],
cb: (sRGB: Type.RGB) => number,
lo: number,
hi: number
): void {
if (lo < hi) {
const pivot = cb(arr[Math.floor((lo + hi) / 2)].rgb);
const p = partition(arr, lo, hi, pivot, cb);
quickSort(arr, cb, lo, p.hi);
quickSort(arr, cb, p.lo, hi);
}
}
export function sort(
arr: Type.Color[],
cb: (sRGB: Type.RGB) => number) {
return quickSort(arr, cb, 0, arr.length - 1);
}
SortStep 3
export function quickSort(
arr: Type.Color[],
cb: (sRGB: Type.RGB) => number,
lo: number,
hi: number
): void {
if (lo < hi) {
const pivot = cb(arr[Math.floor((lo + hi) / 2)].rgb);
const p = partition(arr, lo, hi, pivot, cb);
quickSort(arr, cb, lo, p.hi);
quickSort(arr, cb, p.lo, hi);
}
}
export function sort(
arr: Type.Color[],
cb: (sRGB: Type.RGB) => number) {
return quickSort(arr, cb, 0, arr.length - 1);
}
SortStep 3
export function quickSort(
arr: Type.Color[],
cb: (sRGB: Type.RGB) => number,
lo: number,
hi: number
): void {
if (lo < hi) {
const pivot = cb(arr[Math.floor((lo + hi) / 2)].rgb);
const p = partition(arr, lo, hi, pivot, cb);
quickSort(arr, cb, lo, p.hi);
quickSort(arr, cb, p.lo, hi);
}
}
export function sort(
arr: Type.Color[],
cb: (sRGB: Type.RGB) => number) {
return quickSort(arr, cb, 0, arr.length - 1);
}
SortStep 3
export function partition(
arr: Type.Color[],
lo: number,
hi: number,
pivot: number,
cb: (sRGB: Type.RGB) => number): { lo: number, hi: number} {
if (lo <= hi) {
if (cb(arr[lo].rgb) < pivot) {
return partition(arr, lo + 1, hi, pivot, cb);
}
if (cb(arr[hi].rgb) > pivot) {
return partition(arr, lo, hi - 1, pivot, cb);
}
if (lo <= hi) {
swap(arr, lo, hi);
return partition(arr, lo + 1, hi - 1, pivot, cb);
}
}
return { lo, hi };
}
SortStep 3
export function quickSort(
arr: Type.Color[],
cb: (sRGB: Type.RGB) => number,
lo: number,
hi: number
): void {
if (lo < hi) {
const pivot = cb(arr[Math.floor((lo + hi) / 2)].rgb);
const p = partition(arr, lo, hi, pivot, cb);
quickSort(arr, cb, lo, p.hi);
quickSort(arr, cb, p.lo, hi);
}
}
export function sort(
arr: Type.Color[],
cb: (sRGB: Type.RGB) => number) {
return quickSort(arr, cb, 0, arr.length - 1);
}
AaAaAaAaAa
QuicksortStep 3
Aa Aa AaAaAa
Sorted by
luminance
Step 3
Binary Search
efficient algorithm that searches
a sorted list
Aa Aa AaAaAa
Binary
Search
Step 4 AAA color contrast check
Match!
SearchStep 4 function lowerSearch<T extends QuickSearch>(
arr: Array<T>,
el: T,
val: number,
lo: number,
hi: number): number | [] {
const mid = Math.floor((lo + hi) / 2);
const prev = mid - 1;
const next = mid + 1;
const midRatio = contrastRatio(arr[mid].rgb, el.rgb);
if (lo < hi) {
if (midRatio > val && prev >= 0) {
if (contrastRatio(arr[prev].rgb, el.rgb) < val) {
return mid;
}
return lowerSearch(arr, el, val, lo, mid);
}
if (midRatio < val && next < arr.length) {
if (contrastRatio(arr[next].rgb, el.rgb) > val) {
return next;
}
return lowerSearch(arr, el, val, mid, hi)
}
if (mid === val) {
return mid;
}
}
return [];
};
export function search(
arr: Type.Color[],
el: Type.Color,
val: Type.A11yRatio,
type?: Type.Search): number | [] {
if (type === Type.Search.upper) {
return upperSearch(arr, el, val, 0, arr.length);
}
return lowerSearch(arr, el, val, 0, arr.length);
};
SearchStep 4 function lowerSearch<T extends QuickSearch>(
arr: Array<T>,
el: T,
val: number,
lo: number,
hi: number): number | [] {
const mid = Math.floor((lo + hi) / 2);
const prev = mid - 1;
const next = mid + 1;
const midRatio = contrastRatio(arr[mid].rgb, el.rgb);
if (lo < hi) {
if (midRatio > val && prev >= 0) {
if (contrastRatio(arr[prev].rgb, el.rgb) < val) {
return mid;
}
return lowerSearch(arr, el, val, lo, mid);
}
if (midRatio < val && next < arr.length) {
if (contrastRatio(arr[next].rgb, el.rgb) > val) {
return next;
}
return lowerSearch(arr, el, val, mid, hi)
}
if (mid === val) {
return mid;
}
}
return [];
};
export function search(
arr: Type.Color[],
el: Type.Color,
val: Type.A11yRatio,
type?: Type.Search): number | [] {
if (type === Type.Search.upper) {
return upperSearch(arr, el, val, 0, arr.length);
}
return lowerSearch(arr, el, val, 0, arr.length);
};
SearchStep 4 function lowerSearch<T extends QuickSearch>(
arr: Array<T>,
el: T,
val: number,
lo: number,
hi: number): number | [] {
const mid = Math.floor((lo + hi) / 2);
const prev = mid - 1;
const next = mid + 1;
const midRatio = contrastRatio(arr[mid].rgb, el.rgb);
if (lo < hi) {
if (midRatio > val && prev >= 0) {
if (contrastRatio(arr[prev].rgb, el.rgb) < val) {
return mid;
}
return lowerSearch(arr, el, val, lo, mid);
}
if (midRatio < val && next < arr.length) {
if (contrastRatio(arr[next].rgb, el.rgb) > val) {
return next;
}
return lowerSearch(arr, el, val, mid, hi)
}
if (mid === val) {
return mid;
}
}
return [];
};
export function search(
arr: Type.Color[],
el: Type.Color,
val: Type.A11yRatio,
type?: Type.Search): number | [] {
if (type === Type.Search.upper) {
return upperSearch(arr, el, val, 0, arr.length);
}
return lowerSearch(arr, el, val, 0, arr.length);
};
Enhanced
Color
Enhanced
colors
Step 5
export function createEnhanced(
rawColor: Type.Color,
aaa: Type.Color[] | [],
aa: Type.Color[] | []
): Type.colorEnhanced {
const rgb = rawColor.rgb;
return {
name: rawColor.name,
rgb,
aaa,
aa,
toRGB(): string {
return toRGBString(rgb);
},
toHEX(): string {
return tinyColor(toRGBString(rgb)).toHexString();
},
toHSL(): string {
return tinyColor(toRGBString(rgb)).toHslString();
},
toRGBA(alpha: number): string {
const color = tinyColor(toRGBString(rgb));
color.setAlpha(alpha);
return color.toRgbString()
}
}
}
Enhanced
colors
Step 5
export function createEnhanced(
rawColor: Type.Color,
aaa: Type.Color[] | [],
aa: Type.Color[] | []
): Type.colorEnhanced {
const rgb = rawColor.rgb;
return {
name: rawColor.name,
rgb,
aaa,
aa,
toRGB(): string {
return toRGBString(rgb);
},
toHEX(): string {
return tinyColor(toRGBString(rgb)).toHexString();
},
toHSL(): string {
return tinyColor(toRGBString(rgb)).toHslString();
},
toRGBA(alpha: number): string {
const color = tinyColor(toRGBString(rgb));
color.setAlpha(alpha);
return color.toRgbString()
}
}
}
Colors
Under
Control
Demo
It’s open
github.com/palmaswell/forward
Use it, play with it, make it better!
Benefits
New opportunities
Offer utility and elegance
Profitable
Legal compliance
Before: 10% (imaginary number)
Middle: x100%
After: x1000%
A11y costs factors
Questions?
JS Fest 2019. Mauricio Palma. You can’t read this sentence - A11y automation
Thanks!Github: @palmaswell
Twitter: @palmaswell
mauricio.palma@sinnerschrader.com

More Related Content

PDF
Mauricio Palma - You can’t read this sentence - A11y automation - Codemotion ...
PDF
Mining Functional Patterns
PDF
Power of functions in a typed world
PDF
Functional and Algebraic Domain Modeling
PDF
Architectural Patterns in Building Modular Domain Models
PDF
Approximation Data Structures for Streaming Applications
PDF
Algebraic Thinking for Evolution of Pure Functional Domain Models
PDF
Category Theory for Programmers
Mauricio Palma - You can’t read this sentence - A11y automation - Codemotion ...
Mining Functional Patterns
Power of functions in a typed world
Functional and Algebraic Domain Modeling
Architectural Patterns in Building Modular Domain Models
Approximation Data Structures for Streaming Applications
Algebraic Thinking for Evolution of Pure Functional Domain Models
Category Theory for Programmers

What's hot (17)

PDF
Category Theory for Mortal Programmers
PPT
DSL - expressive syntax on top of a clean semantic model
PPTX
Overview of c (2)
PPTX
Library functions in c++
PDF
An Algebraic Approach to Functional Domain Modeling
PDF
201801 CSE240 Lecture 07
PDF
Functional and Event Driven - another approach to domain modeling
PDF
Regex cheatsheet
PPTX
Introduction to c++
PPTX
Object-Orientated Design
PDF
Learning notes of r for python programmer (Temp1)
PPT
Dependency Injection in Scala - Beyond the Cake Pattern
PPTX
Lecture 1 Introduction C++
PDF
Fp in scala with adts part 2
PDF
From functional to Reactive - patterns in domain modeling
Category Theory for Mortal Programmers
DSL - expressive syntax on top of a clean semantic model
Overview of c (2)
Library functions in c++
An Algebraic Approach to Functional Domain Modeling
201801 CSE240 Lecture 07
Functional and Event Driven - another approach to domain modeling
Regex cheatsheet
Introduction to c++
Object-Orientated Design
Learning notes of r for python programmer (Temp1)
Dependency Injection in Scala - Beyond the Cake Pattern
Lecture 1 Introduction C++
Fp in scala with adts part 2
From functional to Reactive - patterns in domain modeling
Ad

Similar to JS Fest 2019. Mauricio Palma. You can’t read this sentence - A11y automation (20)

PPT
Cgo2007 P3 3 Birkbeck
PPT
A Dimension Abstraction Approach to Vectorization in Matlab
PDF
Hive function-cheat-sheet
PPT
Grokking Monads in Scala
DOCX
CSCI 2033 Elementary Computational Linear Algebra(Spring 20.docx
PPTX
Loom & Functional Graphs in Clojure @ LambdaConf 2015
DOCX
Compilers Final spring 2013 model answer
PDF
Tao Fayan_Iso and Full_volume rendering
PPT
CV2005_3Lec02.ppt
PPTX
PDF
Model answer of compilers june spring 2013
PDF
Rcpp11 genentech
PDF
[系列活動] Data exploration with modern R
PDF
Apache Spark & Streaming
DOC
Computer hw1
PDF
Sorbet at Grailed
PPTX
C programming
PDF
What's new in Apache SystemML - Declarative Machine Learning
PDF
Extensible Operators and Literals for JavaScript
PDF
Python lecture 05
Cgo2007 P3 3 Birkbeck
A Dimension Abstraction Approach to Vectorization in Matlab
Hive function-cheat-sheet
Grokking Monads in Scala
CSCI 2033 Elementary Computational Linear Algebra(Spring 20.docx
Loom & Functional Graphs in Clojure @ LambdaConf 2015
Compilers Final spring 2013 model answer
Tao Fayan_Iso and Full_volume rendering
CV2005_3Lec02.ppt
Model answer of compilers june spring 2013
Rcpp11 genentech
[系列活動] Data exploration with modern R
Apache Spark & Streaming
Computer hw1
Sorbet at Grailed
C programming
What's new in Apache SystemML - Declarative Machine Learning
Extensible Operators and Literals for JavaScript
Python lecture 05
Ad

More from JSFestUA (20)

PDF
JS Fest 2019/Autumn. Роман Савіцький. Webcomponents & lit-element in production
PDF
JS Fest 2019/Autumn. Erick Wendel. 10 secrets to improve Javascript Performance
PDF
JS Fest 2019/Autumn. Alexandre Gomes. Embrace the "react fatigue"
PDF
JS Fest 2019/Autumn. Anton Cherednikov. Choreographic or orchestral architect...
PDF
JS Fest 2019/Autumn. Adam Leos. So why do you need to know Algorithms and Dat...
PDF
JS Fest 2019/Autumn. Marko Letic. Saving the world with JavaScript: A Data Vi...
PPTX
JS Fest 2019/Autumn. Александр Товмач. JAMstack
PPTX
JS Fest 2019/Autumn. Влад Федосов. Technology agnostic microservices at SPA f...
PPTX
JS Fest 2019/Autumn. Дмитрий Жарков. Blockchainize your SPA or Integrate Java...
PPTX
JS Fest 2019/Autumn. Maciej Treder. Angular Schematics - Develop for developers
PPTX
JS Fest 2019/Autumn. Kyle Boss. A Tinder Love Story: Create a Wordpress Blog ...
PPTX
JS Fest 2019/Autumn. Андрей Старовойт. Зачем нужен тип "true" в TypeScript?
PPTX
JS Fest 2019/Autumn. Eyal Eizenberg. Tipping the Scale
PDF
JS Fest 2019/Autumn. Sota Ohara. Сreate own server less CMS from scratch
PPTX
JS Fest 2019/Autumn. Джордж Евтушенко. Как стать программистом, которого хотят
PDF
JS Fest 2019/Autumn. Алексей Орленко. Node.js N-API for Rust
PDF
JS Fest 2019/Autumn. Daniel Ostrovsky. Falling in love with decorators ES6/Ty...
PPTX
JS Fest 2019/Autumn. Андрей Андрийко. Гексагональна архітектура в Nodejs проекті
PPTX
JS Fest 2019/Autumn. Борис Могила. Svelte. Почему нам не нужно run-time ядро
PPTX
JS Fest 2019/Autumn. Виталий Кухар. Сравнение кластеризации HTTP, TCP и UDP н...
JS Fest 2019/Autumn. Роман Савіцький. Webcomponents & lit-element in production
JS Fest 2019/Autumn. Erick Wendel. 10 secrets to improve Javascript Performance
JS Fest 2019/Autumn. Alexandre Gomes. Embrace the "react fatigue"
JS Fest 2019/Autumn. Anton Cherednikov. Choreographic or orchestral architect...
JS Fest 2019/Autumn. Adam Leos. So why do you need to know Algorithms and Dat...
JS Fest 2019/Autumn. Marko Letic. Saving the world with JavaScript: A Data Vi...
JS Fest 2019/Autumn. Александр Товмач. JAMstack
JS Fest 2019/Autumn. Влад Федосов. Technology agnostic microservices at SPA f...
JS Fest 2019/Autumn. Дмитрий Жарков. Blockchainize your SPA or Integrate Java...
JS Fest 2019/Autumn. Maciej Treder. Angular Schematics - Develop for developers
JS Fest 2019/Autumn. Kyle Boss. A Tinder Love Story: Create a Wordpress Blog ...
JS Fest 2019/Autumn. Андрей Старовойт. Зачем нужен тип "true" в TypeScript?
JS Fest 2019/Autumn. Eyal Eizenberg. Tipping the Scale
JS Fest 2019/Autumn. Sota Ohara. Сreate own server less CMS from scratch
JS Fest 2019/Autumn. Джордж Евтушенко. Как стать программистом, которого хотят
JS Fest 2019/Autumn. Алексей Орленко. Node.js N-API for Rust
JS Fest 2019/Autumn. Daniel Ostrovsky. Falling in love with decorators ES6/Ty...
JS Fest 2019/Autumn. Андрей Андрийко. Гексагональна архітектура в Nodejs проекті
JS Fest 2019/Autumn. Борис Могила. Svelte. Почему нам не нужно run-time ядро
JS Fest 2019/Autumn. Виталий Кухар. Сравнение кластеризации HTTP, TCP и UDP н...

Recently uploaded (20)

PDF
Practical Manual AGRO-233 Principles and Practices of Natural Farming
PDF
احياء السادس العلمي - الفصل الثالث (التكاثر) منهج متميزين/كلية بغداد/موهوبين
PDF
Trump Administration's workforce development strategy
PPTX
Chinmaya Tiranga Azadi Quiz (Class 7-8 )
PPTX
Unit 4 Computer Architecture Multicore Processor.pptx
PPTX
Introduction to pro and eukaryotes and differences.pptx
PPTX
CHAPTER IV. MAN AND BIOSPHERE AND ITS TOTALITY.pptx
PDF
AI-driven educational solutions for real-life interventions in the Philippine...
DOCX
Cambridge-Practice-Tests-for-IELTS-12.docx
PDF
CISA (Certified Information Systems Auditor) Domain-Wise Summary.pdf
PDF
Chinmaya Tiranga quiz Grand Finale.pdf
PDF
1.3 FINAL REVISED K-10 PE and Health CG 2023 Grades 4-10 (1).pdf
PDF
IGGE1 Understanding the Self1234567891011
PPTX
Share_Module_2_Power_conflict_and_negotiation.pptx
PDF
Τίμαιος είναι φιλοσοφικός διάλογος του Πλάτωνα
PPTX
Onco Emergencies - Spinal cord compression Superior vena cava syndrome Febr...
PPTX
A powerpoint presentation on the Revised K-10 Science Shaping Paper
PDF
LDMMIA Reiki Yoga Finals Review Spring Summer
PDF
Weekly quiz Compilation Jan -July 25.pdf
PDF
BP 704 T. NOVEL DRUG DELIVERY SYSTEMS (UNIT 2).pdf
Practical Manual AGRO-233 Principles and Practices of Natural Farming
احياء السادس العلمي - الفصل الثالث (التكاثر) منهج متميزين/كلية بغداد/موهوبين
Trump Administration's workforce development strategy
Chinmaya Tiranga Azadi Quiz (Class 7-8 )
Unit 4 Computer Architecture Multicore Processor.pptx
Introduction to pro and eukaryotes and differences.pptx
CHAPTER IV. MAN AND BIOSPHERE AND ITS TOTALITY.pptx
AI-driven educational solutions for real-life interventions in the Philippine...
Cambridge-Practice-Tests-for-IELTS-12.docx
CISA (Certified Information Systems Auditor) Domain-Wise Summary.pdf
Chinmaya Tiranga quiz Grand Finale.pdf
1.3 FINAL REVISED K-10 PE and Health CG 2023 Grades 4-10 (1).pdf
IGGE1 Understanding the Self1234567891011
Share_Module_2_Power_conflict_and_negotiation.pptx
Τίμαιος είναι φιλοσοφικός διάλογος του Πλάτωνα
Onco Emergencies - Spinal cord compression Superior vena cava syndrome Febr...
A powerpoint presentation on the Revised K-10 Science Shaping Paper
LDMMIA Reiki Yoga Finals Review Spring Summer
Weekly quiz Compilation Jan -July 25.pdf
BP 704 T. NOVEL DRUG DELIVERY SYSTEMS (UNIT 2).pdf

JS Fest 2019. Mauricio Palma. You can’t read this sentence - A11y automation

  • 10. She had a long history…
  • 13. To
  • 18. Today
  • 19. Mauricio Palma Co-founder and all kind of things @WDLK Product Engineer @sinnerschrader everywhere else @palmaswell
  • 20. But
  • 21. Why?
  • 26. We use our our abilities
  • 28. You can’t read this sentence A11y automation April, 2019
  • 37. Key Takeaways Publish all information and content from your site in your HTML Use semantic HTML and the appropriate ARIA landmarks Write screen reader friendly markup Provide keyboard navigation
  • 40. Key Takeaways Besides the mentioned semantic HTML and screen reader friendly markup You should follow a linear logical layout, that supports at least 200% magnification
  • 43. Key Takeaways Always put form elements in context. Meaning putting buttons, inputs, and notifications together in a logical manner For action elements in your interface use a good combination of colors, shapes, and text Do not rely on colors to convey meaning
  • 46. Key Takeaways Align your text to the left and keep a consistent layout Keep content short, clear and simple Consider producing materials in other formats (for example audio or video) Let the users change the contrast between background and text
  • 50. Key Takeaways Make sure that colors are not your only method of conveying important information.
  • 56. You Your codeUnit testsShipCode Test
  • 61. 2500
  • 62. Forward A11y color contrast automation github.com/palmaswell/forward
  • 64. Make it easier for users to see and hear content including separating foreground from background. Guideline 1.4 Distinguishable:
  • 69. 24px || 19px bold Large-scale text
  • 70. Logos and brand Other exceptions
  • 72. Can your read this? Color contrast 1.6 ratio
  • 73. Can your read this? Color contrast 8.05 ratio AAA
  • 74. Note 1: For the sRGB colorspace, the relative luminance of a color is defined as L = 0.2126 * R + 0.7152 * G + 0.0722 * B where R, G and B are defined as: if RsRGB <= 0.03928 then R = RsRGB/12.92 else R = ((RsRGB+0.055)/1.055) ^ 2.4 if GsRGB <= 0.03928 then G = GsRGB/12.92 else G = ((GsRGB+0.055)/1.055) ^ 2.4 if BsRGB <= 0.03928 then B = BsRGB/12.92 else B = ((BsRGB+0.055)/1.055) ^ 2.4 WCAG definition of relative luminance
  • 78. 0
  • 79. 1
  • 80. Note 1: For the sRGB color space, the relative luminance of a color is defined as L = 0.2126 * R + 0.7152 * G + 0.0722 * B where R, G and B are defined as: WCAG definition of relative luminance
  • 81. standardized by the International Electrotechnical Commission sRGB
  • 82. sRGB
  • 84. Works in a similar way Default color space Visual SystemWeb Browsers
  • 85. Chromaticity | Chromaticity | Red | Green | Blue | White point | |--------------|---------|-----------|----------|--------------| | x | 0.6400 | 0.3000 | 0.1500 | 0.3127 | | y | 0.3300 | 0.6000 | 0.0600 | 0.3290 | | Y | 0.2126 | 0.7152 | 0.0722 | 1.0000 |
  • 86. export enum YValues { r = 0.2126, g = 0.7152, b = 0.0722, } xyY color space Step 1 Y values represent the luminance of a color entry
  • 87. export function calculateRGBEntry( entry: number, y: Type.YValues): number { const average = entry / 255; return average <= 0.03928 ? average / 12.92 * y : ((average + 0.055) / 1.055 ) ** 2.4 * y; }; Color contrast Step 2
  • 88. Color contrast Step 2 export function luminance( sRGB: Type.RGB ): number { return calculateRGBEntry(sRGB[0], Type.YValues.r) + calculateRGBEntry(sRGB[1], Type.YValues.g) + calculateRGBEntry(sRGB[2], Type.YValues.b); }
  • 89. Color contrast Step 2 export function contrastRatio( sRGB: Type.RGB, sRGB2: Type.RGB): number { const light = Math.max(luminance(sRGB), luminance(sRGB2)); const dark = Math.min(luminance(sRGB), luminance(sRGB2)); return +((light + 0.05) / (dark + 0.05)).toFixed(2); }
  • 90. N colors Aa Aa Aa Aa [ ]
  • 93. SortStep 3 export function quickSort( arr: Type.Color[], cb: (sRGB: Type.RGB) => number, lo: number, hi: number ): void { if (lo < hi) { const pivot = cb(arr[Math.floor((lo + hi) / 2)].rgb); const p = partition(arr, lo, hi, pivot, cb); quickSort(arr, cb, lo, p.hi); quickSort(arr, cb, p.lo, hi); } } export function sort( arr: Type.Color[], cb: (sRGB: Type.RGB) => number) { return quickSort(arr, cb, 0, arr.length - 1); }
  • 94. SortStep 3 export function quickSort( arr: Type.Color[], cb: (sRGB: Type.RGB) => number, lo: number, hi: number ): void { if (lo < hi) { const pivot = cb(arr[Math.floor((lo + hi) / 2)].rgb); const p = partition(arr, lo, hi, pivot, cb); quickSort(arr, cb, lo, p.hi); quickSort(arr, cb, p.lo, hi); } } export function sort( arr: Type.Color[], cb: (sRGB: Type.RGB) => number) { return quickSort(arr, cb, 0, arr.length - 1); }
  • 95. SortStep 3 export function quickSort( arr: Type.Color[], cb: (sRGB: Type.RGB) => number, lo: number, hi: number ): void { if (lo < hi) { const pivot = cb(arr[Math.floor((lo + hi) / 2)].rgb); const p = partition(arr, lo, hi, pivot, cb); quickSort(arr, cb, lo, p.hi); quickSort(arr, cb, p.lo, hi); } } export function sort( arr: Type.Color[], cb: (sRGB: Type.RGB) => number) { return quickSort(arr, cb, 0, arr.length - 1); }
  • 96. SortStep 3 export function partition( arr: Type.Color[], lo: number, hi: number, pivot: number, cb: (sRGB: Type.RGB) => number): { lo: number, hi: number} { if (lo <= hi) { if (cb(arr[lo].rgb) < pivot) { return partition(arr, lo + 1, hi, pivot, cb); } if (cb(arr[hi].rgb) > pivot) { return partition(arr, lo, hi - 1, pivot, cb); } if (lo <= hi) { swap(arr, lo, hi); return partition(arr, lo + 1, hi - 1, pivot, cb); } } return { lo, hi }; }
  • 97. SortStep 3 export function quickSort( arr: Type.Color[], cb: (sRGB: Type.RGB) => number, lo: number, hi: number ): void { if (lo < hi) { const pivot = cb(arr[Math.floor((lo + hi) / 2)].rgb); const p = partition(arr, lo, hi, pivot, cb); quickSort(arr, cb, lo, p.hi); quickSort(arr, cb, p.lo, hi); } } export function sort( arr: Type.Color[], cb: (sRGB: Type.RGB) => number) { return quickSort(arr, cb, 0, arr.length - 1); }
  • 99. Aa Aa AaAaAa Sorted by luminance Step 3
  • 100. Binary Search efficient algorithm that searches a sorted list
  • 101. Aa Aa AaAaAa Binary Search Step 4 AAA color contrast check Match!
  • 102. SearchStep 4 function lowerSearch<T extends QuickSearch>( arr: Array<T>, el: T, val: number, lo: number, hi: number): number | [] { const mid = Math.floor((lo + hi) / 2); const prev = mid - 1; const next = mid + 1; const midRatio = contrastRatio(arr[mid].rgb, el.rgb); if (lo < hi) { if (midRatio > val && prev >= 0) { if (contrastRatio(arr[prev].rgb, el.rgb) < val) { return mid; } return lowerSearch(arr, el, val, lo, mid); } if (midRatio < val && next < arr.length) { if (contrastRatio(arr[next].rgb, el.rgb) > val) { return next; } return lowerSearch(arr, el, val, mid, hi) } if (mid === val) { return mid; } } return []; }; export function search( arr: Type.Color[], el: Type.Color, val: Type.A11yRatio, type?: Type.Search): number | [] { if (type === Type.Search.upper) { return upperSearch(arr, el, val, 0, arr.length); } return lowerSearch(arr, el, val, 0, arr.length); };
  • 103. SearchStep 4 function lowerSearch<T extends QuickSearch>( arr: Array<T>, el: T, val: number, lo: number, hi: number): number | [] { const mid = Math.floor((lo + hi) / 2); const prev = mid - 1; const next = mid + 1; const midRatio = contrastRatio(arr[mid].rgb, el.rgb); if (lo < hi) { if (midRatio > val && prev >= 0) { if (contrastRatio(arr[prev].rgb, el.rgb) < val) { return mid; } return lowerSearch(arr, el, val, lo, mid); } if (midRatio < val && next < arr.length) { if (contrastRatio(arr[next].rgb, el.rgb) > val) { return next; } return lowerSearch(arr, el, val, mid, hi) } if (mid === val) { return mid; } } return []; }; export function search( arr: Type.Color[], el: Type.Color, val: Type.A11yRatio, type?: Type.Search): number | [] { if (type === Type.Search.upper) { return upperSearch(arr, el, val, 0, arr.length); } return lowerSearch(arr, el, val, 0, arr.length); };
  • 104. SearchStep 4 function lowerSearch<T extends QuickSearch>( arr: Array<T>, el: T, val: number, lo: number, hi: number): number | [] { const mid = Math.floor((lo + hi) / 2); const prev = mid - 1; const next = mid + 1; const midRatio = contrastRatio(arr[mid].rgb, el.rgb); if (lo < hi) { if (midRatio > val && prev >= 0) { if (contrastRatio(arr[prev].rgb, el.rgb) < val) { return mid; } return lowerSearch(arr, el, val, lo, mid); } if (midRatio < val && next < arr.length) { if (contrastRatio(arr[next].rgb, el.rgb) > val) { return next; } return lowerSearch(arr, el, val, mid, hi) } if (mid === val) { return mid; } } return []; }; export function search( arr: Type.Color[], el: Type.Color, val: Type.A11yRatio, type?: Type.Search): number | [] { if (type === Type.Search.upper) { return upperSearch(arr, el, val, 0, arr.length); } return lowerSearch(arr, el, val, 0, arr.length); };
  • 106. Enhanced colors Step 5 export function createEnhanced( rawColor: Type.Color, aaa: Type.Color[] | [], aa: Type.Color[] | [] ): Type.colorEnhanced { const rgb = rawColor.rgb; return { name: rawColor.name, rgb, aaa, aa, toRGB(): string { return toRGBString(rgb); }, toHEX(): string { return tinyColor(toRGBString(rgb)).toHexString(); }, toHSL(): string { return tinyColor(toRGBString(rgb)).toHslString(); }, toRGBA(alpha: number): string { const color = tinyColor(toRGBString(rgb)); color.setAlpha(alpha); return color.toRgbString() } } }
  • 107. Enhanced colors Step 5 export function createEnhanced( rawColor: Type.Color, aaa: Type.Color[] | [], aa: Type.Color[] | [] ): Type.colorEnhanced { const rgb = rawColor.rgb; return { name: rawColor.name, rgb, aaa, aa, toRGB(): string { return toRGBString(rgb); }, toHEX(): string { return tinyColor(toRGBString(rgb)).toHexString(); }, toHSL(): string { return tinyColor(toRGBString(rgb)).toHslString(); }, toRGBA(alpha: number): string { const color = tinyColor(toRGBString(rgb)); color.setAlpha(alpha); return color.toRgbString() } } }
  • 109. Demo
  • 110. It’s open github.com/palmaswell/forward Use it, play with it, make it better!
  • 111. Benefits New opportunities Offer utility and elegance Profitable Legal compliance
  • 112. Before: 10% (imaginary number) Middle: x100% After: x1000% A11y costs factors