综合示例

项目简介

为世界著名的乐队Jay Skript and the Domsters设计一个网站。

原始资料

有关乐队的介绍材料、巡演日程,以及一些照片。

站点结构

站点文件夹目录结构:

  • /images

  • /styles

  • /scripts

要创建的页面:

  • /Home

  • /About

  • /Photos

  • /Live

  • /Contact

对应如下文件:

  • index.html

  • about.html

  • photos.html

  • live.html

  • contact.html

页面结构

站点每个页面分成几个区域:

  • 头部区域包含站点的品牌性信息,也是放logo的地方。这个区域要使用<header>元素。

  • 导航区域包含一组链接,指向各个页面。这个区域使用<nav>元素。

  • 内容区域包含每一页的实质性内容,这个区域使用<article>元素。

模板代码:

<!DOCTYPE html>
<html lang="en">
<head>
        <meta charset="UTF-8">
        <title>Jay Skript and the Domsters</title>
</head>
<body>
		<header>
		        <nav>
		                <ul>
		                        <li><a href="index.html">Home</a></li>
		                        <li><a href="about.html">About</a></li>
		                        <li><a href="photos.html">Photos</a></li>
		                        <li><a href="live.html">Live</a></li>
		                        <li><a href="contact.html">Contact</a></li>
		                </ul>
		        </nav>
		</header>
		<article>
		</article>
</body>
</html> 

设计

外观设计

CSS

建议把所有CSS分别放在几个文件:

  • layout.css 整体布局

  • color.css 颜色

  • typography.css 版式

这些样式表都可以导入到一个基本的样式表中:

@import url(layout.css);
@import url(color.css);
@import url(typography.css);

把包含这三行代码的文件保存为basic.css,并放在styles文件夹中。如果想添加一个新样式表或者删除一个样式,只要编辑basic.css即可。在模板的<head>元素中通过<link>元素引入这个基本样式表,然后在页面<header>中添加一个<img>标签,指向logo图片。也可以向<article>中添加一些临时性填充文本:

<!DOCTYPE html>
<html lang="en">
<head>
        <meta charset="UTF-8">
        <title>Jay Skript and the Domsters</title>
		<link rel="stylesheet" href="styles/basic.css" media="screen" />
</head>
<body>
		<header>
				<img src="images/logo.gif" alt="Jay Skript and the Domsters" />
		        <nav>
		                <ul>
		                        <li><a href="index.html">Home</a></li>
		                        <li><a href="about.html">About</a></li>
		                        <li><a href="photos.html">Photos</a></li>
		                        <li><a href="live.html">Live</a></li>
		                        <li><a href="contact.html">Contact</a></li>
		                </ul>
		        </nav>
		</header>
		<article>
				<h1>Lorem Ipsum Dolor</h1>
				<p>Lorem assumenda nihil commodi sequi nemo velit accusamus nulla, magnam a Possimus veniam suscipit omnis culpa doloremque. Eligendi corporis eius quae similique eius Quam nostrum molestias a nemo illo corrupti?</p>
		</article>
</body>
</html> 

颜色

记住,不管为哪个元素应用什么颜色,都要同时给它一个背景色。否则,就有可能导致意外,看不到某些文本。

body {
        color:#fb5;
		background-color: #334;
}
a:link{
		color:#445;
		background-color: #eb6;
}
a:visited{
		color:#345;
		background-color: #eb6;
}
a:hover{
		color:#667;
		background-color: #fb5;
}
a:active{
		color:#778;
		background-color: #ec8;
}
header{
		color:#ec8;
		background-color: #334;
		border-color: #667;
}
header nav {
        color: #445;
		background-color: #789;
		border-color: #667;
}
article {
        color: #223;
		background-color: #edc;
		border-color: #667;
}
header nav ul {
        border-color: #99a;
}
header nav a:link,header nav a:visited {
        color:#eef;
		background-color: #transparent;
		border-color: #99a;
}
header nav a:hover {
        color:#445;
		background-color: #eb6;
}
header nav a:active {
        color:#667;
		background-color: #ec8;
}
article img {
        border-color: #ba9;
		outline-color: #dcb;
}
#imagegally a {
        background-color: transparent;
} 

布局

section,header,article,nav {
        display:block;
}
* {
        padding:0;
		margin:0;
}
body {
        margin:1em 10%;
		background-image: url(..images/background.gif);
		background-attachment: fixed;
		background-position: top left;
		background-repeat: repeat-x;
		max-width: 80em;
}
header {
        background-image: url(..images/guitarist.gif);
		background-repeat: no-repeat;
		background-position: bottom right;
		border-width: .1em;
		border-style: solid;
		border-bottom-width: 0;
}
header nav{
		background-image: url(..images/header navbar.gif);
		background-position: bottom left;
		background-repeat: repeat-x;
		border-width: .1em;
		border-style: solid;
		border-bottom-width: 0;
		border-top-width: 0;
		padding-left: 10%;
}
header nav ul {
        width:100%;
		overflow:hidden;
		border-left-width: .1em;
		border-left-style: solid;
}
header nav li {
        display:inline;
}
header nav li a {
        display: block;
		float: left;
		padding:.5em 2em;
		border-right: .1em solid;
}
article {
        border: .1em;
		border-style: solid;
		border-top-width: 0;
		padding: 2em 10%;
		line-height: 1.8em;
}
article img {
        border-width: .1em;
		border-style: solid;
		outline-width: .1em;
		outline-style: solid;
}

版式

字体和大小显然应该放在版式文件中,而外边距和内边距难以说清,这里将内边距信息放在布局中,外边距信息放在版式中:

body {
        font-size: 76%;
		font-family: "Helvetica","Arial",sans-serif;
}
body * {
        font-size: 1em;
}
a {
        font-weight: bold;
		text-decoration: none;
}
header nav {
        font-family: "Lucida Grande","Helvetica","Arial",sans-serif;
}
header nav a {
        text-decoration: none;
		font-weight: bold;
}
article {
        line-height: 1.8em;
}
article p {
        margin: 1em 0;
}
h1 {
        font-family: "Georgia","Times New Roman",sans-serif;
		font: 2.4em normal;
}
h2 {
        font-family: "Georgia","Times New Roman",sans-serif;
		font: 1.8em normal;
		margin-top: 1em;
}
h3 {
        font-family: "Georgia","Times New Roman",sans-serif;
		font: 1.4em normal;
		margin-top: 1em;
}
#imagegallery li{
		list-style-type: none;
}
textarea {
        font-family:  "Helvetica","Arial",sans-serif;
}

标记

主页index.html添加一段介绍性文字:

<p id="intro">
Welcome to the official website of Jay Skript and the Domsters.
Here,you can <a href="about.html" title="About">learn more about the band</a>,view <a href="photos.html" title="Photos">photos of the band</a>,find out about <a href="live.html" title="Tout date">tour dates</a> and <a href="contact.html" title="Contact">get in touch with the band</a>.
</p>

JavaScript

在编写DOM脚本之前,必须先确定怎么组织JavaScript文件。如果站点需要很多长长的脚本,那最好把它分割成几个小文件。本站很简单,所需的JavaScript代码也不长。为了减少请求的数量,将所有脚本放在global.js文件里。需要添加的函数:addLoadEvent函数,insetAfter函数,addClass函数。

页眉突出显示

修改color.css文件,添加为here类定义的样式:

header nav a.here:link,
header nav a.here:visited,
header nav a.here:hover,
header nav a.here:active{
		color:#eef;
		background-color: #799;
}

增加函数highlightPage:

function highlightPage(){
		if(!document.getElementsByTagName) return false;
		if(!document.getElementById) return false;
		var headers=document.getElementsByTagName("header");
		if(headers.length==0) return false;
		var navs=headers[0].getElementsByTagName("nav");
		if(navs.length==0) return false;
		var links=navs[0].getElementsByTagName("a");
		var linkurl;
		for(var i=0;i<links.length;i++){
				linkurl=links[i].getAttribute("href");
				if(window.location.href.indexOf(linkurl)!=-1){  //比较两者地址(字符串)
						links[i].className="here";
				}
		}
}
function highlightPage(){
		if(!document.getElementsByTagName) return false;
		if(!document.getElementById) return false;
		var headers=document.getElementsByTagName("header");
		if(headers.length==0) return false;
		var navs=headers[0].getElementsByTagName("nav");
		if(navs.length==0) return false;
		var links=navs[0].getElementsByTagName("a");
		var linkurl;
		for(var i=0;i<links.length;i++){
				linkurl=links[i].getAttribute("href");
				if(window.location.href.indexOf(linkurl)!=-1){ 
						links[i].className="here";
						var linktext=links[i].lastChild.nodeValue.toLowerCase();  //转换成小写
						document.body.setAttribute("id",linktext);
				}
		}
}

更新layout.css,添加以下代码:

#about header {
        background-image: url(../images/lineup.gif);
}
#photos header {
        background-image: url(../images/basshead.gif);
}
#live header {
        background-image: url(../images/bassist.gif);
}
#contact header {
        background-image: url(../images/drummer.gif);
}

如此一来,每个页面的头部就会应用不同的背景图像了。

JavaScript幻灯片

需要用到moveElement函数。还要创建幻灯片元素并准备相应链接:

function prepareSlideshow(){
		if(!document.getElementsByTagName) return false;
		if(!document.getElementById) return false;
		if(!document.getElementById("intro")) return false;
		var intro=document.getElementById("intro");
		var slideshow=document.createElement("div");
		slideshow.setAttribute("id","slideshow");
		var frame=document.createElement("img");
		frame.setAttribute("src","images/frame.gif");
		frame.setAttribute("alt","");
		frame.setAttribute("id","frame");
		var preview=document.createElement("img");
		preview.setAttribute("src","images/slideshow.gif");
		preview.setAttribute("alt","a glimpse of what awaits you");
		preview.setAttribute("id","preview");
		slideshow.appendChild(preview);
		insertAfter(slideshow,intro);
		var links==document.getElementsByTagName("a");
		var destination;
		for(var i=0;i<links.length;i++){
				links[i].onmouseover=function(){
						destination=this.getAttribute("href");
						if(destination.indexOf("index.html")!=-1){
								moveElement("preview",0,0,5);
							}
						if(destination.indexOf("about.html")!=-1){
								moveElement("preview",-150,0,5);
							}
						if(destination.indexOf("photos.html")!=-1){
								moveElement("preview",-300,0,5);
							}
						if(destination.indexOf("live.html")!=-1){
								moveElement("preview",-450,0,5);
							}
						if(destination.indexOf("contact.html")!=-1){
								moveElement("preview",-600,0,5);
							}
					}
			}
	}

内部导航

制作About页面。在about.html的<article>元素添加如下标记:

<h1>About the band</h1>
				<nav>
				        <ul>
								<li><a href="#jay">Jay Skript</a></li>
								<li><a href="#domsters">The Domsters</a></li>
				        </ul>
				</nav>
				<section id="jay">
				        <h2>Jay Skript</h2>
				        <p>Jay Skript is going to rock your world!</p>
				        <p>Together with his compatriots the Domsters,Jay is set for world domination,Just you wait and see.</p>
				        <p>Jay Skript has been on the scene since the mid 1990s.His talent hasn't always been recognized or fully appreciated.In the early days,he was often unfavorably compared to bigger,similarly named artists.That is all in the past now.</p>
				</section>
				<section id="domsters">
				        <h2>The Domsters</h2> 
						<p>The Domsters have been around,in one form or another,for almost as long.It is only in the past few years that the Domsters have settled down to their current,stable lineup.Now they are a rock-solid bunch:methodical and dependable.</p>
				</section>

但是页面略长,而<nav>元素中包含的内部链接就是解决这个问题。单击<nav>中的每个链接,都会跳到带有相应id属性的<section>。使用JavaScript和DOM,选择性地每次只显示其中一个部分(section):

function showSection(id){
		var sections=document.getElementsByTagName("section");
		for(var i=0;i<sections.length;i++){
				if(sections[i].getAttribute("id")!=id){
						sections[i].style.display="none";
					}else{
						sections[i].style.display="block";
							}
			}
	}

然后还需要在<article>中的<nav>所包含的链接被单击时调用showSection函数:

function prepareInternalnav(){
		if(!document.getElementsByTagName) return false;
		if(!document.getElementById) return false;
		var articles=document.getElementsByTagName("article");
		if(articles.length==0) return false;
		var navs=articles[0].getElementsByTagName("nav");
		if(navs.length==0) return false;
		var nav=navs[0];
		var links=nav.getElementsByTagName("a");
		for(var i=0;i<links.length;i++){
				var sectionId=links[i].getAttribute("href").split("#")[1];
				if(!document.getElementById(sectionId)) continue;
				document.getElementById(sectionId).style.display="none";
				links[i].destination=sectionId;
				links[i].onclick=function(){
						showSection(this.destination);
						return false;
					}
			}
	}

JavaScript图片库

接下来制作photos.html

<h1>Photos of the band</h1>
				<ul id="imagegallery">
				        <li><a href="images/photos/concert.jpg" title="The crowd goes wild"><img src="images/photos/thumbnail_concert.jpg" alt="the band in concert" /></a></li>
				        <li><a href="images/photos/bassist.jpg" title="An atmospheric moment"><img src="images/photos/thumbnail_bassist.jpg" alt="the bassist"></a></li>
				        <li><a href="images/photos/guitarist.jpt" title="Rocking out"><img src="images/photos/thumbnail_guitarist.jpg" alt="the guitarist"></a></li>
				        <li><a href="images/photos/crowd.jpg" title="Encore!Encore!"><img src="images/photos/thumbnail_crowd.jpg" alt="the audience"></a></li>
				</ul>

更新layout.css,添加:

#imagegallery li{
	display:inline;
}

增强表格

制作live.html页面

<h1>Tour dates</h1>
				<table summary="when and where you can see the band">
				        <thead>
				                <tr>
				                        <th>Date</th>
				                        <th>City</th>
				                        <th>Venue</th>
				                </tr>
				        </thead>
				        <tbody>
				                <tr>
				                        <td>June 9th</td>
										<td>Portland,<abbr title="Oregon">OR</abbr></td>
				                        <td>Crystal Ballroom</td>
				                </tr>
				                <tr>
				                        <td>June 10th</td>
										<td>Seattle,<abbr titlt="Washington">WA</abbr></td>
				                        <td>Crocodile Cafe</td>
				                </tr>
				                <tr>
				                        <td>June 12th</td>
										<td>Sacramento,<abbr title="California">CA</abbr></td>
				                        <td>Torch Club</td>
				                </tr>
				                <tr>
				                        <td>June 17th</td>
										<td>Austin,<abbr title="Texas">TX</abbr></td>
				                        <td>Speakeasy</td>
				                </tr>
				        </tbody>
				</table>

更新layout.css:

td{
			padding:.5em 3em;
		}

更新color.css:

th{
				color:#edc;
				background-color:#455;
		}
tr td{
				color:#223;
				background-color:#eb6;
		}

在global.js中添加stripeTables函数、highlightRows函数和displayAbbreviations函数。 改动:

  • highlightRows:没有直接运用样式,而是使用addClass函数添加了highlight类。

  • displayAbbreviations:将content改为article元素。

更新layout.css

dl{
				overflow:hidden;
		}
dt{
				float:left;
		}
dd{
				float:left;
		}

更新typography.css

dt{
				margin-right:1em;
		}
dd{
				margin-right:3em;
		}

更新color.css

tr.odd td{
				color:#223;
				background-color:#ec8;
		}
tr.highlight td{
				color:#223;
				background-color:#cba;
		}

增强表单

构建一个联系表单

<h1>Contact the band</h1>
				<form method="post" action="submit.html">
				<fieldset>
				        <p>
				                <label for="name">Name:</label>
				                <input type="text" id="name" name="name" placeholder="Your name" required="required">
				        </p>
				        <p>
				                <label for="email">Email:</label>
				                <input type="email" id="email" name="email" placeholder="Your email address" required="required" />
				        </p>
				        <p>
				                <label for="message">Message:</label>
								<textarea cols="45" rows="7" id="message" name="message" required="required" placeholder="Write your message here."></textarea>
				        </p>
						<input type="submit" value="Send" />
				</fieldset>
				</form>

更新layou.css

label{
				display:block;
		}
fieldset{
				border:0;
		}

然后基于模板创建submit.html,添加如下内容:

<h1>Thanks!</h1>
<p>Thanks for contacting us.We will get back to you as soon as we can.</p>

字段标签

表单中有三个字段:name、email和message。每个字段都有一个对应的<label>标签。很多浏览器会对label元素添加默认行为:如果label中的文本被单击,关联的表单字段就会获得焦点。但并不是所有浏览器都实现了该行为,写个函数保证在所有浏览器都有此行为:

function focusLabels(){
				if(!document.getElementsByTagName) return false;
				var labels=document.getElementsByTagName("label");
				for(var i=0;i<labels.length;i++){
								if(!labels[i].getAttribute("for")) continue;
								labels[i].onclick=function(){
												var id=this.getAttribute("for");
												if(!document.getElementById(id)) return false;
												var element=document.getElementById(id);
												element.focus();
										}
						}
		}

表单验证

在使用JavaScript编写验证表单的脚本时,记住三件事:

  • 验证脚本写得不好,反而不如没有验证。

  • 千万不要完全依赖JavaScript。客户端验证并不能取代服务器端的验证。

  • 客户端验证的目的在于帮助用户填好表单,避免他们提交未完成的表单,从而节省他们的时间。

function isFilled(){
				if(field.value.replace(' ','').length==0) return false;
				var placeholder=field.placeholder||field.getAttribute('placeholder');
				return (field.value!=placeholder);
		}

提交表单

function getHTTPObject() {
  if (typeof XMLHttpRequest == "undefined")
    XMLHttpRequest = function () {
      try { return new ActiveXObject("Msxml2.XMLHTTP.6.0"); }
        catch (e) {}
      try { return new ActiveXObject("Msxml2.XMLHTTP.3.0"); }
        catch (e) {}
      try { return new ActiveXObject("Msxml2.XMLHTTP"); }
        catch (e) {}
      return false;
  }
  return new XMLHttpRequest();
}

function displayAjaxLoading(element) {
    // Remove the existing content.
  while (element.hasChildNodes()) {
      element.removeChild(element.lastChild);
  }
  //  Create a loading image.
  var content = document.createElement("img");
  content.setAttribute("src","images/loading.gif");
  content.setAttribute("alt","Loading...");
  // Append the loading element.
  element.appendChild(content);
}

function submitFormWithAjax( whichform, thetarget ) {
  
  var request = getHTTPObject();
  if (!request) { return false; }

  // Display a loading message.
  displayAjaxLoading(thetarget);

  // Collect the data.
  var dataParts = [];
  var element;
  for (var i=0; i<whichform.elements.length; i++) {
    element = whichform.elements[i];
    dataParts[i] = element.name + '=' + encodeURIComponent(element.value);
  }
  var data = dataParts.join('&');

  request.open('POST', whichform.getAttribute("action"), true);
  request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");

  request.onreadystatechange = function () {
    if (request.readyState == 4) {
        if (request.status == 200 || request.status == 0) {
          var matches = request.responseText.match(/<article>([\s\S]+)<\/article>/);
          if (matches.length > 0) {
            thetarget.innerHTML = matches[1];
          } else {
            thetarget.innerHTML = '<p>Oops, there was an error. Sorry.</p>';
          }
        } else {
          thetarget.innerHTML = '<p>' + request.statusText + '</p>';
        }
    }
  };

  request.send(data);
   
  return true;
};

压缩代码

最佳实践

Last updated