高对比度,一个 PostCSS 插件的故事*

Avatar of Eduard Pochtar
Eduard Pochtar

DigitalOcean 为您的旅程的每个阶段提供云产品。 立即开始使用 $200 免费信用额度!

*基于真实事件

如今很难想象没有互联网的生活。 许多人的生活或多或少与互联网息息相关。 想想我们依赖它的所有事情:沟通、教育、购物、业务控制、家庭管理、娱乐等等。 它就像另一个世界中的一个世界,拥有自己的规则和多样性。

欧盟约有 8000 万残疾人,而且这个数字还在不断增加。 不幸的是,他们中的许多人无法利用互联网提供的所有机会,因为他们中的许多人并不关心无障碍。

我们能做些什么呢?

这是一个好问题。 我们生活在一个技术可以帮助我们照顾需要特殊照顾的人的时代。 越来越多的组织、公司甚至政府都在参与帮助残疾人。

网络无障碍法

不久前,欧盟通过了一项关于网络无障碍的法律。 这项法律涵盖公共部门网站和移动应用程序,例如行政部门、警察部门、公立医院、大学和图书馆。 它将要求它们对所有公民无障碍,特别是对盲人、听力障碍者、聋人以及视力障碍者和功能性残疾人。

欧盟网络无障碍指令中接受的新规则是

  • 欧盟成员国政府拥有的所有网站或网络应用程序必须对残疾人完全无障碍。 新网站必须无障碍,并且必须更新现有内容。
  • 档案内容和文件将根据要求以无障碍形式提供。
  • 政府视频必须提供闭幕字幕。 直播视频自首次播出之日起 14 天内提供字幕。
  • 在线服务,例如支付罚款或费用,必须无障碍。
  • 欧盟政府网站必须说明其网站的哪些部分(以及原因)无法访问。
  • 欧盟成员国必须定期监测并向公众和欧盟委员会报告其网络服务的无障碍状况。

在一份新闻稿中,数字经济和社会委员 Günther H. Oettinger 表示

数百万欧洲公民被数字社会抛在后面,这是不可接受的。 我们刚刚达成的协议将确保每个人都有平等的机会享受互联网和移动应用程序带来的益处,更充分地参与社会并过上更加独立的生活。

数字单一市场副主席安德鲁斯·安西普呼应了这种情绪,他说

互联网接入应该成为所有人的现实。 将数百万欧洲人抛在后面是不可取的。 今晚的协议是迈向数字单一市场的重要一步,这将消除障碍,使所有欧洲人都能从数字世界中获得最大收益。

我认为理解互联网是每个人平等的地方非常重要。 我认为如今,互联网实际上应该以某种形式,尽可能多地为用户提供访问。

我想分享我们关于如何开发一个工具来帮助开发网站的高对比度版本的故事。

对比度很重要

对比度可以轻松区分不同的事物。 在网页设计中,对比度通常指的是文本前景和背景之间的差异。 换句话说,屏幕上的文字与它们所处的背景有多大区别。

文本对比度是一个重要的无障碍标准。 当人们使用网站或应用程序时,他们不是阅读,而是浏览。 当大多数人快速浏览或阅读时,他们依赖于单词和字符的形状,而不是更明确的意识策略,例如分析每个字母及其出现的顺序。 您现在可能正在这样做,通过使用对比度良好的文本,使这些形状易于立即识别。

高对比度

在一些国家,政府要求公共网站提供带有反色颜色的特殊高对比度版本。 您可能通过这种图标知道它们

这种高对比度设置有利于视力障碍或其他视觉障碍的用户。

挑战

不久前,我们的团队遇到了需要高对比度版本的项目。 对我们所有人来说,这是一个巨大的挑战。

首先,我们在互联网上搜索了关于什么是高对比度以及它应该如何工作的信息。 不幸的是,我们没有找到足够的信息。 一切都非常抽象和糟糕。 但是我们发现了一些有用的信息。 背景应该很暗(黑色),文字 - 与背景相反的颜色(白色),链接 - 黄色或绿色。

一些网站甚至可以反转图像,有些网站甚至可以完全从高对比度版本中删除图像。

CSS 预处理器

构建网站高对比度版本的一种方法是使用预处理器,例如 Less、Sass 或 Stylus。 预处理器还提供了许多方法来编译网站的两个版本。 例如,它可以是变量

$high-contrast: true;
$background-color: #fff;
$background-high-contrast-color: #000;
$text-color: #000;
$text-high-contrast-color: #fff;

body {
  …
  @if $high-contrast == true {
    background-color: $background-high-contrast-color;
  } else {
    background-color: $background-color;
  }
  …
}
…
.text {
  @if $high-contrast == true {
    color: $text-color;
  } else {
    color: $text-high-contrast-color;
  }
}

这可能会使我们的 CSS 变得有点复杂且难以维护。 以下还有另一种方法,@mixins

$high-contrast: true;
$background-color: #fff;
$background-high-contrast-color: #000;
$text-color: #000;
$text-high-contrast-color: #fff;

@mixin background-color {
  @if $high-contrast == true {
    background-color: $background-high-contrast-color;
  } @else {
    background-color: $background-color;
  }
}

@mixin text-color {
  @if $high-contrast == true {
    color: $text-high-contrast-color;
  } @else {
    color: $text-color;
  }
}

body {
  …
  @include background-color;
  …
}
…
.text {
  @include text-color;
}

这种方法稍微好一些,但仍然存在缺点。 还有很多其他方法可以开发高对比度版本。 每种方法都有其优点和缺点。

但是,如果您不使用预处理器怎么办? 或者如果您的项目已经在开发中,并且变量或 mixins 没有被正确使用或根本不存在呢?

我们遇到了这个问题。 团队的一部分正在研究高对比度以及将其整合到开发过程中的方法,而团队的另一部分已经在开发项目。 此外,不幸的是,他们根本没有使用预处理器。

一个插件的想法!

对我们来说幸运的是,我们已经了解了 PostCSS 及其所有可能性。 PostCSS 对我们来说最棒的一点是,我们可以随意修改或替换我们需要修改或替换的那些属性或值,其他一切都可以保持不变。 这不是很棒吗? 这就是我们决定创建 PostCSS 高对比度插件的原因。

开发 PostCSS 插件

起初,这似乎对我们来说是另一个挑战。 没有人知道如何编写 PostCSS 插件。 我们惊讶于它有多么容易。 PostCSS 有很棒的文档和社区,这对我们这些新手来说非常有帮助。

浏览了 PostCSS 文档一个小时后,我们就可以开始我们的插件了。 PostCSS 拥有非常棒的 API。 看看这几行 js

css.walkRules( function (rule) {
  if (rule.selector === 'body') {
    // do something…
  }
});

它们不言自明!

但是,我们仍然面临着一系列其他问题

  • 要更改哪些颜色,哪些颜色保持不变?
  • 如果颜色从父元素继承会怎么样?
  • 如果颜色已经是高对比度会怎么样?
  • 如果它是一个复杂元素,不容易修改,更改其颜色或背景颜色怎么办?

我们有很多问题。 我们不知道如何继续前进。

首先,我们必须决定要更改哪些颜色,哪些颜色保持不变。 我们试图通过检查颜色的亮度和饱和度来确定每种颜色是否具有足够的对比度

 var declColor = color(decl.value).hsl();    
if (declColor.s > 50 && declColor.l > 50){
  decl.value = '#000';
}

但是经过对这种方法的一些测试后,我们决定它不适合我们。 它非常复杂,有时它不像我们预期的那样工作,并且编译我们的 CSS 需要更多时间。 我们意识到最好的方法是直接替换所有颜色,无论是什么

if (decl.prop === 'background-color') {
  decl.value = #000;
}

if (decl.prop === 'color') {
  decl.value = #fff;
}

这似乎效果很好。 庆祝我们又一次的小胜利后,我们注意到并非所有元素都受到影响。 对问题的调查表明,并非所有元素都具有颜色属性。 CSS 继承! 为了解决这个问题,我们决定创建“激进模式”。

“激进模式”接受一个选择器列表,无论如何这些选择器都将获得颜色属性。

postcss([
  require('postcss-high-contrast')({
    aggressiveHC: true,
    aggressiveHCDefaultSelectorList: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p', 'li', 'th', 'td'],
    aggressiveHCCustomSelectorList: ['div', 'span'],
  })
])

经过了更多不同的测试后,我们的插件似乎已经完成了。

它是怎么工作的?

在我们结束这个故事之前,我想描述一下如何使用 PostCSS 高对比度插件。我希望你已经熟悉 PostCSS 及其生态系统。如果不是,请查看 PostCSS 网站。无论你的预处理器偏好是什么,你都可以额外使用 PostCSS。这意味着 PostCSS 高对比度插件将适用于任何 CSS。

这里是一个配置示例

postcss([
  require('postcss-high-contrast')({
    aggressiveHC: true,
    aggressiveHCDefaultSelectorList: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p', 'li', 'th', 'td'],
    aggressiveHCCustomSelectorList: ['div', 'span'],

    backgroundColor: '#000',
    altBgColor: '#fff',

    textColor: '#fff',

    linkColor: '#fcff3c',
    linkHoverColor: '#fcff3c',

    borderColor: '#fff',
    disableShadow: true,

    imageFilter: 'invert(100%)',
    imageSelectors: ['img'],

    removeCSSProps: false,
    CSSPropsWhiteList: ['background', 'background-color', 'color', 'border', 'border-top', 'border-bottom',
      'border-left', 'border-right', 'border-color', 'border-top-color', 'border-right-color',
      'border-bottom-color', 'border-left-color', 'box-shadow', 'filter', 'text-shadow']
  })
])

普通模式示例

/* Before */
body {
  background: #fff;
  color: #000;
}

a {
  color: #0b39e1;
}

/* After */
body {
  background: #000;
  color: #fff;
}

a {
  color: #fcff3c;
}

激进模式示例

/* Before */
h1 {
  font-size: 48px;
  margin: 0;
  padding: 0 24px;
  width: 100%;
}

p {
  font-size: 48px;
  margin: 0 0 24px;
}

/* After */
h1 {
  color: #fff;
  font-size: 48px;
  margin: 0;
  padding: 0 24px;
  width: 100%;
}

p {
  color: #fff;
  font-size: 48px;
  margin: 0 0 24px;
}

结束

开发 PostCSS 高对比度插件 对我们来说是一次很棒的体验。我要感谢 PostCSS 团队提供如此棒的工具、文档和 API。我们从未想过会如此简单。

我们生活在一个美好的时代。我们拥有如此多的技术帮助我们每天,互联网是最重要的技术之一。所以让我们努力让它更易于所有人访问。