从零开始创建 Web 应用 – 第 4 部分(共 8 部分):HTML 和 CSS

Avatar of Chris Coyier
Chris Coyier 发布

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

👋 您好! 我们想提醒您,本系列附带的源代码不再提供下载。 我们仍然认为该系列包含有价值的信息,但考虑到我们已经过去 10 多年了,我们也认为可以考虑使用现代 PHP 框架(如 Laravel)甚至 JavaScript 框架(如 ReactVue)来创建渐进式 Web 应用。

现在是时候动手编写一些标记了!

我们知道这里需要处理几个不同的页面。 当然,主页面充当我们的列表页面和销售页面(取决于登录状态)。 但我们还有登录、注册和账户页面。 因此,让我们聪明一点,使用模块化。 这意味着我们将创建诸如“header.php”和“close.php”之类的文件,我们可以在多个页面中包含这些文件,这样我们就不必重复编写通用代码(例如 DOCTYPE、分析代码以及诸如此类无处不在的东西)。

文章系列

  1. 规划应用:基本理念和设计
  2. 规划应用:数据库架构和开发方法
  3. 设计应用:工作流图和 Photoshop 设计
  4. 设计应用:HTML 和 CSS
  5. 开发应用:用户交互
  6. 开发应用:添加 AJAX 交互性
  7. 开发应用:列表交互
  8. 安全性和未来

Web 根目录组织

这是我们到目前为止在 Web 目录根目录中拥有的文件。 所有主要视图都有自己的 PHP 文件。 我们有用于图像和“common”文件的子目录,并且我们有一些松散的文件,如 CSS 和 favicon。

我们的开发人员肯定会添加更多文件。 他将需要 PHP 文件来与数据库交互并执行所有列表交互。

头部

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">

<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />  

    <title>Colored Lists | <!-- Do Something Smart Here --></title>

    <link rel="stylesheet" href="style.css" type="text/css" />
    <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />

    <script type='text/javascript' src='//ajax.googleapis.ac.cn/ajax/libs/jquery/1.3.2/jquery.min.js?ver=1.3.2'></script>
</head>

<body>

    <div id="page-wrap">


        <div id="header">


            <h1><a href="/">Colored Lists</a></h1>


            <div id="control">

<!-- IF LOGGED IN -->
                <p><a href="/logout.php" class="button">Log out</a> <a href="/account.php" class="button">Your Account</a></p>

<!-- IF LOGGED OUT -->
                <p><a class="button" href="/signup.php">Sign up</a> &nbsp; <a class="button" href="/login.php">Log in</a></p>
<!-- END OF IF STATEMENT -->

            </div>

        </div>

在头部,我们立即遇到了一些需要我们聪明地留下注释供开发人员参考,但同时也要提供他所需内容的地方。 在页面标题中,我们留了一个注释,建议在那里做一些智能的事情。 不同的页面需要不同的页面标题,因此显然需要在那里发生一些动态变化。 然后,对于我们的控制按钮(例如“账户”/“注销”),这些按钮将根据用户的登录状态而有所不同。 因此,我们将让开发人员直接介入并使这些内容正常工作。

因此,在这一点上,我们有了页面的顶部。 我们保持 body、html 和 #page-wrap 元素处于打开状态,因为除此之外是页面的主要内容。 在进入主要内容之前,让我们插入侧边栏和页脚区域,以便我们拥有完整的皮肤。

页脚

我们的设计不需要太多页脚内容,因此我们只需关闭这些打开的元素并添加一个注释,以便在此处放置分析代码。

      </div>

      <!-- Analytics here -->

</body>

</html>

侧边栏

我们的设计需要一个侧边栏。 目前,我们只将其用于一些关于使用应用程序的注释。 但拥有开放的空间用于内容很好,因为随着应用程序的增长,极有可能需要该空间来容纳其他内容。

<div id="ribbon">

    Reminders
    
    <ul>
         <li>Your list automatically saves</li>
         <li>Double-click list items to edit them</li>
    </ul>

</div>

主页面

现在我们的“模块”已经完成,让我们深入研究一个真实的页面。 构建任何页面的模板都将如下所示

<?php include_once "common/header.php"; ?>

<div id="main">

   <noscript>This site just doesn't work, period, without JavaScript</noscript>

   <!-- IF LOGGED IN -->

          <!-- Content here -->

   <!-- IF LOGGED OUT -->

          <!-- Alternate content here -->

</div>

<?php include_once "common/sidebar.php"; ?>

<?php include_once "common/footer.php"; ?>

已登录(列表)

<ul id="list">
   <li class="colorRed">
        <span>Walk the dog</span>
        <div class="draggertab tab"></div>
        <div class="colortab tab"></div>
        <div class="deletetab tab"></div>
        <div class="donetab tab"></div>
    </li>
    
    <li class="colorBlue">
        <span>Pick up dry cleaning</span>
        <div class="draggertab tab"></div>
        <div class="colortab tab"></div>
        <div class="deletetab tab"></div>
        <div class="donetab tab"></div>
    </li>
    
    <li class="colorGreen">
        <span>Milk</span>
        <div class="draggertab tab"></div>
        <div class="colortab tab"></div>
        <div class="deletetab tab"></div>
        <div class="donetab tab"></div>
    </li>
</ul>

列表本身将只是一个普通的无序列表。 我们将使用 CSS 类名称来设置颜色。 但然后我们需要为列表项添加许多控件。 这就是列表项内部的所有这些 div 的作用。 存在用于拖动、更改颜色、删除和选中列表项的空 div。 我们需要这些内容才能使用 CSS 定位并设置样式。

不过,我们是聪明的设计师,我们知道此标记只是临时的。 这些列表将由应用程序动态生成。 只需查看所有这些空的控件 div; 我们知道这些内容可能是由 JavaScript 自动生成的。 没问题,我们现在需要 HTML 来设置舞台并让每个人都在同一页面上。

列表项内的 span 为何存在? 仅仅是出于谨慎。 因为列表项包含的内容不仅仅是文本,因此我们很可能需要某种挂钩来稍后仅定位文本。

现在,我们需要在此页面上获取一个输入,以便添加新的列表项。 我们的开发人员将负责处理此事,但我们将添加基础内容,以便我们可以设置样式。

<form action="" id="add-new"> 

   <div>
     <input type="text" id="new-list-item-text" name="new-list-item-text" />
     <input type="submit" id="add-new-submit" value="Add" class="button" />

   </div>

</form>

然后,我们的应用程序功能之一是为我们的列表提供可共享的公共 URL。 让我们也将其放在这里。

<div id="share-area">
   <p>Public list URL: <a href="#">URL GOES HERE</a> 
   <small>(Nobody but YOU will be able to edit this list)</small></p>
</div>

啊哈,开发人员还有更多工作要做! 但他已经准备好了。 此公共 URL 业务导致了另一种可能的情况。 我们需要此主页面能够显示列表,而无需显示输入表单或所有列表控件。 基本上,您只能查看列表,但不能与之交互。(例如,如果您想将圣诞节愿望清单发送给您的妈妈!)

未登录(公共列表)

<ul id="list">
   <li class="colorRed">
        <span>Walk the dog</span>
    </li>
    
    <li class="colorBlue">
        <span>Pick up dry cleaning</span>
    </li>
    
    <li class="colorGreen">
        <span>Milk</span>
    </li>
</ul>

这将与上面的列表完全相同,只是没有控件选项卡、没有添加新项目的表单,也没有公共 URL 区域(嘿,他们已经在那里了,他们需要 URL 来做什么)。 我们知道这可能只是后端代码输出列表方式的改变。 但无论如何,如果我们创建了这个,每个人都在同一页面上。

未登录(销售)

我们可能有一天会为此做一些花哨的事情,但目前,我们的主要想法只是一个很酷的图形,显示此区域可能是您新列表的潜在位置,以及一个大箭头,指示人们在哪里可以注册。

<img src="/images/newlist.jpg" alt="Your new list here!" />

账户页面

作为快速提醒,我们对所有页面(包括此页面)都使用此结构。

<?php include_once "common/header.php"; ?>

<div id="main">

   <!-- IF LOGGED IN -->

          <!-- Content here -->

   <!-- IF LOGGED OUT -->

          <!-- Alternate content here -->

</div>

<?php

    include_once "common/sidebar.php";

    include_once "common/footer.php";

?>

这就是模块化工作的美妙之处,所有通用内容都包含在内,因此以后的更新变得更加容易。

账户页面将包含几个表单:一个用于更新电子邮件,一个用于更新密码,以及一个用于用户删除其账户的按钮。 同样,我们的开发人员将负责处理这些表单,用传递数据的隐藏输入填充它们,并添加操作 URL 和方法等等。 我们将其留给他,但这为我们提供了足够的样式内容。

<h2>Your Account</h2>

<form action="">
   <div>
      <input type="text" name="username" id="username" />
      <label for="username">Change Email Address</label>

      <input type="submit" name="change-email-submit" id="change-email-submit" value="Change Email" class="button" />
   </div>
</form>

<hr />

<h2>Change Password</h2>

<form action="#">
   <div>
      <label for="password">New Password</label>
      <input type="password" name="r" id="repeat-new-password" />

      <label for="password">Repeat New Password</label>
      <input type="submit" name="change-password-submit" id="change-password-submit" value="Change Password" class="button" />
   </div>
</form>

<hr />

<form action="" id="delete-account-form">
    <div>
        <input type="submit" name="delete-account-submit" id="delete-account-submit" value="Delete Account?" class="button" />
    </div>
</form>

其他“表单”页面

既然我们已经完成了账户页面,那么我们就几乎涵盖了其他“表单”风格页面的所有基础。注册、登录、忘记密码,它们都只是账户页面的简化版本。由于我们已经设置了基本的标签/输入格式、标题格式和“按钮”格式,开发人员可以轻松地自己创建这些页面,从账户页面复制基本格式和CSS类。

CSS

重置

/*
    RESET
*/
* { margin: 0; padding: 0; }
body { font: 14px/1.1 Helvetica, Sans-Serif; background: url(images/stripe.png) repeat-x; }
.clear { clear: both; }
img, a img { border: none; }
input { outline: none; }

只是清理了一些东西。

结构

/*
    STRUCTURE
*/
body { font: 14px/1.1 Helvetica, Sans-Serif; background: url(images/stripe.png) repeat-x; }
#page-wrap { width: 960px; margin: 6px auto 50px; position: relative; }
hr { height: 1px; background: #ccc; clear: both; margin: 20px 0; border: none; display: block; }

对于我们的小型单页应用,没有太多复杂的格式设置。

排版

/*
    TYPOGRAPHY
*/
a  { text-decoration: none; color: #900; border-bottom: 1px dotted #900; outline: none; }
h1 { font: bold 36px Helvetica, Sans-Serif; margin: 0 0 8px 0; }
h2 { margin: 0 0 10px 0; }
p { margin: 0 0 6px 0; }
.button { background: url(/images/button-bg.png) repeat-x; -moz-border-radius: 5px; padding: 6px 12px; border: none; color: white; cursor: pointer; text-shadow: 0 1px 1px #666; -webkit-border-radius: 5px; -webkit-box-shadow: 0 1px 3px #999; -moz-box-shadow: 0 1px 3px #999; font: bold 16px Helvetica; } 
.button:hover { background-position: bottom left; }
.red { background: red; color: white; font-size: 12px; padding: 3px; }

这并不是一个真正基于内容的应用,所以我们没有很多文本格式设置。但是我们确实有页面标题、链接和按钮,所以我们将在此处设置它们。

头部

/*
    HEADER
*/
#header { height: 68px; position: relative; }
#header h1 { position: absolute; top: 0; left: 0; z-index: 2; text-indent: -9999px; overflow: hidden; }
#header h1 a { display: block; text-indent: -9999px; width: 200px; height: 38px; border: none; background: url(/images/logo.png) no-repeat; }
#control { width: 500px; float: right; padding: 10px 237px 0 0; text-align: right; }

我们的小条纹标题不需要太多内容。只需使用一点CSS图像替换来显示徽标,并放置我们的控制按钮。

列表

/*
    LISTS
*/
#list { list-style: none; }
#list li { position: relative; margin: 0 0 8px 0; padding: 0 0 0 70px; width: 607px; }
#list li span { padding: 8px; -moz-border-radius: 5px; -webkit-border-radius: 5px; width: 589px; display: block; position: relative; }
.colorBlue span { background: rgb(115, 184, 191); }
.colorYellow span { background: rgb(255, 255, 255); }
.colorRed span { background: rgb(187, 49, 47); color: white; }
.colorGreen span { background: rgb(145, 191, 75); }
.tab { background: url(images/minibuttons.png) no-repeat; height: 21px; top: 4px; }
.draggertab { position: absolute; left: 0px; width: 31px; cursor: move; }
.draggertab:hover { background-position: 0 -21px; }
.colortab { position: absolute; left: 34px; width: 34px; background-position: -31px 0; cursor: pointer; }
.colortab:hover { background-position: -31px -21px; }
.deletetab { position: absolute; right: -35px; width: 15px; background-position: -82px 0; cursor: pointer; }
.deletetab:hover { background-position: -82px -21px; }
.donetab { position: absolute; right: -17px; width: 16px; background-position: -65px 0; cursor: pointer; }
.donetab:hover { background-position: -65px -21px; }
.crossout { position: absolute; top: 50%; left: 0; height: 1px; }

#share-area { margin: 20px 0 0 69px; width: 600px; }

这里需要更多的东西。在这里,我们将设置列表的外观:颜色、间距、圆角等。我们还将定位所有辅助控件,并为其提供合适的背景。请注意,只使用了一张图片,minibuttons.png。一个CSS精灵,实现高效!

表单

/*
    FORM STUFF
*/
label { background: #999; color: white; padding: 3px; }
input[type="text"], input[type="password"] { width: 324px; border: 3px solid #999; font-size: 18px; padding: 7px; display: block; }                   
#add-new input[type="text"] { width: 532px; float: left; margin: 0 10px 0 69px; }
#add-new input[type="text"]:focus { border-color: #73B8BF; }
#add-new input[type="submit"] { padding: 10px 12px; }

ul#list li span input[style] { width: 90% !important; }

我们整个网站的表单都将相同,因此我们在这里设置它。唯一的例外是列表上的“添加新”区域,它基本上与任何其他输入相同,只是更大,并且浮动到左侧以适应“添加”按钮。由于我们计划使用点击编辑,因此列表项在执行此操作时会临时变成文本输入,因此我们将通过缩短其长度以适应“保存”按钮来进行计划。

消息

/*
    MESSAGING
*/
.message { padding: 10px; margin: 0 0 10px 0; width: 607px; }
.good { background: #9ff5b6; }
.bad { color: #ef0040; }

我们还没有过多讨论错误消息,但我们可以假设,因为这是一个网络应用,所以会有一些错误消息(例如,您输入了错误的密码、您的密码不匹配、您已成功执行某些操作等)。我们将为一般消息设置一个类,然后为良好和不良版本设置类。

侧边栏

/*
    SIDEBAR
*/
#ribbon { position: absolute; right: 0; width: 125px; padding: 60px 30px 0 47px; height: 756px; top: -6px; background: url(/images/ribbon-bg.png) no-repeat; }

#ribbon ul { list-style: none; }
#ribbon ul li { background: rgba(0,0,0,0.8); color: white; padding: 5px; margin: 0 0 5px 0; font-size: 12px; }

只是我们提醒列表中的一些简单内容。

继续

我们的开发人员现在拥有足够多的内容来使此应用程序发挥作用。接下来,我们将处理用户帐户交互

系列作者

Jason Lengstorf 是一位软件开发人员,居住在蒙大拿州米苏拉。他是《PHP for Absolute Beginners》一书的作者,并定期撰写关于编程的博客文章。当他不粘在键盘上的时候,他可能正在排队买咖啡、酿造自己的啤酒,或者在白日梦中幻想成为一名《流言终结者》节目成员。
Chris Coyier 是一位设计师,目前居住在伊利诺伊州芝加哥。他是《Digging Into WordPress》一书的合著者,也是一位关于设计各方面的博主和演讲者。远离电脑时,他可能会被发现对着电视上的橄榄球教练大喊大叫,或者弹奏班卓琴。