CSS 设计指南之界面组建

导航菜单

菜单由一组链接组成。用 HTML 中的列表元素(ul 或 ol)来分组链接不仅符合逻辑,而且即使没有额外的 CSS 也能适当显示链接的层次。默认列表项(li)是块级元素,因此它们会上下堆叠。

纵向菜单

标签:

<nav class="list1">

<ul>

<li><a href="#">Alternative</a></li>

<li><a href="#">Country</a></li>

<li><a href="#">Jazz</a></li>

<li><a href="#">Rock</a></li>

</ul>

</nav>

样式:

/*去掉默认的内边距和外边距*/

* {

margin: 0;

padding: 0;

}

/*设定菜单的大小和位置*/

nav {

margin: 50px;

width: 150px;

}

/*给菜单加上边框*/

.list1 ul {

border: 1px solid #f00;

border-radius: 3px;

padding: 5px 10px 3px;

}

/*去掉项目符号并为链接添加间距*/

.list1 li {

list-style-type: none;

padding: 3px 10px;

}

/*“非首位子元素”选择符 (任何跟在li之后的li) */

.list1 li+li {

border-top: 1px solid #f00;

}

/*为链接添加样式*/

.list1 a {

text-decoration: none;

font: 20px Exo, helvetica, arial, sans-serif;

font-weight: 400;

color: #000;

background: #ffed53;

}

/*悬停高亮*/

.list1 a:hover {

color: #069;

}

菜单1

非首位子元素 选择符 : 如:li+li , 对于连续的元素,这样,就可以给除第一个 元素 之外的所有元素设定相同的样式。

同样效果的其他方法 :

/*给所有 li 上方添加一条边框*/

li {

border-top:1px solid #f00;

}

/*去掉第一个 li 上方的边框*/

li:first-child {

border-top:none;

}

让列表行可以点击

目前只有文本是可以点的,因为链接(a)是行内元素,它会收缩并包住其中的文本。然而,更好的用户体验是让列表项所在的整行都能点击。(很多站点都没有这么做)

  • li标签 的内边距调整到 a标签里, 并且 a标签 的显示方式调整为 block.
  • li标签 的上边框调整到 a标签

/* 去掉li元素的上边框 */

.list1 li {list-style-type:none;}

/* 调整到a标签的上边框 */

.list1 li + li a {border-top:1px solid #f00;}

/* 调整内边距,显示方式调为 块 显示(让链接完全填满整个列表项) */

.list1 a {display:block; padding:3px 10px;

text-decoration: none; font:20px Exo, helvetica, arial, sansserif;

font-weight:400; color:#000; background:#ffed53;}

菜单2

菜单3

横向菜单

默认情况下,列表项是垂直堆叠在一起的。不过,要把它们变成水平排列的横向菜单。方法是浮动列表项。

<nav class="list1">

<ul>

<li><a href="#">Shirts</a></li>

<li><a href="#">Pants</a></li>

<li><a href="#">Dresses</a></li>

<li><a href="#">Shoes</a></li>

<li><a href="#">Accessories</a></li>

</ul>

</nav>

.list1 ul {

/*强制 ul 包围浮动的 li 元素*/

overflow: hidden;

}

.list1 li {

/*让 li 元素水平排列*/

float: left;

/*去掉项目符号*/

list-style-type: none;

}

.list1 a {

/*让链接填满 li 元素*/

display: block;

padding: 0 16px;

/*去掉链接的下划线*/

text-decoration: none;

color: #999;

}

.list1 li+li a {

border-left: 1px solid #aaa;

}

.list1 a:hover {

color: #555;

}

菜单4

这个水平菜单很常见,很多时尚的零售网店都有它们的身影。

  • 浮动让 li 元素从垂直变成水平,display:block 让链接从收缩变成扩张,从而整个 li 元素都变成了可以点击的。
  • 另外,选择符 li + li a 为除第一个链接之外的每个链接左侧都加了一条竖线,作为视觉分隔线。

下拉菜单

下拉菜单是以一组嵌套列表为基础,综合运用刚刚学到的纵向和横向菜单的CSS 技术创建的。

菜单5

<nav class="multi_drop_menu">

<!-- 一级开始 -->

<ul>

<li><a href="#">Power</a></li>

<li><a href="#">Money</a></li>

<li><a href="#">Love</a></li>

<li><a href="#">Fame</a>

<!-- 二级开始 -->

<ul>

<li><a href="#">Sports Star</a></li>

<li><a href="#">Movie Star</a></li>

<li><a href="#">Rock Star</a>

<!-- 三级开始 -->

<ul>

<li><a href="#">Bruce Springsteen</a></li>

<li><a href="#">Bono</a></li>

<li><a href="#">Mick Jagger</a></li>

<li><a href="#">Bob Dylan</a></li>

</ul>

<!-- 三级结束 -->

</li>

<li><a href="#">Web Designer</a></li>

</ul>

<!-- 二级结束 -->

</li>

</ul>

<!-- 一级结束 -->

</nav>

为方便设定菜单样式,为列表容器 nav 添加了 multi_drop_menu 类。这个菜单的每一条CSS规则都以 .multi_drop_menu 开头,以确保它们只会应用给带有这个类的容器。

顶级菜单样式

/*添加视觉样式 开始*/

.multi_drop_menu {

font: 1em helvetica, arial, sans-serif;

}

.multi_drop_menu a {

/*让链接充满列表项*/

display: block;

/*文本颜色*/

color: #555;

/*背景颜色*/

background-color: #eee;

/*链接的内边距*/

padding: .2em 1em;

/*分隔线宽度*/

border-width: 3px;

/*可以有颜色,也可以透明*/

border-color: transparent;

}

.multi_drop_menu li:hover > a {

/*悬停时文本颜色*/

color: #fff;

/*悬停时背景色*/

background-color: #aaa;

}

.multi_drop_menu li a:active {

/*点击时背景变色*/

background: #fff;

/*点击时文本变色*/

color: #ccc;

/*背景只出现在内边距区域后面*/

background-clip: padding-box;

}

/*添加视觉样式 结束*/

/*添加功能样式 开始 */

/* 布局,行为,*/

.multi_drop_menu * {

margin: 0;

padding: 0;

}

/*强制 ul 包围 li*/

.multi_drop_menu ul {

float: left;

}

.multi_drop_menu li {

/*水平排列菜单项*/

float: left;

/*去掉默认的项目符号*/

list-style-type: none;

/*为子菜单提供定位上下文*/

position: relative;

}

.multi_drop_menu li a {

/*让链接填充列表项*/

display: block;

/*给每个链接添加一个右边框*/

border-right-style: solid;

/*背景只出现在内边距区域后面*/

background-clip: padding-box;

/*去掉链接的下划线*/

text-decoration: none;

}

.multi_drop_menu li:last-child a {

border-right-style: none;

}

/*临时隐藏低级菜单*/

.multi_drop_menu li ul {

display: none;

}

/*添加功能样式 结束 */

菜单6

对于CSS的样式,首先要注意把菜单的视觉样式功能样式分开来写。

  • 视觉样式 : 控制 字体大小 、边框 和 文本的颜色.
  • 功能样式 : 控制菜单的 布局 和 行为。

两者的区别主要通过代码注释。

对于像下拉菜单这么复杂的组件,分开来写视觉和功能代码是非常值得提倡的。

这样,将来如果有人要修改菜单外观,只要修改它的 视觉样式 就好了,而 功能样式 可以原封不动。

注: 如果在代码中像这样把 视觉样式 与 功能样式 分开来写,一定要用注释说明为什么。

目前最明显的变化是 li 通过浮动由垂直堆叠变成了水平排列。

至于为了让 ul包围列表项,没有使用 overflow:hidden,而是使用了 float:left,是因为前者会导致后来添加到下拉菜单中的子菜单无法显示。

【最终会显示在父元素 ul 的外面,结果会因为“溢出”(overflow)而被隐藏(hidden)】。

为了保证用户体验,所有视觉样式——内边距、背景、边框,等等,都要应用给链接 a,而不要应用给 ul 或 li,

以便热区(可点击区域)最大化,让用户鼠标经过时不会产生前面例子中看到的状态切换。

为达到这个目的,同时还要从视觉上分隔链接,使用 background-clip:padding-box 声明,这样可以阻止链接的背景(像常规状态下一样)延伸到边框后面。

然后,让边框透明(也可显示为其他实色),在链接之间产生间隙,让后面的页面能够透过边框被看到。

如此一来,不用外边距也能分隔链接,而且鼠标从一个菜单项移动到另一个菜单项时,也不会出现光标切换。

菜单项之间从视觉上是分开,但实际上却是紧挨在一块的。

background-clip 和透明边框的更多用法 : css-tricks

注意:

  • 给 li 元素应用了 position:relative,这是给添加子菜单做的准备,在当前没有什么效果。
  • 最后一行 CSS 隐藏了子菜单,以防显示它们影响我们创建顶级菜单。在后面会有怎么在菜单项处于悬停状态时显示它们。
  • 为顶级菜单添加的样式都会被次级菜单继承。【需要应用给子菜单的样式大部分都已经写完啦!】

菜单的下拉部分:

虽然子菜单继承顶级菜单的样式为我们提供了方便,但其实有些样式在子菜单中并不是必要的。如:

  • 下拉菜单(列表的第二级)是垂直堆叠的,所以不希望其中的列表项继承浮动而变成水平排列。
  • 顶级菜单使用右边框作为分隔线,而 下拉菜单 需要使用上边框来分隔垂直堆叠的菜单项。
  • 下拉菜单还会用到绝对定位下拉菜单,以便它能精确地对齐父元素(包含子菜单的 li),而这个父元素已经在上一步被设定成相对定位了。
  • 为了看到设定的效果,还要显示二级下拉菜单,并继续隐藏三级下拉菜单(下一步再考虑它)。

以下是实现上述改变需要添加的 CSS:

/* 添加的视觉样式 */

/*二级菜单宽度*/

.multi_drop_menu li ul {

width: 9em;

}

.multi_drop_menu li li a {

/*去掉继承的右边框*/

border-right-style: none;

/*添加上边框*/

border-top-style: solid;

}

.multi_drop_menu li li li a {

/* 三级菜单的a标签左边框分割 */

border-left-style: solid;

}

/* 添加的功能样式 */

.multi_drop_menu li ul {

/*临时显示二级下拉菜单*/

display: block;

/*相对于父菜单项定位 使用到了定位上下文,父节点的定位为relative */

position: absolute;

/*左边与父菜单项对齐*/

left: 0;

/*顶边与父菜单项底边对齐*/

top: 100%;

}

.multi_drop_menu li li {

/*停止浮动,恢复堆叠*/

float: none;

}

.multi_drop_menu li li ul {

/*继续隐藏三级下拉菜单*/

display: none;

}

菜单7

二级下拉菜单显示在其父菜单项下方

这一步成功的关键是下拉菜单的 绝对/相对定位 。

通过将其顶边位置(top)设定为100%(相对于其相对定位的父元素 li),其顶边会与父元素底边恰好对齐。

它与父元素之间的间隙,实际上是下拉菜单中第一个链接的边框.

让下拉菜单响应鼠标事件

让下拉菜单拥有自己的功能【一开始是隐藏的,只有在其父元素处于鼠标悬停状态时,才需要显示】

.multi_drop_menu li ul {

/*隐藏二级下拉菜单*/

display: none;

/*相对于父菜单项定位*/

position: absolute;

/*左边与父菜单项对齐*/

left: 0;

/*顶边与父菜单项底边对齐*/

top: 100%;

}

.multi_drop_menu li:hover > ul {

/*父元素悬停时显示*/

display: block;

}

菜单8

让菜单起作用的关键在于先把它藏起来:

/*隐藏二级菜单*/

li ul {display:none;}

然后,再在父元素悬停时把它显示出来:

/*显示二级菜单*/

li:hover > ul {display:block;}

/* 当鼠标移动到列表项上时,就显示它的子列表。 */

注意,这里的 :hover 触发器 是设定在 li 元素 而非 链接(a标签) 身上的。

这样做是因为想要显示li 的子元素 ul,而它(a标签)不是想链接的子元素。

此外,为了只显示其子元素,悬停列表项与子列表之间还有一个 子选择符 >

如果没有这个子选择符,当顶级菜单项处于悬停状态时,会同时显示二级和三级菜单。

添加三级菜单

这时候三级菜单已经算是能用了。只不过位置不对。

菜单9

由于前面包含:hover 的 CSS 规则会像应用给二级菜单一样,应用给三级菜单,所以在父元素处于鼠标之下时,三级菜单自然也会显示出来。

可是图中的三级菜单被其父元素挡住了。这时候三级菜单与其二级父元素的位置是 二级菜单与顶级菜单的关系 。

所以,三级菜单跑到了鼠标下的二级菜单后面去了,而且其第一项顶边与悬停的父菜单项底边是对齐的。

从图中可以看到,三级菜单第一项“Bruce Springsteen”的上半部分被二级菜单最后一项“Web Designer”给盖住了。

在这一步要做的,就是把三级菜单放到二级菜单右侧,让它的顶边与鼠标所在菜单项的底边对齐。

.multi_drop_menu li li ul {

/*相对于父菜单定位*/

position: absolute;

/*与父菜单右侧对齐*/

left: 100%;

/*与父菜单项顶边对齐*/

top: 0;

}

现在的菜单能用了,可以在顶级添加更多列表项,在标记中添加更多子列表,然后无须多写一行 CSS,它们就能构成新的下拉菜单。

此时,还应该再作两个调整。

首先,为了真正让这些代码有用,而且可以重用,需要再写一些样式,让顶级菜单能够 垂直显示,以便能将其用在导航 侧边栏 里。

为此,我得先给 nav 容器添加第二个类 vertical

<!-- HTML 类名之间要有空格 -->

<nav class="multi_drop_menu vertical">

/* CSS 类名之间没有空格 */

/* .multi_drop_menu.vertical */

/*只在导航容器有 vertical 类的情况下才起作用*/

/*顶级垂直菜单宽度*/

.multi_drop_menu.vertical {

width:8em;

}

.multi_drop_menu.vertical li a {

border-right-style:none;

border-top-style:solid;

}

.multi_drop_menu.vertical li li a {

border-left-style:solid;

}

.multi_drop_menu.vertical ul,

.multi_drop_menu.vertical li {

/*让顶级菜单垂直显示*/

float:none;

}

.multi_drop_menu.vertical li ul {

/*子菜单左边与上一级菜单右边对齐*/

left:100%;

/*子菜单顶边与上一级菜单项顶边对齐*/

top:0;

}

菜单10

为了让菜单恢复默认的堆叠状态,这里重置了顶级 li 元素及其父元素 ul 的浮动属性,后者原来浮动是为了包围浮动的 li 元素。

这里还为 nav 容器设定了宽度。如果不设定导航容器宽度,那么 nav 及其包含的顶级菜单项都会尽可能伸展。最后,把二级菜单与顶级菜单的位置关系,设定成了前面三级菜单和二级菜单之间的关系,即让子菜单顶边与父菜单项顶边对齐。当然去掉了顶级菜单项的右边框,代之以上边框.

突出显示选择路径

菜单11

只有位于鼠标下方的元素才会突出显示。为了让用户明确地知道自己是怎么一路选择下来的,还需要让每一级菜单中被选择的元素突出显示。

实际上只要把 .multi_drop_menu a:hover 替换成以下 CSS 即可。

.multi_drop_menu li:hover > a {

/*悬停时的文本颜色*/

color:#fff;

/*悬停时的背景颜色*/

background-color:#aaa

}

这个小小的替换能够起作用,是因为:hover 事件会沿着元素的结构层次 “向上冒泡”。

所以,把 :hover 设定在 li 元素,就相当于也把它设定给了所有祖先 li 元素。

然后,只要再给其子元素(链接)设定样式即可。这个改进能够极大地提高菜单的易用性,下拉菜单到此讲完了,最终结果如上图所示。

有了以上 CSS 文件,只要把它链接到页面中,并给一个包含无序列表的容器加上 multi_drop_menu 类,该列表就会摇身一变,成为一个全功能的菜单,

表单

表单与其他页面元素的作用不同。

其他元素是把服务器发过来的内容显示给用户,

而表单则是把用户的信息发送给服务器。

作为设计者,当然希望用户能够顺利地使用表单,从而得到他们的反馈、意见、联系信息……当然——还有他们的信用卡号。

大型表单的复杂程度较高,电商网站的购物车就是一例。假如设计得不好,让用户觉得费解,很可能转眼之间就丢掉了生意。可见,设计的品质是可以用白花花的银子来衡量的。

关于表单设计的参考 Web Form Design: Filling in the Blanks

HTML表单元素

HTML5表单

HTML5 为 input 元素新增了 13 种新类型(type 属性),也对表单进行了大幅增强,包括特别特别棒的 placeholder 属性,可以在文本框中显示说明文字(例如“在这里填写用户名”),只要用户一开始输入它就会消失。

了解新增的 HTML5 表单标签和属性,以及浏览器对它们的支持情况,可以参考这个网页 和 html5forms.

更详细的input标签介绍:INPUT – Form Input 和 html-form-tutorial

标签:

<!-- 必要的 form 标签 -->

<form class="stylin_form1" action="process_form.php" method="post">

<h3>A Stylin' Form</h3>

<!-- 控件组,即各种控件的容器 -->

<fieldset>

<!-- 控件组的文字说明,或标题 -->

<legend><span>Part 1 &#8226; Basic Controls</span></legend>

<!-- 开始单行文本输入控件 -->

<section>

<p class="note">* indicates required field</p>

<!-- for 属性把标注与控件关联起来,它的值必须与控件 ID 值相同 -->

<label for="user_name">User Name<span> *</span></label>

<!-- text 属性让这个控件可以输入文本 -->

<input type="text" id="user_name" name="user_name" />

<p>Please select a user name</p>

</section>

<!-- 开始密码控件 -->

<section>

<label for="password">Password<span> *</span></label>

<!-- 密码文本显示为掩码 -->

<input type="password" id="password" name="password" maxlength="20" />

<p>Password must be 8 or more characters</p>

</section>

<!-- 开始多行文本输入控件 -->

<section>

<label for="description">Description</label>

<textarea id="description" name="description" placeholder="Enter the description here."></textarea>

</section>

<!-- 开始 HTML5 日期控件 -->

<section>

<label for="description">Date</label>

<input type="date" id="special_date" name="event_date" min="2012-09-05" />

</section>

</fieldset>

<fieldset>

<legend><span>Part 2 &#8226; Multiple-Choice Controls</span></legend>

<!-- 开始复选框 -->

<section>

<h4>Select Any Number</h4>

<section>

<input type="checkbox" id="check1" name="checkset" value="1" tabindex="4" />

<label for="check1">Choice 1</label>

</section>

<section>

<input type="checkbox" checked="checked" id="check2" name="checkset" value="2" />

<label for="check2">Choice 2 is pre-checked</label>

</section>

<section>

<input type="checkbox" id="check3" name="checkset" value="3" />

<label for="check3">Choice 3&mdash;add as many as you need!</label>

</section>

<p>You must choose one or more</p>

</section>

<!-- 开始单选按钮 -->

<section>

<h4>Select Only One</h4>

<section>

<input checked="checked" id="radio1" name="radioset" type="radio" value="Choice_1" />

<label for="radio1">Choice 1 is pre-selected and shows the text wraps nicely if it goes to multiple lines.</label>

</section>

<section>

<input id="radio2" name="radioset" type="radio" value="Choice_2" />

<label for="radio2">Choice 2</label>

</section>

<section>

<input id="radio3" name="radioset" type="radio" value="Choice_3" />

<label for="radio3">Choice 3</label>

</section>

</section>

<!-- 开始选项列表(下拉列表) -->

<section>

<label for="select_choice">Select Your Choice</label>

<select id="select_choice" name="select_choice">

<option value="0">None</option>

<option value="1">Choice 1</option>

<option value="2">Choice 2</option>

<option value="3">Choice 3</option>

<option value="4">Choice 4</option>

</select>

</section>

</fieldset>

<!-- 开始提交按钮 -->

<section>

<input type="submit" value="Submit This Form" />

</section>

</form>

表单1

基于常用表单元素创建的表单

form 元素

所有表单的标记都包含在一个 form 元素中。

<form class="stylin_form1" action="process_form.php" method="post">

<!-- 这里是表单标记 -->

</form>

form 元素有两个必要的属性:action 和 method。

action 属性用于指定服务器上用来处理表单数据的文件的 URL。

method(值要么是 post,要么是 get)用于指定怎么把数据发送到服务器。

服务器处理表单数据参考:html-form-tutorial。网页底部还有不少与表单相关的链接,

提交表单

用户提交表单后,他们在 表单控件 中填写的表单数据或者做出的选择,都会被发送到服务器。

  • 控件,是对表单中用来收集数据的各种表单组件的通称,包括 文本框复选框单选按钮,等等。
  • 表单中的数据是以“名=值”的形式发送给服务器的,比如 “username=chrisconsumer”,每个控件都是这么一个 名/值 形式。
  • 这里的“名”就是你在控件 name 属性中设定的名字。
  • 这里的“值”可能是用户在文本控件中输入的信息,也可能是表示可选控件(如复选框)中某一项是否被选中的 布尔状态值(比如某个复选框中用 1 表示选中,用 0 表示未选中)。

在确定这些控件的名字时,最好跟编程人员以及数据库管理员共同协商,得到一个大家都认可的命名方案。

控件组

可以把一组相关的表单控件组织到一个控件组元素 fieldset 中。

比如: 在一个电商网站上, 用于收集用户姓名和地址的控件组 ,可能会加上一个标题叫“收货人信息”。随后可能就是另一个 用于填写信用卡信息的控件组 。

前面表单标记使用了两个 fieldset 元素,把所有控件分成了两组。

第一组包含基本的标注和控件,第二组包含更复杂的控件,比如复选框(type=”checkbox”)、单选按钮(type=”radio”)和选项列表(select)。

fieldset 的第一个子元素一定得是 legend文本元素,其中包含这个控件组的标题。

<fieldset>

<legend>Mailing Address</legend>

<!--- 标注和控件 -->

</fieldset>

控件与标注

表单包含一或多个控件。如前所述,控件就是让用户勾选、点选、输入的组件。

对于那些可以输入的控件,大家又俗称其为字段。

每个表单控件(submit 按钮除外),都有一个对应的 label 文本元素,用于描述控件代表的数据。

<label for="user_name">User Name</label>

<!-- 创建一个文本字段 -->

<input type="text" id="user_name" name="user_name" />

<p>Please select a user name</p>

label 元素可以包含控件,也可以放在控件前头或后头。

如果像前面那样没有用 label包含控件,那么 label 的 for 属性与控件的 id 属性必须匹配,以便把两者关联起来。

不过,控件与标注之间的关系是隐式存在的,而且如果 label 像下面这样包含控件,其 for 属性也不是必需的:

<label>User Name<input type="text" name="user_name" />

</label>

for 属性与 id 属性通过相同的值关联起来后,用户点击标注文本也可以选择单选按钮和复选框。

无论采用哪种方式关联标注与控件都没问题,重要的是一定要有这种关联。这种关联对于屏幕阅读器等辅助技术解读表单非常关键。

个人习惯于把 label 放在控件前面(当然对于 复选框 和 单选按钮,还是要放在后面),因为这样更方便设定样式。

除了标记和控件,有时候还需要告诉用户如何填写或选择,特别是在需要填写特定格式数据(如日期)的时候。

HTML 中没有为表单控件说明规定什么标签,因此就用 p 这个段落元素吧。

另外,说明的文字最好方便在用户输入无效数据的情况下突出显示(比如变成红色),这样就不用单独准备和控制错误消息了。后面会介绍怎么做到这一点。

当然,如果希望在用户输入无效数据时显示不同于说明的错误消息,可以再添加一个 p 元素,并赋予它.error 类。

控件类型

最常用的 HTML 表单元素是 input , 因为它可以在屏幕上显示为多种不同的外观,并具有不同的行为。

文本框、复选框、单选按钮等的背后都是 input 元素,区别在于它们的 type 属性。

下面列出了 type 属性部分可能的值:

  • text:基本的单行文本框。
  • password:文本显示为掩码。
  • checkbox:复选框。
  • radio:单选按钮。
  • submit:提交表单的按钮。
  • time、date、search:HTML5 文本框的变体。

这些类型值决定了相应 input 元素的外观和行为。

type 属性的所有值可参考: MDN-firefox 和 中文版

有一个文本控件不是 input 元素的变体,那就是多行文本区 textarea 元素。另外,在用户输入之前一直显示的占位符文本,是通过 placeholder 属性设定的。

复选框、单选按钮和选项列表

这三种表单元素比一般的控件/标注组合要复杂一些:

  • 复选框可以让用户从多个备选项中选择一或多个项。每个备选项都是非排他型的,即勾选同一组中的其他项,不会影响已经选择的项。
  • 单选按钮限制用户只能从多个备选项中选择一项。每个备选项都是排他型的,即勾选同一组中的另一项,就会取消对前一项的选择。

    • 特别注意一下,复选框和单选按钮都是成组出现的,分组的方法是为它们设定相同的 name 属性。
    • 本例中的单选按钮,它们共同的名字叫 radioset。这个组中的每个单选按钮由其 value 属性唯一标识。
    • 本例中,分别是 Choice_1、Choice_2,等等。假设用户选择了第一个按钮,那么发送到服务器的名/值对,就是 radioset=Choice_1。

  • 选项列表(select 元素)会创建一个下拉列表,用户可以在其中点选。在 select元素中,每个备选项都用 option 文本元素来生成。

HTML 中的所有表单元素,可以参考这里:form-elements

表单标记策略

因为 HTML 标准没有规定专门包含控件及其标注的元素,所以可以用块级 section元素来充当这个角色。

这样既方便组织控件,又方便为行内表单控件及其标注设定样式。

基本的标注和控件

在前面的标记中,把每个标注和控件都放到了一个 section 元素中,让 label 位于控件之前。

<section>

<label>…</label>

<input />

<p>…</p> <!-- 控件使用说明 -->

</section>

通过把每一对标注和控件都放到块级 section 元素中,它们自然就在页面上垂直堆叠起来了。而且,这样也有了一个可以定位它们的包含元素。

复选框和单选按钮

单选按钮和复选框是由很多标注/控件组成的,所以把它们都放到了一个 section元素中(便于为标注/控件设定基本的 CSS 样式)。

然后,在这个元素里面,再把每个复选框或单选按钮的标注/控件分别放到各自的 section 元素中。

<section>

<h4>Set Heading</h4>

<!-- 第一个单选按钮/复选框 -->

<section>

<input />

<label>…</label>

</section>

<!-- 第二个单选按钮/复选框 -->

<section>

<input />

<label>…</label>

</section>

<!-- 控件使用说明 -->

<p>…</p>

</section>

这时候,把标注放到了控件后面,这样它才能显示在控件右侧。

虽然每个控件(复选框和单选按钮)都有一个对应的标注,但不能将它们用作整个控件组的标题。

每个 label 元素只能用于标注一个控件。为此就用一个 h4 元素来作为它们的标题。

如前所述,还添加了一个 p 元素,用于显示控件使用说明。

HTML 未来的版本中或许会专门规定这些特定用途的标签。

但在此之前,到底选用什么标签来达到目的,还是会因人而异。

设定表单样式

首先,从表单的整体布局开始。【就是先设定 form 和两个 fieldset 元素的样式。】

form.stylin_form1 {

width:14em; /* 表单整体宽度 */

margin:20px auto; /* 在容器内居中 */

border:1px solid #bbb7ae;

padding:.5em .5em .15em;

}

.stylin_form1 h3 { /* 表单主标题 */

margin:0;

padding:0 0 .2em .2em;

font-weight:600;

color:#bbb7ae;

}

.stylin_form1 fieldset { /*包含控件与标注*/

margin:0;

padding:0 0 .2em 0;

width:100%;

border:0;

}

/* legend 元素的位置不同寻常,所以我把它的文本包含在一个块级 span 中,转而为 span

设定样式 */

.stylin_form1 legend {

width:100%;

padding:.3em 0;

background:#bbb7ae; /*灰色条*/

}

.stylin_form1 legend span { /* 设定标题文本的样式 */

display:block;

font-size:1em;

line-height:1.1em;

padding: 0 0 0 .4em;

font-weight:700;

color:#fff; /*灰色条上的反白文本*/

}

通过为 form 设定内边距,它所包含的内容都与表单边界空开了距离。

很明显,给 legend 添加了灰色条,相应地把文本设定成了白色。

legend 元素默认的位置是由浏览器内部的一种未加说明的机制确定的,并不是由浏览器样式表设定的。因此,不可能通过 CSS 来精确控制它的位置。

解决这个问题的方法,就是把它的文本包含在一个 span 元素中,将该元素设定为 display:block,然后再设定该元素的位置。

接下来,从宏观到微观,给控件组(fieldset)中的控件和标注设定样式:

.stylin_form1 section {

overflow: hidden;

/* 强制 section 包含表单控件及标注 */

padding: .2em 0 .4em 0;

border-bottom: 8px solid #e7e5df;

/* 根据需要在每个 section 间增加间距 */

}

.stylin_form1 section:last-child {

/* 每组最后一个 section 没有边框 */

border-bottom: 0px;

}

.stylin_form1 section label,

/* 表单控件的标注 */

.stylin_form1 section h4 {

/* h4 是复选框和单选按钮组的标题 */

display: block;

clear: both;

margin: .3em .3em 0 0;

/* 右外边距确保标注文本在碰到 input 之前会换行 */

padding-bottom: .1em;

font-size: .8em;

font-family: 'Droid Sans';

font-weight: 400;

line-height: 1.1;

}

.stylin_form1 section label span,

/* 星号表示必填字段 */

.stylin_form1 section h4 span {

font-size: .75em;

vertical-align: text-top;

color: #f00;

}

.stylin_form1 section p.note {

/*说明星号是必填字段的文本*/

font-size: .7em;

color: #f00;

margin: 0;

padding: 0 0 .3em 0;

}

.stylin_form1 section input,

.stylin_form1 section textarea,

.stylin_form1 section select {

margin: .2em .5em .2em 0;

padding: .2em .4em;

/* 给 input 中的文本添加间距 */

color: #000;

box-shadow: 1px 1px 3px #ccc;

font-size: .8em;

/* 针对 Firefox - 没有这条声明会在 textarea 上使用 Courier */

font-family: inherit;

outline: none;

/* 去掉默认蓝色聚焦轮廓线 */

}

/* 设定文本字段(文本、密码、日期、文本区等)的样式,并加圆角 */

.stylin_form1 section input,

.stylin_form1 section textarea {

width: 12em;

/*设定字段宽度*/

border: 1px solid #bbb7ae;

border-radius: 3px;

/*圆角边框*/

}

.stylin_form1 section textarea {

height: 5em;

/* textarea 的高度 */

margin-top: .3em;

/* 与上面 label 的间距 */

line-height: 1.1;

}

.stylin_form1 section p {

/*控件使用说明*/

margin: .3em .75em 0;

clear: both;

font-size: .7em;

line-height: 1.1;

color: #000;

}

.stylin_form1 section p.error {

color: #f00;

/* 添加 error 类,把说明文字设定为红色 */

}

表单2

把所有控件的可见盒子(类型为 text、date、textarea 和 select)都设定为相同宽度,为说明文字应用了样式,并给每个 section 元素添加了较宽的边框,让它们从视觉上保持适当距离。

某些标注后面的星号表示相应字段是必填的,也就是用户不能不填。

这个(用 Shift-8)输入的星号被包含在 span 元素中,以便调整它与标注文本的相对位置,并应用不同颜色。

注意,还为控件使用说明段落设定了一条 p.error 规则。

如果控件中数据无效,这个类就会被添加到说明段落上。然后,说明文字会变成红色,提醒用户必须输入有效数据才能提交表单。

这个 error 类将由验证表单的代码添加

下面该轮到复选框、单选按钮和选项列表了。

这些控件全都位于第二个控件组中。它们的标注都在控件下方,应该让这些标注与控件并排显示。

/* 复选框和单选框 */

.stylin_form1 section section {

/* 控件/标注的内包装 */

overflow: hidden;

/* 强制元素包围浮动标注 */

margin: .2em 0 .3em .4em;

padding: 0 0 .1em 0;

border-bottom: none;

}

.stylin_form1 section section input {

/*单选按钮或复选框*/

float: left;

clear: both;

width: auto;

/* 重设继承的宽度 */

margin: .1em 0 0em .3em;

/* 顶部与标注对齐,左侧防止 intput 溢出 */

}

.stylin_form1 section section label {

float: left;

clear: none;

/* 重设继承的值 */

width: 15em;

margin: .15em 0 0 .6em;

/* 在相邻的复选框之间、复选框与标注之间增加间距 */

font-weight: normal;

/* 重设继承的值 */

font-size: .7em;

line-height: 1.2;

}

.stylin_form1 section select {

margin-left: .4em;

font-size: .85em;

}

.stylin_form1 section input[type="submit"] {

/*提交按钮*/

width: auto;

/* 覆盖为其他字段设定的宽度 */

margin: .4em .3em 0 0;

font-size: 1em;

font-weight: 800;

color: #fff;

background-color: #bbb7ae;

cursor: pointer;

/*在鼠标位于按钮之上时,把光标变成小手形状*/

}

.stylin_form1>section:last-child {

/*居中提交按钮*/

text-align: center;

}

表单3

复选框、单选按钮和提交按钮已经各就各位

每一组单选按钮和复选框的标题,看起来很像表单第一个控件组里的标注。

但实际上,它们是 h4 元素——我们只能用 label 来关联控件。

正因为如此,要把同样的样式设定给 h4 很简单,把为表单第一个控件组中的 label 设定样式的选择符中的 label替换成 h4 即可。

然后,给这里每个复选框和单选按钮的小标注另外写一种样式。

为了让选项列表与其他元素对齐,我们也为它设定了相应的样式,通过减小其文本大小也把它缩小了一点。

至于提交按钮,它的宽度不再继承前面设定给其他 input 的规则,并且在表单底部居中。

明确告诉用户,这是表单的最后一个步骤。

在为 name 属性设定同一个名字的情况下,复选框和单选按钮的行为就像一个组一样。提交表单时,它们的 name 值与 value 值,将分别作为“名=值”对中的“名”和“值”。

接下来让表单的标注显示在控件的左侧。使用这个“标注在左”版的样式也很简单,只要给 form 元素加上 labels_left 类即可。

form.stylin_form1.labels_left {

width: 22em;

/*加宽表单,为标注腾出地方*/

}

form.stylin_form1.labels_left label,

form.stylin_form1.labels_left h4 {

float: left;

/*把标注浮动到控件左侧*/

width: 8em;

}

form.stylin_form1.labels_left p {

margin: 0 0 0 9.35em;

/*缩进控件说明,以便它位于控件正下方*/

padding: .3em 0 0 0;

clear: both;

/*确保说明不会跟着浮动的标注和控件走*/

}

form.stylin_form1.labels_left p.note {

/*必填字段文本下方的间距*/

margin: 0 0 .2em 0;

}

/*每个单选按钮或复选框及其标注的内包装*/

form.stylin_form1.labels_left section section {

width: 10em;

margin-left: 6.5em;

padding-top: 0;

}

form.stylin_form1.labels_left section section input {

width: 1.25em;

/*单选按钮或复选框的宽度*/

margin-left: 0;

}

.stylin_form1.labels_left section input,

.stylin_form1.labels_left section textarea,

.stylin_form1.labels_left section select {

float: left;

/*让控件成为第二栏*/

width: 12em;

}

.stylin_form1.labels_left section select {

/*缩进选项列表*/

margin-left: .2em;

}

/*防止提交表单按钮继承浮动的行为*/

.stylin_form1.labels_left>section input[type=submit] {

float: none;

}

表单4

这个例子涉及的那么多 HTML 和 CSS 代码,一定深深体会到了为表单添加样式多么复杂,多么耗时间。

正因为如此,这里对原型式表单的标记进行了精心设计,而且写了很多注释,以方便轻松地把它作为自己设计表单的起点。

直接复制粘贴 HTML 代码也好,模仿其结构再添加需要的各种控件也罢,别忘了把这个表单 CSS 链接到页面中。

然后,给 form 元素加上 stylin_form1 类,表单一下子就能变成现在这个样子。

以此为起点,进行各种改进和增强,就会非常容易了。

作者自己就是这样做的,这样每次都能节省好几个钟头的时间。

设计搜索表单

几乎每个站点都会提供一种搜索机制。恐怕很难把一个搜索框当成一个表单,但它的确是一个字段的表单。

搜索表单提供了简单的搜索功能,它随时恭候在标题栏的右侧,那儿几乎是它的专属位置。

苹果网站上那个小巧、低调的搜索框,在用户点击它的时候会扩展开来,为输入关键词提供更多空间。

它旁边甚至连一个按钮都没有——用户都知道点击、输入,然后再按 Return 或回车键。

这种搜索表单的 form 元素中只需要包含一个 label 和一个 input。

在下面的例子中,会把这个表单放在一个 header 标签中,以便得到一个包含搜索功能的页眉。

<header>

<form class="stylin_form_search1" action="#" method="post">

<label for="search">search</label>

<input type="search" id="search" name="search" placeholder="search" />

</form>

</header>

借这个例子,正好可以讲一讲 CSS3 的过渡功能。过渡可以基于某个 CSS 属性实现动画效果。

在这个例子中,要利用它实现文本框动态变宽的效果。

对应的CSS 如下:

* {

margin: 0;

padding: 0;

}

header {

/*在这个例子中代表页眉*/

font-family: helvetica, arial, sans-serif;

display: block;

overflow: hidden;

width: 300px;

margin: 30px;

border-radius: 6px;

background-color: #ddd;

}

form.stylin_form_search1 {

/*包含 label 和 input 的容器*/

float: right;

width: 200px;

margin: 5px;

padding: 5px;

}

form.stylin_form_search1 input {

float: right;

width: 70px;

padding: 2px 0 3px 5px;

outline: none;

/*去掉默认的突显轮廓线*/

font-size: .8em;

border-color: #eee #ccc #ccc #eee;

/*针对其他浏览器的厂商前缀*/

border-radius: 10px;

-webkit-transition: 2s width;

}

form.stylin_form_search1 input:focus {

width: 200px;

}

form.stylin_form_search1 label {

/*标注是必要的,但不用显示出来*/

display: none;

}

搜索1

这里的 form 元素是“有宽度的”,而且是向右浮动的。

表单内部的 input 也是向右浮动。

虽然 label 元素没有显示出来,但它是必须要加的。

文本框中的文本由 placeholder 属性生成,只要用户一开始输入,这些占位符文本就会自动隐藏。

运用 CSS3 过渡

在前面的 CSS 中,input 规则将该字段宽度设定为 70 像素,input:focus 规则将该字段宽度修改成了 200 像素。

这意味着,在用户单击搜索框让它获得键盘焦点之后,字段宽度会改变。

不过,由于现在有了 transition:2s width;声明,字段不会突然扩展到新宽度,而是会用两秒钟时间平滑地伸展到 200 像素。

必须注意,CSS3 的过渡声明要放在设定初始状态的规则中。而且,transition 属性需要使用带厂商前缀的形式【这里只示范了带有 WebKit(Safari/Chrome)前缀的属性】。

附注:CSS3 过渡

CSS3 过渡可以让 CSS 属性产生动画效果。平常被某些事件触发时变化很突然的样式。 比如:鼠标悬停时改变链接颜色,使用过渡后会在指定的时间段内逐渐变化。

第一条 CSS 规则设定属性的初始状态和过渡参数。

第二条 CSS 规则设定事件发生时属性的目标状态。

在下面这个例子中,用户单击表单输入字段后,输入框的边框颜色会从黑色变化为绿色,过渡周期为两秒钟。

input {border-color:black; transition:border-color 2s;}

input:focus {border-color:green;}

/* 请注意,使用 transition 属性时要针对所有浏览器添加厂商前缀。 */

通常,过渡动画是由用户鼠标悬停时的 :hover 伪类规则 和 表单元素获得焦点时 的 :focus 伪类规则 触发的。

除此之外,还可以在一个带类名选择符的规则中设定新状态,然后通过 JavaScript(或 jQuery、MooTools 等 JavaScript 库)为元素添加这个类名来触发过渡,添加类名的时机可以是鼠标点击或其他事件发生时。

有五个过渡属性:

  • transition-property,过渡的 CSS 属性名,比如 color、width;
  • transition-duration,过渡的持续时间,以秒或毫秒设定,比如 2s、500ms;
  • transition-timing-function,过渡的调速函数,决定动画效果是否平滑,是先慢后快还是先快后慢,比如 ease-in、ease-out、ease-in-out 或 linear(默认值);
  • transition-delay,过渡开始前的延迟时间,以秒或毫秒设定,比如 1s、200ms;
  • transition,过渡的简写属性,例如 transition:color 2s ease-in 1ms;

很多(并非全部)CSS 属性都可以通过 transition 属性来实现动画效果。

至于哪些属性可以实现动画效果,可以参考 animatable-properties,这个页面是 W3C 对 CSS3 Transitions Module 的官方陈述。

下面这篇介绍 CSS3 过渡的文章也非常值得一看:An Introduction to CSS3 Transitions。

弹出层

弹出层(也叫提示条)指的是在鼠标悬停于某个元素之上时显示的一个界面组件。

在页面空间有限的情况下,弹出层是为用户提供更多信息的一种有效手段。

而且,在用户把鼠标移动到关注的元素之上时,显示一个弹出层也是件自然而然的事儿。

乍一听,弹出层不是个太复杂的东西。

但是,一会儿你就知道我为什么把它放在本章最后才讲了。

围绕创建弹出层,会跟大家讲两个 CSS 中非常强大,但又没多少人真正理解的特性:z-index 属性动态生成 HTML 元素

会在接下来的练习中用到三张图片,每张图片都配一个图题。

以下就是练习的 HTML 标记,其中使用了HTML5 新增的 figure 和 figcaption 元素。

<figure>

<img src="images/pink_heels.jpg" alt="pink heels" />

<figcaption>

<h3>Pink Platforms</h3>

<a href="#">More info</a>

</figcaption>

</figure>

<figure class="click_me">

<img src="images/leopard_heels.jpg" alt="leopard heels" />

<figcaption>

<h3>Leopard Platforms</h3>

<a href="#">More info</a>

</figcaption>

</figure>

<figure class="click_me">

<img src="images/red_heels.jpg" alt="red heels" />

<figcaption>

<h3>Red Platforms</h3>

<a href="#">More info</a>

</figcaption>

</figure>

注意: 如果要使用 figcaption,必须确保它在 figure 中是唯一的。而且,它要么是第一个子元素,要么是最后一个子元素。

首先,设定 figure 元素的样式,让它在视觉上成为一个包围图片的盒子。

figure {

width: 144px; /*图片盒子宽度*/

height: 153px; /*图片盒子高度*/

margin: 20px 20px; /*图片盒子间距*/

border: 1px solid #666; /*图片边框*/

position: relative; /*为弹出层提供定位上下文*/

float: left; /*让图片并排显示*/

}

img {

display: block; /*去掉图片下方的基线空白*/

}

弹出层1

figure 元素的边框之内恰好能容纳图片,而且浮动也让它们并排显示在一行。

figcaption 元素目前就显示在它默认的位置,但下一步它就会变成弹出层。

为什么把图片设定为 display:block 呢?因为图片默认是行内元素,行内元素的定位原则是与文本基线对齐,而不是与它们容器的底边对齐。在把它们放在块级元素内部时(像这里一样),把图片转换为块级元素可以解决这个问题。

另外,这里还把 figure 元素设定为 相对定位 ,这样随后就可以把它作为定位上下文来定位figcaption 了,下面就是相应的样式。

figcaption {

display: none; /*隐藏弹出层*/

position: absolute; /*相对于容器(图片)定位*/

left: 74%;

top: 14px; /*把弹出层放到图片右侧*/

width: 130px; /*弹出层宽度*/

padding: 10px; /*弹出层内边距*/

background: #f2eaea;

border: 3px solid red;

border-radius: 6px;

}

figure:hover figcaption {display: block;} /*鼠标悬停在图片上时显示弹出层*/

figcaption h3 {

/*弹出层的内容*/

font-size: 14px;

color: #666;

margin-bottom: 6px;

}

figcaption a {

/*弹出层的内容*/

display: block;

text-decoration: none;

font-size: 12px;

color: #000;

}

这里又用到了实现下拉菜单时的技术,即先隐藏弹出层,然后在鼠标悬停时再显示它。

为了把弹出层定位在图片盒子的右侧,把它的 left 属性设定为 74%。或许有人认为在这里应该使用 right 属性,但那样就是设定图片盒子右边与弹出层右边的相对位置了。

弹出层2

弹出层3

鼠标移动图片上时,会在弹出层中显示图题。可是,前两个截图的弹出层被右边的图片给挡住了

堆叠上下文和z-index

从图中的截图来看,其中一张图片的弹出层被右边的图片给挡住了一部分。

这是由于 figure 元素的堆叠次序导致的。

在一个包含多个同辈元素的容器内,这些同辈元素都会构造一个堆叠上下文。【就像这里 body 元素的三个 figure 子元素一样】

在这个上下文中,它们的子元素会上下堆叠起来。

假如通过定位让前两个 figure 元素重叠,那么你会发现第一个 figure 元素,以及它的堆叠上下文中的所有子元素,都将位于第二个 figure 元素的后面。

第一个插图的弹出层属于第一个 figure 元素的堆叠上下文,因此它默认会在第二个 figure 元素的堆叠上下文中所有元素的后面。

CSS 中有一个 z-index 属性,用于控制元素的在堆叠上下文中的次序。【通过它可以改变元素堆叠时的默认次序。】

z-index 值较大的元素,在堆叠层次中位于z-index 值较小的元素上方。

z-index 属性的值可以是 0 到任意大的数值;负值也可以,但在某些浏览器中并不可靠。

默认情况下,所有堆叠元素的 z-index 的值为 auto,相当于 0。

不过,z-index 只对那些 position 值为 static 之外的元素有效。【涉及的两个元素必须是 absolute、relative 或 fixed 定位才行】。

在例子中,弹出层已经是绝对定位了,其位置相对于相对定位的 figure 元素。所以,只要给弹出层应用大于 0 的 z-index 值,就可以让它们在堆叠中处于最高层。这里,我们把 z-index设定为 2。

figure:hover figcaption {

display: block;

z-index:2;/*把弹出层放到最前面*/

}

弹出层4

在给弹出层设定了较大的 z-index 属性后,它们就能显示在所有图片之前了

这个例子告诉我们,应该只给悬停状态设定 z-index 属性,而不要试图通过设定个别元素的 z-index 来确保元素不会重叠。只要坚持“悬停时设定 z-index”,就能放心地摆放图片,而且知道在触发弹出层时,它一定会显示在页面的最前面,如图所示。

用 CSS 创造三角形

使用三角形对接的边框让弹出层和图片的关系更加明确。

源码:

<style>

div {

border:12px solid;

border-color:transparent red transparent transparent;

height:0px;

width:0px;

}

</style>

<div></div>

通过加宽盒子的边框,将盒子的宽和高都设定为 0,同时将其他三个边框设定为 transparent,就可以用 CSS 造出一个三角形。

三角形01

其他类型的如:

<html>

<head>

<meta charset="utf-8" />

<title> Creating a CSS Triangle</title>

<style>

div {margin:20px 30px; float:left;}

div.step1 {

border:12px solid;

border-color:red;

height:30px; width:30px;

bottom:100%; left:140px;

color:#000;

}

div.step2 {

border:12px solid;

border-color:orange red green gray;

height:30px; width:30px;

bottom:100%; left:140px;

color:#000;

}

div.step3 {

border:12px solid;

border-color:orange red green gray;

height:0px; width:0px;

bottom:100%; left:140px;

color:#000;

}

div.step4 {

border:12px solid;

border-color:transparent red transparent transparent;

height:0px; width:0px;

bottom:100%; left:140px;

color:#000;

}

</style>

</head>

<body>

<div class="step1"></div>

<div class="step2"></div>

<div class="step3"></div>

<div class="step4"></div>

</body>

</html>

三角形02

把这个技术与 ::before 伪元素结合起来。【::before 和 ::after 这两个伪元素是用于添加文本或图标等少量内容的。】

可以为它们生成的内容设定任何样式,就像给标记中其他元素设定样式一样。

在这把伪元素生成内容的盒子,通过 CSS 制作成一个三角形,并把它放到弹出层的左边。

figcaption::after { /*红色三角形的盒子*/

content:""; /*需要有内容,这里是一个空字符串*/

position:absolute; /*相对于弹出层定位*/

border:12px solid;

border-color:transparent red transparent transparent;

right:100%; top:17px; /*相对于盒子边框定位三角形*/

height:0px; width:0px; /*收缩边框创造三角形*/

}

如图:

弹出层5

以上是 CSS 设计指南之界面组建 的全部内容, 来源链接: utcz.com/z/264214.html

回到顶部