TanXinNiao / blog

贪心鸟的博客
0 stars 0 forks source link

CSS设计指南(第3版)第七章 CSS3实战 #8

Open TanXinNiao opened 3 years ago

TanXinNiao commented 3 years ago

我想先给大家讲一讲怎么规划页面的整体框架,之后再带大家一步一步地为页面每 个区域设定 CSS 样式。

TanXinNiao commented 3 years ago

规划页面结构

就算写个再简单不过的页面,恐怕都得敲出几百行 HTML和 CSS。所以,事先规划 一下页面结构是非常必要的。记住两条:代码结构要符合逻辑,规划组织要考虑层 次。只有这样,才能确保 CSS与 HTML标记前后照应、协同一致。后面例子中的代 码就是遵循上述规则组织的,我想这应该是编写网页的最佳实践。

HTML结构

着手写HTML的时候,怎么才能把画好的设计图转换成恰当的HTML元素是个挑战 一般来说,这时候你应该有一张用 Photoshop 或 Fireworks 做的设计图,至少也是用铅笔在纸上画出的页面框架图。有一张图,才好跟客户沟 通,然后再调整,保证设计的风格还有内容的组织能够满足项目需要。设计图确定 之后,就要考虑编写页面代码了。此时,第一步应该先在设计图上画一些半透明的 矩形,分别代表主要的 HTML结构。

HTML 不是由矩形的元素构成的嘛,所以一上来就应该想,怎么把页面布局分成尽 可能大的矩形区块。据此,来确定页面标记结构中的顶级元素。然后,再把每个大 区块进一步划分成更小的区块,分别对应为结构中的子元素。

从图 7-2可以看出,页面最外层的粗框是一个外包装( div#wrapper ),有了它就可以 轻易地设定布局宽度,并且让布局在浏览器窗口内居中。外包装内有 4 个与布局同 宽的矩形,它们的框稍细一些,算是布局中的顶级 HTML 元素。这时候,最好想一 想给这些元素添加什么类和 ID。不过, header 和 footer 元素是不需要类和 ID的, 因为它们在整个页面中都仅出现了一次。主要是中间两个 section 元素的矩形区块, 需要用不同的 ID来区分,我们就用 feature_area 和 book_area 。(不懂咋添加图片)

对 header 而言,其中内容可以分三部分:页面标题在左侧,导航菜单在中间,搜索 表单在右侧。在 feature_area 中,左边是博客正文的前几段,右边是一个 aside 元 素,包含登录表单和博文链接。这个 aside 区域在下一步还要细分。

再往下的 book_area 需要 4 个容器,因为要放 4 本书。最底下的 footer 包含一点文 本和一个结构化的 nav 元素。

接下来是第三级。先说 feature_area aside 吧,要把它分成两个独立的区块,一个 表单和一组链接。而在 book_area article 中,每张图片也分别用一个元素包装起来, 好为每本书的弹出层提供定位上下文。刚才说的这几个元素构成了结构化标记的第 三级。它们的方框在图 7-2 中比第二级的方框要深一点。

虽然实际写起网页来,可能还要额外加一些元素,但页面结构规划到这种程度已经 差不多了。下面就是根据以上分析,初步写出的一个标记结构。

<div id="wrapper">
    <header>
      <!-- 一级 -->
      <section id="title">
        <!-- 二级 -->
        <!-- h1 和 h2 -->
      </section>
      <nav>
        <!-- 二级 -->
        <!-- 菜单 -->
      </nav>
      <form>
        <!-- 二级 -->
        <!-- 搜索框 -->
      </form>
    </header>
    <section id="feature_area">
      <!-- 一级 -->
      <article id="blog_leadoff">
        <!-- 二级 -->
        <!-- 博客内容 -->
      </article>
      <aside>
        <!-- 二级 -->
        <form>
          <!-- 三级 -->
          <!-- 登录表单 -->
        </form>
        <nav>
          <!-- 三级 -->
          <!-- 博文链接 -->
        </nav>
      </aside>
    </section>
    <section id="promo_area">
      <!-- 一级 -->
      <article>
        <!-- 二级 -->
        <div class="inner">
          <!-- 三级 -->
          <!-- 图书封面及旋转的文字-->
        </div>
      </article>
      <!-- article 重复 4 次-->
    </section>
    <footer>
      <!-- 一级 -->
      <!-- 页脚文本和 nav 元素 -->
    </footer>
  </div> <!-- wrapper 结束 -->

仔细看一看这些标记就会知道,布局中嵌套的每一级区块,都对应着标记中嵌套的 元素。选择 HTML元素时,一定要考虑它的语义。比如,菜单列表显然应该放在一 个 nav 元素中。 写完结构化标记,可以先通过 body 元素设定页面的字体和颜色,再利用 wrapper 设 定布局宽度,并实现布局在页面上居中。

body {
  font-family:helvetica, arial, sans-serif;
  background:#efefef;
  margin:0;
}
wrapper {width:980px; margin:0 auto 20px;}
TanXinNiao commented 3 years ago

页眉

先从页眉( header )开始吧。

<header>
      <section id="title">
        <h1>Stylin&#8217; with CSS</h1>
        <h2>The Blog and Books of Charles Wyke-Smith</h2>
      </section>
      <nav class="menu">
        <ul>
          <li class="choice1"><a href="#">Articles</a></li>
          <li class="choice2"><a href="#">Books</a></li>
          <li class="choice3"><a href="#">Resources</a></li>
          <li class="choice4"><a href="#">Bookshelf</a></li>
          <li class="choice5"><a href="#">Contact Me</a></li>
        </ul>
      </nav>
      <form class="search" action="#" method="post">
        <label for="user_name">search</label> <!-- 标注的for属性与文本框ID相同 -->
        <input type="text" id="user_name" name="user_name" placeholder="search" />
      </form>
    </header>

页眉的标记分三部分:页面标题( section#title )、搜索表单( form.search )和导 航菜单( nav.menu )

页面标题

我们把 h1 和 h2 元素定位在了 header 元素的左上角。以下是 CSS。

header {
      position: relative;
      /*为页面标题和搜索表单提供定位上下文*/
      height: 70px;
      /*固定高度,包围绝对定位元素*/
      margin: 10px 0;
      background: #fff;
      border-radius: 20px 0px 20px 0px;
      /*顺序:左上、右上、右下、左下*/
      box-shadow: 0 12px 8px -9px #555;
      /*负扩展值把阴影定位到盒子内部*/
      padding: 1px;
      /*防止子元素外边距叠加*/
    }

    header section#title {
      position: absolute;
      width: 300px;
      /*宽到足以不让文本折行*/
      height: 65px;
      /*高到足以容纳两行文本*/
      left: 0px;
      /*左上角定位*/
      top: 0;
    }

    header h1 {
      padding: 9px 12px 0;
      font-family: 'Lato', helvetica, sans-serif;
      font-weight: 900;
      font-size: 2.2em;
      line-height: 1;
      letter-spacing: -.025em;
      color: #4eb8ea;
    }

    header h2 {
      padding: 0px 12px;
      font-family: "Source Sans Pro", helvetica, sans-serif;
      font-weight: 400;
      /*设定下载字体的粗细*/
      font-size: .9em;
      line-height: 1;
      letter-spacing: -.025em;
      color: #333;
    }

这里要注意的第一件事,就是明确地为 header 设定了固定高度。在前面的例子中, 我们一直提倡让内容本身决定结构化元素的高度,让高度随内容增多而扩展。可是 在这里,由于 header 包含的是绝对定位的元素,该元素不会影响父元素高度,所以 必须明确设定这个高度。 header 的内容是极少会改动的,因此未来也不大可能出现 内容溢出 header 的情况。

其次,就是我把“两个圆角,两个方角”的样式,应用给了 header 及页面中的很多 其他元素。这种不张扬但又与众不同的效果,为页面赋予了独特的外观。

接着,给 section#title 设定了绝对定位,在确定其文本内容的大小和内边距之后, 又给它设定了足以包含这些文本的固定宽度和高度

对于这里标题的文本,我们使用了 Google Web字体 Lato。而在设定 Google Web字 体粗细的时候, font-weight 属性的值使用是数字值。这跟使用系统安装的字体不一 样,对于系统安装的字体,浏览器通常只能显示 font-weight 的 normal 和 bold 两个 值。

另外一处别出心裁的设计,就是盒子的阴影。我们的 CSS 会控制这些阴影只显示在 盒子底部,而且比盒子自身窄一些。这样,盒子就好像在页面上悬空一样。

弧形角 border-radius:10px 6px 4px 12px / 20px 12px 8px 24px; /* 4个水平值,4个垂直值 */

盒阴影 box-shadow:4px 4px 5px 8px #aaa inset; box-shadow 属性的这几值分别代表:水平偏移量、垂直偏移量、模糊量、扩展量、颜色、阴 影位于边框内部(默认位于边框外部,即 outset)。 另外,box-shadow 还支持多个阴影声明

搜索表单

<form class="search" action="#" method="post">
  <label for="user_name">search</label>
  <input type="text" id="user_name" name="user_name" placeholder="search" />
</form>

以下其实就是上一章搜索表单示例的 CSS。唯一明显不同的,就是表单在页眉中定 位的方式。

form.search {
      position: absolute;
      width: 150px;
      /*宽到足以容纳扩展后的搜索框*/
      top: 23px;
      right: 20px;
      /*相对于页眉右上角定位*/
    }

    .search input {
      float: right;
      width: 70px;
      padding: 2px 0 3px 5px;
      border-radius: 10px 0px 10px 0px;
      font-family: "Source Sans Pro", helvetica, sans-serif;
      font-weight: 400;
      font-size: 1em;
      color: #888;
      outline: none;
      /*去掉默认的轮廓线*/
      -webkit-transition: 2s width;
      /*搜索框过渡动画,别忘了带其他厂商前缀的属性*/
    }

    .search input:focus {
      width: 140px;
    }

    /*在获得焦点时扩展到这么宽*/
    .search label {
      display: none;
    }

    form.search input {
      background-color: #fff;
    }

    form.search input::-webkit-input-placeholder {
      color: #ccc;
    }

菜单

现在,页眉两端有了两个绝对定位的元素,这两个元素已经离开了常规文档流。接 下来,我必须让菜单在它们之间居中。

<nav class="menu">
        <ul>
          <li class="choice1"><a href="#">Articles</a></li>
          <li class="choice2"><a href="#">Books</a></li>
          <li class="choice3"><a href="#">Resources</a></li>
          <li class="choice4"><a href="#">Bookshelf</a></li>
          <li class="choice5"><a href="#">Contact Me</a></li>
        </ul>
</nav>

包含在 nav 元素中的仍然是普通的链接列表,但现在每个列表项都有了不同的类, 方便我们设定颜色。以下是 CSS。

nav.menu {
      margin: 19px auto;
      padding: 0;
      text-align: center;
      /*在容器内居中菜单*/
      font-size: .8em;
    }

    nav.menu>ul {
      display: inline-block;
    }

    /*收缩包紧列表项*/
    nav.menu li {
      float: left;
      /* 让菜单项水平排列*/
      list-style-type: none;
      /*去掉默认的项目符号*/
      position: relative;
      /*为子列表提供定位上下文*/
    }

    nav.menu li a {
      display: block;
      /*让链接填满列表项*/
      padding: .25em .8em;
      font-family: "Source Sans Pro", helvetica, sans-serif;
      font-style: normal;
      font-weight: 600;
      font-size: 1.2em;
      text-align: left;
      color: #fff;
      text-decoration: none;
      /*去掉链接的下划线*/
      -webkit-font-smoothing: antialiased;
      /*在 WebKit 浏览器中平滑字体*/
    }

    nav.menu li.choice1 a {
      background: #f58c21;
    }

    nav.menu li.choice2 a {
      background: #4eb8ea;
    }

    nav.menu li.choice3 a {
      background: #d6e636;
    }

    nav.menu li.choice4 a {
      background: #ee4c98;
    }

    nav.menu li.choice5 a {
      background: #f58c21;
    }

    nav.menu li:hover>a {
      color: #555;
      border-color: #fff;
      border: 0;
    }

    nav.menu li:last-child a {
      border-bottom-right-radius: 10px;
    }

    nav.menu li:first-child a {
      border-top-left-radius: 10px;
    }

页面标题和搜索表单是绝对定位,因而离开了常规文档流。换句话说, nav 元素就会 当它们不存在,而在水平方向上扩展填充父元素 header (图 7-7)。这样我就可以让 菜单在页面上居中。

居中没有宽度的元素 在一个元素内居中另一个元素有时候会很困难。对于常规、静态定位的元素,可以 让它向左或向右浮动,或者使用 text-align 属性让它在父元素内居左、居右或居中。 还可以利用自动外边距( margin:0 auto )来居中元素。这些方法的问题在于,要居 中的元素必须是有宽度的。像这里用于构成菜单的 HTML 列表,它可能是根据数据 库信息动态生成的,或者说将来有可能手工编辑,总之你不可能提前设定它的宽度。 我们来看看怎么居中一个没有设定宽度的元素。

在 display 属性的值中, inline-block 具有一些特殊的混合行为。正如它的名字所暗 示的,它既有块级元素的特点,也有行内元素的行为。从块级元素角度说,可以为 它设定外边距和内边距,也可以通过它简便而有效地包围其他块级元素。从行内元 素角度看,它会收缩包裹自己的内容,而不是扩展填充父元素。换句话说, inline-block 元素的宽度始终等于其内容宽度。这种元素还有一个特点,就是可以 包围浮动元素。不过,这种元素也有一个问题,即不能给它的外边距设定 auto 值—— 而这恰恰又是在更大的容器内居中元素的最简单方法。

解决方案就是为要居中元素的父元素(这里的 nav )应用 text-align:center ,为要 居中的元素(这里的 ul )设定 display:inline-block ,让它包含列表项。这样设定 就可以得到我们想要的结果:没有固定宽度的元素也能在其父元素内居中。如前面 代码开头加粗的 CSS 声明所示,我们就是这么做的。现在菜单完美居中了,因为其 父元素 nav 忽略了两端绝对定位的元素,扩展到了与 header 同宽。

下面,利用添加下拉菜单的机会,我来给大家介绍另一种 CSS过渡效果。

nav.menu li ul {
      opacity: 0;
      visibility: hidden;
      /* 隐藏下拉菜单*/
      position: absolute;
      /*相对于父菜单定位*/
      width: 12em;
      /*下拉菜单宽度*/
      left: 0;
      /*左边与父菜单项左边对齐*/
      top: 100%;
      /*顶边与父菜单项底边对齐*/
      -webkit-transition: 1s all;
      /*设定过渡效果*/
      -moz-transition: 1s all;
      transition: 1s all;
    }

    nav.menu li:hover>ul {
      opacity: 1;
      visibility: visible;
      /*两个属性都会产生过渡动画*/
    }

    nav.menu li li {
      float: none;
      /*去掉继承的浮动,让菜单项上下堆叠*/
    }

    nav.menu li li:first-child a {
      border-radius: 0;
    }

    nav.menu li li:last-child a {
      border-bottom-left-radius: 10px;
    }

    nav.menu li li:first-child a {
      border-radius: 0;
    }

    nav.menu li li:last-child a {
      border-bottom-left-radius: 10px;
    }

    .no-csstransitions nav.menu li ul {
      /*针对不支持过渡的浏览器*/
      visibility: visible;
      /*覆盖过渡声明*/
      opacity: 1;
      /*覆盖过渡声明*/
      display: none;
      /*如果不支持过渡,就直接隐藏菜单*/
    }

    .no-csstransitions nav.menu li:hover>ul {
      display: block;
      /*在父菜单项悬停时显示菜单*/
    }

首先,下拉菜单会继承圆角样式。但对于下拉菜单来说,我们不想像顶级菜单一样 把该样式应用到对角上,而只想应用给最后一个菜单项下面的两个角。所以,我们 覆盖了继承的左上角的圆角边框,又给左下角添加了圆角边框样式。

其次,代码注释里也提到了,我们为下拉菜单应用了不透明度过渡,让它产生淡入 效果。我一开始只使用了 opacity 属性,把它的起始值设定为 0(透明,不可见), 终止值设定为 1(不透明,完全可见)。这样确实可以在鼠标悬停时让下拉菜单淡入 淡出,但即使不可见的时候,它也会在那里。换句话说,鼠标移动到顶级菜单项下 方,甚至还没有到那一项时,其下拉菜单就会淡入。后来,我又尝试添加 display:none 和 display:block ,即在非悬停状态完全去掉下拉菜单。这倒是解决了下拉菜单“占 位”的问题,但过渡效果就没有了,下拉菜单会突然出现、消失。然后,我又放弃 display ,改为在悬停状态关掉 visibility 属性,同时过渡 opacity 。结果是下拉菜 单淡入,但会突然消失。最后,还是同时过渡 opacity 和 visibility 属性解决了问 题——菜单在透明时消失无形,淡入和淡出都正常了。

垂直居中 用 CSS 实现垂直居中也不简单。如果你想在一个固定高度的元素内垂直居中一行文本,可以把 这一行文本的 line-height 设定为该元素的高度。假设元素高度为 300 像素,可以这样写: text-align:center; /水平居中/ line-height:300px; /垂直居中:行高=容器高度/ 如果想垂直居中其他元素,比如图片,可以将容器的 display 属性设定为 table-row,再设定 (只对单元格有效的)vertical-align 属性为 middle,比如: display:table-cell; /借用表格的行为/ vertical-align:middle; /垂直居中/ text-align:center; /水平居中/

TanXinNiao commented 3 years ago

专题区

页面的专题区主要用于展示最新博客文章的前几段文字,同时右侧还有一小块区域, 显示登录表单和最近博文的一组链接。以下就是 section#feature_area 元素的HTML 标记。

<section id="feature_area">
    <article id="blog_leadoff">
      <div class="inner">
        <h4>September 7, 2012</h4>
        <a href="#">
          <h3>Managing CSS Classes with jQuery</h3>
        </a>
        <img src="images/charles_wyke-smith.jpg" alt="Charles Wyke-Smith
    photo" />
        <p>Sintus at neque in magna...</p>
      </div>
    </article>
    <aside>
      <form autocomplete="off" class="signin" action="process_form.php" method="post">
        <!-- 必要的<form>标签 -->
        <fieldset>
          <!-- 作为表单控件的容器 -->
          <!-- 控件组的标题 -->
          <legend><span>Sign In for Code and Updates</span></legend>
          <section>
            <!-- 用于为控件、标注和说明添加样式的外包装 -->
            <!-- 与控件 ID 同名的 for 属性将标注与控件关联起来 -->
            <label for="email">Email</label>
            <!-- type 属性的 text 值表明这是文本框 -->
            <input type="text" id="email" name="email" />
          </section>
          <section>
            <label for="password">Password</label>
            <input type="password" id="password" name="password" maxlength="20" /> <!-- 密码框中的字符显示为掩码 -->
            <p class="direction">Wrong user name or password</p>
          </section>
          <section>
            <!-- 提交按钮 -->
            <input type="submit" value="Sign In" />
            <p class="signup">Not signed up? <a href="#">Register now!
              </a></p>
          </section>
        </fieldset>
      </form>
      <nav>
        <h3>Recent Articles</h3>
        <!-- 博文链接 -->
      </nav>
    </aside>
  </section>

这个 section 元素与容器同宽,我们要把它包含的 article 和 aside 元素浮动为并列 显示。

section#feature_area {
      overflow: hidden;
      /*包围浮动的子元素*/
      margin: 16px 0 0;
      /*在页眉与专题区之间留出间隙*/
      padding: 0 0 10px;
    }

    section#feature_area article {
      float: left;
      width: 66%;
    }

    section#feature_area aside {
      float: right;
      width: 34%;
    }

这样就在容器里创建了两栏。注意,两栏的宽度是用百分比值设定的,这是因为这 个页面还要考虑适应不同的设备,包括平板电脑和智能手机。具体内容将在下一章 讲解。为此,两栏就用容器宽度的百分比来设定了。

此时,应该在 article 元素内部添加一个内部 div (前面 HTML标记中加粗了),以 便围绕内容设定圆角边框。之后,就是 article 区域的样式。

section#feature_area article .inner {
      /*带圆角和阴影的容器*/
      padding: 12px;
      background: #fff;
      border-radius: 20px 0;
      box-shadow: 0 12px 8px -9px #555;
    }

    section#feature_area article a {
      text-decoration: none;
    }

    /*博文标题链接*/
    section#feature_area article img {
      /*照片*/
      float: left;
      padding: 0 10px 10px 0;
    }

    section#feature_area article h4 {
      /*日期*/
      font-family: "Source Sans Pro", helvetica, sans-serif;
      font-style: normal;
      font-weight: 400;
      font-size: 1em;
      color: #f58c21;
      letter-spacing: -.025em;
    }

    section#feature_area article h3 {
      /*博文标题*/
      font-family: Lato, helvetica, sans-serif;
      font-style: normal;
      font-weight: 700;
      font-size: 1.75em;
      color: #555;
      margin: 0px 0 12px 0px;
      letter-spacing: -.05em;
    }

    section#feature_area article#blog_leadoff p {
      /*博文内容*/
      font-family: "Source Sans Pro", helvetica, sans-serif;
      font-style: normal;
      font-weight: 400;
      font-size: 1.1em;
      line-height: 1.5em;
      color: #616161;
      margin: 0 0px;
      text-align: justify;
    }

    section#feature_area article#blog_leadoff p::first-letter {
      /*首字母下沉*/
      font-family: Lato, helvetica, sans-serif;
      font-style: normal;
      font-weight: 700;
      font-size: 4.5em;
      float: left;
      margin: .05em .05em 0 0;
      line-height: 0.6;
      text-shadow: 1px 3px 3px #ccc;
      /*IE10 及以上版本支持文本阴影*/
    }

    section#feature_area article#blog_leadoff p::first-line {
      /*首行小型大写字母*/
      font-variant: small-caps;
      font-size: 1.2em;
    }

    section#feature_area aside {
      /*右栏*/
      width: 34%;
      float: right;
    }

这些样式涵盖了本书前几章介绍一些元素。值得一提的是包含 h3 的 a 元素。要是在 以前,行内元素包含块级元素可是大忌。但从 HTML5开始, a 元素可以包含任何元 素,这当然为把任何元素转换成可以点击的链接提供了方便。

照片浮动到左侧,所以文本绕排。然后我们采用第 4章讨论的首字 母下沉和首行大型小写样式,为版式添加了一点趣味性,也让字形过渡更加自然。 另外,我们还给放大的第一个字母添加了文本阴影,让它看起来像是悬浮在页面上。

文本阴影 本阴影与本章前头讲过的盒阴影很相似,它的语法如下: text-shadow:4px 4px 5px #aaa; text-shadow 这几值的含义按顺序分别是:水平偏移量、垂直偏移量、模糊量和颜色。与盒阴 影不同的是,文本阴影没有扩展量。最低限度,你得提供水平偏移量、垂直偏移量和颜色值。 如果水平和垂直偏移量是负值,阴影就会出现在文本左上方。另外,text-shadow 还支持多个 阴影声明。

登录表单

登录表单的标记与第 6 章介绍的表单采用相同的结构方式,以下是其 HTML。

<form autocomplete="off" class="signin" action="process_form.php" method="post">
        <!-- 必要的<form>标签 -->
        <fieldset>
          <!-- 作为表单控件的容器 -->
          <!-- 控件组的标题 -->
          <legend><span>Sign In for Code and Updates</span></legend>
          <section>
            <!-- 用于为控件、标注和说明添加样式的外包装 -->
            <!-- 与控件 ID 同名的 for 属性将标注与控件关联起来 -->
            <label for="email">Email</label>
            <!-- type 属性的 text 值表明这是文本框 -->
            <input type="text" id="email" name="email" />
          </section>
          <section>
            <label for="password">Password</label>
            <input type="password" id="password" name="password" maxlength="20" /> <!-- 密码框中的字符显示为掩码 -->
            <p class="direction">Wrong user name or password</p>
          </section>
          <section>
            <!-- 提交按钮 -->
            <input type="submit" value="Sign In" />
            <p class="signup">Not signed up? <a href="#">Register now!
              </a></p>
          </section>
        </fieldset>
      </form>

下面是我从第 6章表单的 CSS中拿来的规则,并针对这个表单修改后的代码

form.signin {
      width: 19em;
      /*表单的整体宽度*/
      float: right;
      background: #fff;
      border-radius: 10px 0 10px 0;
      box-shadow: 0 12px 8px -9px #555;
    }

    .signin fieldset {
      border: 0;
      margin: 10px 14px;
    }

    /*去掉默认的边框*/
    .signin legend span {
      font-family: Lato, helvetica, sans-serif;
      font-weight: 700;
      font-size: 1.3em;
      line-height: 1.1em;
      color: #4eb8ea;
      letter-spacing: -.05em;
    }

    .signin section {
      overflow: hidden;
      /*包围控件和标注*/
      padding: .25em 0;
      /*表单元素的间距*/
    }

    .signin section label {
      font-family: "Source Sans Pro", helvetica, sans-serif;
      font-weight: 400;
      float: left;
      width: 5em;
      /*标注栏的宽度*/
      margin: .5em .3em 0 0;
      /*外边距保持文本与控件的间距*/
      line-height: 1.1;
      color: #555;
    }

    .signin section input {
      float: right;
      width: 10.5em;
      /*控件栏的宽度*/
      margin: .2em 0 0 .5em;
      padding: 3px 10px 2px;
      /*输入文本与控件的间距*/
      color: #555;
      font-size: .8em;
      outline: none;
      /*去掉默认的轮廓线*/
      border-radius: 10px 0 10px 0;
    }

    input:-webkit-autofill {
      color: #fff !important;
    }

    /*去掉 WebKit 默认的黄色背景*/
    .signin section input[type=submit] {
      float: right;
      /*将按钮与控件右边对齐*/
      width: auto;
      /*重设按钮宽度*/
      margin: 0 2px 3px 0;
      padding: 0px 8px 3px;
      font-size: 1em;
      font-weight: 800;
      color: #fff;
      border: none;
      background-color: #d6e636;
      box-shadow: 1px 1px 2px #888;
    }

    .signin section p {
      /*内容为"not signed up?"*/
      float: right;
      clear: both;
      margin: .2em 0 0;
      text-align: right;
      font-size: .8em;
      line-height: 1;
      color: #555;
    }

    .signin section p a {
      color: #333;
    }

    /*到注册表单的链接*/
    .signin section p a:hover {
      color: #777;
      text-decoration: none;
    }

    .signin section p.direction.error {
      /*错误消息*/
      display: block;
      color: #f00;
      /*添加 error 类后,把说明文字变成红色*/
    }

    .signin section p.direction {
      display: none;
    }

    /*隐藏错误消息*/

无论多简单,表单所需的代码总是很多!好在,这里的代码大部分都很直观,配合 注释看基本都能理解。我想提一下错误消息,它一开始是隐藏的,只有必要时才会 显示。要显示错误消息,只要给(已经有了 direction 类的) p 元 素再添加一个 error 类即可。不过,这个类是要通过验证表单的代码来添加的。作 为负责网站 UI的人,添加这种平时隐藏的 HTML 元素和显示它的 CSS是你的事儿。 至于什么时候添加 error 类显示错误消息,那就是开发团队的事儿了。

博文链接

表单下面是博文链接。与以往一样,我使用了无序列表来组织链接。

<nav>
  <h3>Recent Articles</h3>
  <ul>
    <li><a href="#">Z-index&mdash;Layers of Confusion</a></li>
    <li><a href="#">Box-Image Techniques</a></li>
    <li><a href="#">Shadow FX with CSS3</a></li>
  </ul>
</nav>

CSS如下

section#feature_area nav {
      width: 19em;
      /*容器整体宽度*/
      float: right;
      /*与区域右边对齐*/
      margin: 15px 0 0;
      /*上方间距*/
      padding: .6em 0em .75em;
      /*链接上下的间距*/
      background: #fff;
      border-radius: 10px 0 10px 0;
      box-shadow: 0 12px 8px -9px #555;
    }

    #feature_area nav h3 {
      padding: 0 14px 0;
      /*标题左右的空间*/
      font-family: Lato, helvetica, sans-serif;
      font-weight: 700;
      font-size: 1.3em;
      text-align: left;
      color: #aaa;
      letter-spacing: -.05em;
    }

    #feature_area nav ul {
      margin: 0em 0 0 20px;
    }

    #feature_area nav li {
      padding: .7em 0 0 2em;
      position: relative;
      /*项目符号的定位上下文*/
      list-style-type: none
    }

    #feature_area nav li:before {
      /*定制项目符号*/
      content: "";
      /*用空字符串,因为不需要实际内容*/
      position: absolute;
      /*相对于列表项定位*/
      height: 10px;
      /*项目符号大小*/
      width: 10px;
      left: 12px;
      /*定位项目符号*/
      top: 12px;
      border-radius: 5px 0 5px 0;
      /*项目符号形状*/
      background-color: #d6e636;
      /*项目符号颜色*/
      box-shadow: 1px 1px 2px #888;
    }

    #feature_area nav li a {
      display: block;
      /*链接与列表项同宽*/
      text-decoration: none;
      /*去掉默认的下划线*/
      font-size: .9em;
      color: #616161;
    }

    #feature_area nav li a:hover {
      color: #000;
    }

添加了样式之后的链接区就在登录表单正下方。它们都是 aside 元素的子元素,而 aside 元素通过浮动与 article 元素并列在一行。 与浮动 form 元素一样,浮动 nav 元素可以让它直接定位在表单下方。列表的其他部 分没有什么特别,但为了体现“两个圆角,两个方角”的设计风格,我们要重新定 制项目符号。为此,我们抛弃用图片作为列表项记号的常规做法,使用 ::before 创 建了 10像素见方的伪元素,并将其两角变成圆角。而一个像素的小阴影则让这些项 目符号产生了跳脱页面的假象。

TanXinNiao commented 3 years ago

图书区

接下来,有四本图书封面的展示区位于页面底部。为了给这一部分增添趣味性,我 们要使用弹出层和旋转文本。先看 HTML标记。

<section id="book_area">
    <article class="left">
      <div class="inner">
        <h3>HTML5 + CSS3</h3><!-- 要旋转的文字 -->
        <img src="images/stylin_cover.png" alt="Stylin' with CSS cover" />
        <aside>
          <!-- 弹出层 -->
          <ol>
            <li><a href="#">Download the Code</a></li>
            <li><a href="#">Table of Contents</a></li>
            <li><a href="#">Buy this Book</a></li>
          </ol>
        </aside>
      </div>
    </article>
    <!-- 另外三本图书的标记也一样 -->
  </section>

怎么样,HTML 代码极其简单,同样的标记重复四次,就是四本书。下面来看看相 关的 CSS吧,先看看布局和旋转文本的样式,然后再看弹出层的样式。

section#book_area {
      /*与布局同宽*/
      clear: both;
      border-radius: 20px 0px 20px 0px;
      border: 1px solid #f58c21;
      margin: 8px 0 16px;
      /*上下间距*/
      overflow: hidden;
    }

    #book_area article {
      /*四本书四栏*/
      float: left;
      width: 25%;
      padding: 10px 0;
      background: none;
    }

    #book_area article .inner {
      /*封面外包装*/
      position: relative;
      /*为弹出层提供定位上下文*/
      width: 140px;
      /*包装每一本书*/
      margin: 0 auto;
      /*在各自 article 元素内居中每一本书*/
    }

    #book_area .inner h3 {
      /*旋转文字*/
      position: absolute;
      width: 160px;
      left: 112%;
      bottom: 5px;
      /*把文字定位在图书右侧*/
      transform: rotate(-90deg);
      /*旋转文字需要使用带厂商前缀的属性*/
      transform-origin: left bottom;
      /*设定旋转中心点,需要带厂商前缀的属性*/
      color: #ccc;
      font-size: 1.4em;
      font-family: Lato, helvetica, sans-serif;
      font-style: normal;
      font-weight: 900;
      text-align: left;
    }

    /*较窄的封面需要不同的偏移量*/
    #book_area article.right:last-child h3 {
      left: 85%;
    }

    #book_area article img {
      box-shadow: 0 12px 8px -9px #555;
    }

    /*封面阴影*/

在与布局同宽的 section#book_area 元素中,我们浮动了四个 article 元素,每个元 素的宽度都设定为 25%。在这四个 article 中,分别使用一个有宽度的内部 div 来包 含图书封面。这样就可以为图书封面之间添加适当的间距,如图 7-14 所示。接下来 要做成弹出层的 aside 元素目前还处于隐藏状态。

旋转文字是用 CSS3 的 transform 属性的两个函数实现的。第一个函数是 transform-origin ,用于把旋转变换的原点设定为 h3 元素盒子的左下角。这里的原 点指的是旋转的中心点,就好像我在那个地方插进去一根大头针一样。然后用 transform 的 rotate 函数把 h3 元素旋转 90度,最后再将它们向上移动 5像素。

CSS3 变换 如果你用过 Adobe Illustrator 或 Fireworks 等平面图形设计软件,可能知道对文本和其他元素进行旋 转、缩放和斜切变换。现在,通过 CSS3 变换在浏览器中也能实现同样的效果了(如图 7-15 所示)。 CSS3 为变换规定了两个属性:transform 和 transform-origin。先说说 transform。 transform 属性能够调用函数,调用不同的变换函数可以实现不同形式的变换,而通过传入的 参数值可以控制变换的结果。通过 transform 属性调用变换函数的语法如下: transform:函数名(数值或 x、y 值); 以下是 CSS3 规定的变换函数。  scale:用于放大或缩小元素(指定大于 1 的值放大元素,小于 1 的值缩小元素),如 transform: scale(1.5)。  rotate:根据指定的度数旋转元素(正值顺时针旋转,负值逆时针旋转),如 transform: rotate(-30deg)。  skew:让元素在 x 轴和 y 轴方向倾斜(只指定一个值,y 轴不受影响),如 transform: skew(5deg, 50deg)。  translate:根据指定的距离沿 x 轴和 y 轴平移对象(很像相对定位,因为对象初始占据的 空间会保留),如 transform:translate(-50px, 20px)。 transform-origin 属性设定元素围绕其变换的原点。默认情况下,这个点是元素垂直和水平 方向的中心点。因此,如果你旋转元素而未另行指定原点,就会像在元素中心点插进一根大头 针一样,然后元素围绕该点旋转。可以使用 transform-origin 属性及位置关键字(left、 center、right、top 和 bottom 等)另行设定原点,而使用正、负数字甚至可以把原点设定到 元素边界之外。

现在该为每本书添加弹出层了。以第 6章那个弹出层示例为基础,还要进行两点改进。 首先,让页面右侧图书的弹出层显示在封面图片左侧,以免出现在右侧被浏览器窗口 “切掉”;其次,把箭头图形放在弹出层一边,让人感觉它也是弹出层边框的一部分。 经验告诉我们,像这种看似不起眼但却很有意思的改进,往往要编写很多代码。

如果你现在看看前面的标记,会发现我已经给包含图书的 article 元素分别添加了 left 和 right 类,以便分别设定出现在封面右侧和左侧的弹出层和箭头。

#book_area article aside {
      /*弹出层共享样式开始*/
      display: none;
      /*隐藏弹出层*/
      position: absolute;
      /*相对于包含图片的内部 div*/
      z-index: 2;
      width: 200px;
      /*弹出层宽度*/
      background: #fff;
      padding: 10px 2px 5px;
      /*弹出层内容边距*/
      border: 2px solid #f58c21;
      border-radius: 10px 0px 10px 0px;
      box-shadow: 4px 4px 16px #555;
      color: #555;
      font-family: "Source Sans Pro", helvetica, sans-serif;
      font-size: .8em;
      line-height: 1.5em;
    }

    #book_area article:hover aside {
      display: block;
    }

    /*鼠标悬停于封面时显示弹出层*/
    #book_area article aside li {
      padding: .25em 0 .75em 1em;
      /*列表项的垂直间距和左边距*/
      list-style-type: none;
      /*去掉默认的项目符号*/
      line-height: 1.2em;
    }

    #book_area article aside li a {
      /*链接文本*/
      text-decoration: none;
      font-size: 1.2em;
      color: #616161;
    }

    #book_area article aside li a:hover {
      /*悬停时突显链接*/
      color: #333;
    }

    /*弹出层共享样式结束*/
    #book_area article.left aside {
      /*左侧两本书*/
      left: 84%;
      top: 14px;
      /* 把弹出层定位在图片右侧*/
    }

    #book_area article.right aside {
      /*右侧两本书*/
      right: 84%;
      top: 14px;
      /*把弹出层定位在图片左侧*/
    }

    #book_area article aside:after {
      /*橙色三角形*/
      content: "";
      /*需要有内容,这里是一个空字符串*/
      position: absolute;
      /*相对于弹出层定位*/
      top: 33px;
      border: 12px solid;
      height: 0px;
      width: 0px;
      /*收缩边框创造三角形*/
    }

    #book_area article.left aside:after {
      /*左侧图书弹出层的三角形定位及颜色*/
      right: 100%;
      border-color: transparent #f58c21 transparent transparent;
    }

    #book_area article.right aside:after {
      /*右侧图书弹出层的三角形定位及颜色*/
      left: 100%;
      border-color: transparent transparent transparent #f58c21;
    }

    #book_area article aside:before {
      /*白色三角形*/
      content: "";
      /*需要有内容,这里是一个空字符串*/
      position: absolute;
      /*相对于弹出层定位*/
      border: 8px solid;
      height: 0px;
      width: 0px;
      /*收缩边框创造三角形*/
      z-index: 100;
      /*保证白色三角形在最前面*/
      top: 37px;
    }

    #book_area article.left aside:before {
      /*左侧图书白色三角形的样式、位置和颜色*/
      right: 100%;
      border-color: transparent white transparent transparent;
    }

    #book_area article.right aside:before {
      /*右侧图书白色三角形的样式、位置和颜色*/
      left: 100%;
      border-color: transparent transparent transparent white;
    }

弹出层是一个绝对定位的元素,它相对于包含每本书的内部 div 定位。在第 6 章那 个弹出层的例子中,我们只把红色三角形定位在弹出层的一边(参见图 6-24)。而在 这个例子中,我们大幅度地改进了这个效果,弹出层似乎是把边框给向外挤出了一 个尖尖的指针,如图 7-16 所示。这个效果是通过在橙色三角形上面叠加另外一个更 小的白色(与弹出层背景色相同)的三角形,并将它们垂直的边对齐实现的。这样 就用橙色三角形创造了边框的效果。

添加白色三角形使用的是 ::before 伪元素,添加橙色三角形使用的是 ::after 伪元 素,而绝对定位和 z-index 属性则将它们在弹出层边框上精确地对齐。这个结果非常 自然,弹出层及其指针浑然一体。

这个例子中容易搞混的地方是记住哪个弹出层在左,哪个弹出层在右。比如,左侧 两本书的弹出层位于它们封面的右侧,而这两个弹出层的指针三角形则位于弹出层 左侧。右侧两本书的情况恰好相反。

通过这个例子,我们又重温了前面提到的自上而下的方法。前面代码中的注释已经 明确告诉你了,首先是所有弹出层共享的样式,包括大小、内边距、边框、颜色和 内容等样式。其次是把前两本书的弹出层定位在图片右侧的规则,以及把后两本书 的弹出层定位在图片左侧的规则。随后是所有图书弹出层指针三角形共享的样式。 再接着是左侧两本书弹出层三角形的样式,以及右侧两本书弹出层三角形的样式。

TanXinNiao commented 3 years ago

页脚

页脚非常适合放一些声明之类的信息,比如是谁创建了这个网站,以及一些业务相 关的链接,比如免责声明、服务条款、联系信息、隐私政策和版权声明等。下面是 页脚的 HTML 标记。

 <footer>
    <p>A CSS template from <a href="http://www.stylinwithcss.com"><em>Stylin'
          with CSS, Third Edition</em></a> by Charles Wyke-Smith</p>
    <nav>
      <ul>
        <li><a href="#">Privacy Policy</a></li>
        <li><a href="#">Contact Charles</a></li>
      </ul>
    </nav>
  </footer>

下面是它的 CSS

footer {
      padding: .5em 0 .35em 0;
      /*内容上下的间距*/
      text-align: center;
      /*居中内容*/
      border-radius: 10px 0px 10px 0px;
      background: #fff;
      box-shadow: 0 12px 8px -9px #555;
    }

    footer p {
      /*文本行的样式*/
      font-family: 'Source Sans Pro';
      font-weight: 400;
      font-size: .85em;
      letter-spacing: -.05em;
      color: #555;
    }

    footer p a {
      /*文本行中的链接*/
      font-family: 'Source Sans Pro';
      font-style: italic;
      font-weight: 700;
      font-size: 1em;
      color: #4eb8ea;
      text-decoration: none;
    }

    footer p a:hover {
      color: #777;
    }

    footer ul {
      /*链接列表*/
      display: inline-block;
      /*收缩包围列表*/
      margin: 4px 0 0;
    }

    footer li {
      list-style-type: none;
      /*去掉默认的项目符号*/
      float: left;
      /*让列表项水平排列*/
      font-family: "Source Sans Pro";
      font-weight: 400;
      font-size: .85em;
    }

    footer li+li a {
      border-left: 1px solid #ccc;
      /*链接分隔线*/
    }

    footer li a {
      text-decoration: none;
      /*去掉链接默认的下划线*/
      color: #aaa;
      padding: 0 5px;
      /*链接间距*/
    }

    footer a:hover {
      color: #777;
    }

内容通过 text-align:center 居中对齐,段落及其文本都继承了这一设定,在 footer 内居中。这个声明正常情况 下不会让链接列表居中,因为列表项由块级元素构成,默认会与容器同宽。不过, 我给 ul 设定了 display:inline-block ,让它收缩包围 li 元素。这样实际上就相当于 为 ul 指定了宽度,因此 text-align:center 对它也会起作用。记性好的读者应该知 道,在前面介绍菜单的时候,我们解释了应用 display:inline-block 之后,元素宽 度仍然是可变的。换句话说,即使将来再向这个列表中添加链接,或者从中删除链 接,列表仍然会居中。最后,再提醒你一下,对列表应用自动外边距(而不对 footer 应用 text-align:center ),同样能让它在页脚内居中。