HTML可访问性fieldset,legend元素及CSS布局应用

这篇文章发布于 2016年11月12日,星期六,00:01,归类于 HTML相关。 阅读 41856 次, 今日 7 次 8 条评论

 

一、双十一了

现在是2016年11月11日0点11分,大家都在忙着shopping,而对于我而言,正是工作效率最高的时间段,文章写起来~

光棍节时间

二、HTML fieldset,legend元素与可访问性

注:本文可访问性部分的部分内容参考自这篇外文

我们无论做什么产品,都不能只关注眼前那点东西,或者说肉眼所见的表层那点东西。尤其对于有相当用户基数的产品,无障碍访问和无障碍阅读一定要引起重视,否则,对产品的口碑会有严重的影响。

下面这张图是我之前在刷微博的时候看到的,是批评跟滴滴合并之后的uber中国在在无障碍访问这一块做得很糟糕:

Uber中国糟糕的无障碍访问反馈

看来评价者是相当的生气,好奇的我又去看了下滴滴出行APP的反馈,结果不看不知道一看吓一跳,对无障碍访问这一块的差评出乎意料的多,几乎全部都是1星,这口碑和评分妥妥地下去了,看来无障碍访问这一块做的确实很糟糕啊!

糟糕的无障碍访问反馈 滴滴出行

其实,如果你只要有一些基本的常识,按照文档规范本身语义去实现,并不要求你有多精通,基本的无障碍使用绝对是没有问题的。但是,像上面这样,被批得一无是处的,可见真的是一无是处。

我们做web开发的,也同样需要对无障碍阅读,可访问性等引起重视。

我们平常可能都听过“语义化”这个词,为什么HTML代码要语义化,除了代码可读性好以外,SEO有帮助外,最主要的还是对一些屏幕阅读设备或者其他辅助阅读设备友好,可以让用户在条件受限的条件下依然可以正常使用我们的产品,比方说鼠标坏了,又或者说视力有障碍的用户等等。

我们这里介绍两个HTML元素,fieldsetlegend,可能有部分小伙伴没见过,说不定会认为是哪个新出的HTML标签,不是的哈,这两个标签在我在津津乐道看《樱桃小丸子》的时候就有了,主要用来form表单中,给表单控件们分组用的。

我们先看一个例子,一个带有多个选择项的问题:

问题和多个选择的问题

如果让小伙伴们来实现,基本上HTML都是下面这种套路:

<form>
<p>你有港澳通行证吗?</p>

<input type="radio" id="yes">
<label for="yes">有</label>

<input type="radio" id="no">
<label for="no">没有</label>

...
</form>

对于我们以视觉为主要感官的人来讲,上面的最终的视觉呈现是没有问题的,有问题,有单选。但是,由于我们的问题和下面的2个单选他们是有关联的,或者说带有“组”的关系。如果我们使用上述的HTML代码,就会带来一个什么问题呢?屏幕阅读设备就无法知道他们之间的关系,我们听到的仅仅是单选控件的label元素中的“有”和“没有”这两个词,然后问题是什么可能永远都听不到。

对于普通元素,我们如果想让其有特定的可访问特性,可以使用WAI-ARIA中的API,关于ARIA我多年前话很多精力整理过,可参见“WAI-ARIA无障碍网页应用属性完全展示”,例如,你想使用div标签模拟按钮,可能需要加个role="button"

虽然说ARIA是一种解决方法,但是,对于开发人员而言,学习成本啊什么的还是很麻烦的,对于盲人用户而言,要根据ARIA关键属性的引导来引导去,其实效率不太高,于是,还是喜欢使用tab键快速索引,这就导致上面的“你有港澳通行证吗?”被忽视掉,也无法和下面的“有”和“没有”联系上。

我自己使用VoiceOver测试了下,确实,标题内容是很难读取的,也可能是我用得不熟的原因,我发现要框选这段标题文字才会读音,但是,如果用户知道哪里可以框选,怕是也就不需要阅读设备了。

实际上,要修复上面的可访问性问题很简单,我们使用form表单中具有语义的fieldsetlegend元素就可以了,如下:

<form>
<fieldset>
<legend>你有港澳通行证吗?</legend>

<input type="radio" id="yes">
<label for="yes">有</label>

<input type="radio" id="no">
<label for="no">没有</label>
</fieldset>

...
</form>

其中,fieldset表示组的意思,专门用在form表单元素中,表示一组内容,例如,我们填写收货地址的时候,省市区会有多个输入框后者下拉框,就可以使用fieldset归为一组,legend表示这个组的标题,在我们这里例子中,正好就是问题内容。

此时,你再使用tab键导航form表单的时候,就会清晰读出问题“你有港澳通行证吗?”了,这样,用户就能清楚知道,下面的“有”和“没有”到底说的是什么鬼,就不会有困扰了。

注意:IE浏览器中,Jaws屏幕阅读器会读fieldset中每一个操作框的legend(而不是仅第一个),这其实是有问题的。(原文内容,未测试)

我使用VoiceOver测试了下使用fieldsetlegend元素的表单,确实,读的内容是“组 你有港澳通行证吗? 2个选项”,这样显然更好理解。

当然,并不是说只要有表单就一定要使用fieldsetlegend,那什么时候该使用,什么时候不该使用呢?

什么时候该使用fieldsetlegend

  • 使用单选框或多选框的提问内容;
  • 几个输入框使用的是同一个主题,例如,省市区3个下拉和最后详细地址输入框都是“地址”这个主题,此时,legend元素里面就可以是“收获地址”这样的文字,整个所有表单都套上fieldset,例如:
    <form>
    <fieldset>
    <legend>双十一收货地址</legend>
    <label for="province">省:</label><select id="province"><option>上海市</option></select>
    
    <label for="city">省:</label><select id="city"><option>上海市</option></select>
    
    <label for="district">区:</label><select id="district"><option>浦东新区</option></select>
    
    <label for="address">详细地址</label>
    <input type="text" id="address">
    </fieldset>
    
    ...
    </form>

什么时候不建议使用fieldsetlegend

  • 单打独斗的表单控件元素们。

三、fieldset,legend元素在CSS布局中的应用

很多HTML标签抛开语义,就本身就一无是处了,比方说<p>标签,本身没有任何特异性,也没有私藏的绝活。但是,<legend>却不一样,其天生带有一种特殊的布局,在某些场合可以轻松实现一些效果。

我们先看下这种HTML原生的样式是怎样的:
如下HTML:

<fieldset>
    <legend>标题</legend>
</fieldset>

效果如下(实时):

标题

会看到,有一个方框框,但是这个框不是完全闭合的,有个开口,这个开口上面的就是<legend>里面的文字。注意,这里有2个非常重要的点,第1个就是开口,也就是线并没有从文字下面穿过去,这个文字的背景看上去是白色的,实际上,咳咳,是透明的,再说一遍是透明的。类似这种效果,如果你想使用其他标签和CSS模拟,一般想到的就是用个背景色覆盖,使用背景色的问题在于,如果换了个背景,这个覆盖就穿帮了。而透明没有这种担忧,各种背景各个模块都可以自如地飞起来;第2个就是文字是压在线上的,传统的标签我们写个border属性,里面的文字肯定是在border里面的,但是,<legend>偏不,直接压在线上,天然的,你还别说,如果用CSS来模拟这种效果,还真要下点成本的。

基本上,各个浏览器下都是这种框框开口标题文字的效果,我大致看了下,Firefox浏览器的最有质感(设一个深色背景,如下截图),IE就是个浅边框,在白色背景下效果不错,而Chrome浏览器的边框类型是groove(沟槽)。

Firefox legend元素灰色背景上的效果

总而言之,各个浏览器各个系统下差异都不同,但是,注意但是,好在,我们通过特定的CSS代码设置,我们可以让表现保持一致。由于边框是<fieldset>元素产生的,所以,我们可以设置:

fieldset {
    border: 1px solid #ddd;
}

所有浏览器下,基本上效果就大统一了。

如果我们仅仅希望就上面有一条线,我们可以:

fieldset {
    border: 0 none;
    border-top: 1px solid #ddd;
}

如果,我们希望<legend>里面的文字居中对齐,而不是飘在左上角,则……说来话长。

首先,Chrome浏览器下,我们使用text-align:center即可~

legend {
    text-align: center;
}

IE浏览器,IE8+浏览器下可以使用margin:auto

legend {
    text-align: center;
    margin: auto;
}

但是IE7和Firefox浏览器怎么办呢?告诉大家,经过我的反复尝试,几乎无解。有一种方法可以实现居中,那就是:

legend {
    width: 100%;
}

但是,由于<legend>元素的原始位置天然镂空下面的边框,因此,这种设置,会让<fieldset>元素的上边框无法显示,我们使用这两个元素就是看上了上边框的覆盖和开口特性,如果被覆盖了那还使用个毛线啊。

兼容问题在眼前,难道就这么结束了?其实不是的,虽然CSS有些强弩之末的感觉,但是,毕竟这是上世纪就出现的HTML元素,因此,要想居中对齐,还要看HTML属性,如下设置:

<fieldset>
    <legend align="center">标题</legend>
</fieldset>

效果如下(实时):

标题

结果所有浏览器下一马平川,一路居中。

这跟type="file"<input>需要size控制宽度的尿性有些类似。

我们还可以设置线框的类型为虚线,例如:

fieldset {
    border: 0 none;
    border-top: 1px dashed #ddd;
}

但是,有个不幸的消息,在IE浏览器下,如果border-style类型如果不是实线solid,则边框线就会从标题内容下面穿过去,而不是镂空,如下截图:
IE浏览器下非solid边框穿过标题

我瞬间无言以对,而且所有IE浏览器都是这样,我内心呵呵一下。不过IE浏览器很淡定,因为黑色上面再抹点黑色是没有区别的。并且几乎无解。并且IE浏览器还不支持border-radius圆角,需要<legend>浮动后绝对定位或变成其他display类型。

如果非对虚线或者点线念念不忘,我能想到的挫方法就是弄个背景色覆盖覆盖了。

然后,<fieldset><legend>元素组合使用的时候,<legend>一定要是第一个子元素,并且是正常块状流。如果我们在<legend>前面插入其他元素,则在Chrome和Firefox浏览器下,会忽略,视觉表现上会呈现在<legend>的下面。

基本上总结下,如果你有文字压线的效果,使用<fieldset><legend>布局是成本最低的,标题想居中,使用align="center"这个HTML属性,如果是实色边框,无论是solid或者double都可以自如使用,没有兼容性问题,但如果是虚线边框,则要考虑IE浏览器穿透的问题。

好了,说了那么多,我们当场演示一个妙用<fieldset><legend>元素低成本实现特殊布局的效果。什么效果呢?我写文章的时候,有时候会打上分隔线,写上文字示意这里有一段风格。我之前是使用字符实现的,类似“——————低调的分隔线———————-”,使用字符的问题在于,如果在手机上看,很可能字符换行了,就显得有点傻了。

有了<fieldset><legend>事情就简单多了,如下CSS和HTML:

fieldset {
    border:0;
    border-top:1px dashed #ccc;
}
legend { 
    color: #999;
    /* for IE */
    background-color: #fff;
}
<fieldset>
    <legend align="center">低调的分隔线</legend>
</fieldset>

效果如下,是不是比之前实现要巧妙和清爽的多。

低调的分隔线

实际上,对于本例子,最好的实现是使用伪元素生成“低调的分隔线”这几个字,因为,这几个字实际上不属于文章内容的一部分。

四、结束语

本文时间跨度正好一整日,从开头看我的心情还不错,但是,写结束语的时候,心情哪,五味杂陈。

写作结尾的时间

今天小马哥给腾讯的每个员工送了300股腾讯股票,算算6万多港币,想想自己,也就早走半年而已,再想想腾讯股票我160就卖掉了,而现在200多,更是哭晕在厕所。

不过现在好多了,因为老婆安慰我说:“没事,我们还有土可以吃!”想想也是,剁手节一过,很多人土都吃不起,顿时平衡了很多。

你还别说,土的味道还不错,要不,也给你来两份?

可以吃的土

(本篇完)

分享到:


发表评论(目前8 条评论)

  1. bestRenekton说道:

    为什么 IETester上的 IE8测试有问题啊。。。不居中

  2. 云中漫步说道:

    >>我瞬间无言以对,而且所有IE浏览器都是这样,我内心呵呵一下。不过IE浏览器很淡定,因为黑色上面再抹点黑色是没有区别的。并且几乎无解。并且IE浏览器还不支持border-radius圆角,需要浮动后绝对定位或变成其他display类型。

    —-现在遇到IE的这个问题,圆角设置后,加入legend就无法呈现,在firefox和chrome中没这个问题,怎么解?

  3. 陈二少说道:

    legend的位置不是第一个子元素的时候,在ie浏览器下,legend之前的标签在视觉上没有被框住,而在其他浏览器(经测试火狐、谷歌)下,与legend是第一个子元素的情况无异,这个能否解决

  4. 盖大楼说道:

    一下更新三篇,好多。
    作为一个新手,感觉本文最重要的就是提醒我们要注意语义化标签,有时候能用a标签,但是页面完成后,后台的要让我改成input标签;用背景图做完了,又要改成img标签。类似的情况还有一些,这里我不是很懂什么时候该用什么标签?

  5. panshijie205说道:

    张老师,CSS代码里legend误写成了lengend

  6. VV说道:

    老师你太棒啦

  7. 夜雨声繁说道:

    土已经吃不起了,张老师