web前端面试学习指南_面试 怎么学习前端


JavaScript

代码留空和格式

任何关于代码格式、留空和大括号位置的讨论都会引起激烈辩论。对此,我想最简单的规则就是,除非你愿意把整个代码文件重新格式化,不然还是尊重并保持已有代码文件的格式。这意味着如果你看到一个JS文件里的大括号没有换行写,那你的代码也要继续保持大括号不换行。如果你的代码没有和代码文件里的其他部分保持一致,那么你的代码就不应该通过代码审查流程。

一致的代码格式让代码更加易读,同时也意味着代码容易用查找/替换命令进行修改。谢天谢地,我们自己形成的编程习惯和jQuery正式推荐的方式非常相似。细微的差异也是有的,不过,那些是个人问题或者我们觉得没法维护的一些东西。 参阅jQuery核心样式指南

字符间距

// 不好
if(blah==="foo"){
    foo("bar");
}

// 好 :)
if (blah === "foo") {
    foo("bar");
}

大括号不换行

// 不好
if (foo)
{
    bar();
}

// 好 :)
if (foo) {
    bar();
}

总是用大括号

// 不好
if (foo)
    bar();

// 好 :)
if (foo) {
    bar();
}

字符串处理

引用字符串永远要用双引号。 有些人非常喜欢用C语言风格的字符串(单引号),但这种习惯会导致脚本内部的风格冲突。C语言风格的字符串处理要求空字符串和单字符包在单引号里,而短语和单词必须包在双引号内。

注释

往代码里玩命加注释的需求是由各种经理、主管及其他很少接触代码的人们引领的。这种需求无非是雇员们考核指标中的一个勾选栏,花在这上面的时间基本没有带来什么回报。 如果那些从善如流的开发者能遵循本文档中提出的建议,他们的代码会变得相当易于阅读,一目了然,以至于再用注释描述这些代码会多余得令人尴尬。来看下面的例子。在这里,布尔变量被作为问题提出,而函数也有直观的命名。

if (user.hasPermission) {
    editPage();
}

至少在这个场景中,注释是完全没有必要的。

注释重要的情况

一个项目里,永远会有某些部分难以查阅和理解。比如一个复杂的正则表达式,或者一个对角度进行计算或在度和弧度单位之间切换的数学函数。没有上面的注释,初级或中级的读者将对脚本的含义毫无头绪。

// 校验美国电话号码的正则表达式,号码格式是 (XXX) XXX-XXXX (减号、空格和括号都是可选的,可以有也可以没有)
var phoneRegEx = /^\(?(\d{3})\)?[- ]?(\d{3})[- ]?(\d{4})$/;
总是使用 === 比较符

使用 == 比较符可以让令人郁闷的bug消失于无形。它允许在 JavaScript花园 中有清楚解释的弱类型。使用严格的 === 比较符不会执行类型强制转换,从而能够严格地评估两个对象之间的差别。再说一遍,更多详细信息请参见 JavaScript花园

var zeroAsAString = "0";

if (zeroAsAString == 0) {
    // 这样也能判断为true,呵呵...
}

if (zeroAsAString === 0) {
    // 判断为false
}

例外

在和null进行比较的时候,允许使用 == 比较符,因为它会检测null和undefined两个属性。如果你不完全理解这个原理,那我还是建议你用 === 比较符为好。

var foo = null;

// foo 是 null, 但 bar 是 undefined ,因为它尚未被声明
if (foo == null && bar == null) {
    // 上面的判断还是成立的
}

使用 .parseInt() 的时候,总是指定第二个 ‘radix’ 参数

把字符串解析为整数的时候,有个好习惯是指定第二个基数参数 – 它会确定该字符串被转换成几进制。当字符串以 0 开头的时候,默认情况下会触发 16 进制作为基数。大部分初级和中级用户只会用到 10 这个基数。 感谢 João Moreno 记录的这个 勘误

alert( parseInt("08") ); // alerts: 2

alert( parseInt("08", 10) ); // alerts: 8
避免比较 true 和 false

直接比较 true 和 false 的值是没有必要的。有时候也许明确一下有好处,但它还是额外的代码。

if (foo === true) {
    // 用了 === 倒是不错,可这是多余的
}

if (foo) {
    // 赞!
}

if (!bar) {
    // 反过来也赞
}
避免污染全局命名空间

过分依赖全局变量是我们组所有人 – 特别是我自己 – 特别有负罪感的一件事。关于为啥全局变量不好的讨论是相当直接的:这增加了脚本和变量冲突的概率,而且源文件和命名空间本身都会充斥着数不清的命名模糊的变量。

Douglas Crockford 坚信一个Javascript应用的代码质量可以用其中使用的全局变量数来评价,越少越好。由于并不是什么都可以定义成local的(不过要诚实,其实你现在考虑的那个是可以的,别偷懒),你需要想办法整理你的变量以避免冲突,并把命名空间的膨胀减到最小。最简单的方法就是采用单变量或者把用到这些全局变量的模块尽可能减少。 Crockford提到YUI只用了一个全局变量,YAHOO。他在他的博文 “全局统治” 中讨论了更多的细节问题。

考虑这种情况:对于小型web应用,全局变量通常用于保存应用级的设置,可以用你的项目名或者settings作为命名去定义一个对象,这样总的来说会更好。

// 被污染的全局命名空间
var settingA = true;
var settingB = false;
var settingC = "test";

// 用 settings 作为对象命名
var settings = {
    settingA: true,
    settingB: false,
    settingC: "test"
}

不过,如果我们可以通过避免使用全局变量来减少冲突概率,但是把命名空间标准化成一样的,岂不是会增加各个应用之间产生冲突的概率么?呃,这个担忧确实有道理。所以,建议你用自己特定的应用名作为全局变量的命名空间,或者用和jQuery采取的 $.noConflict() 模式相同的方法重新分配你的命名空间.

var myAppName = {
    settings: {
        settingA: true
    }
}

//访问全局变量
myAppName.settings.settingA; // true
驼峰法变量命名

JavaScript变量的驼峰法命名在大部分编程环境中都是作为标准的。有读者在评论中提出了唯一的例外,就是要用大写字母加下划线来指代常量。

var X_Position = obj.scrollLeft;

var xPosition = obj.scrollLeft; // 更好,更简洁

SCENE_GRAVITY = 1; // 常量
循环的性能 - 缓存数组长度

循环估计是Javascript性能调优最重要的部分了。在一个循环内部节省个一两毫秒的,说不定总体就省出好几秒来了。这里有一招就是把数组的长度缓存,这样在循环里就无需每次迭代的时候都计算一遍了。

var toLoop = new Array(1000);

for (var i = 0; i < toLoop.length; i++) {
    // 败家玩意 - 长度会反复算 1000 次你知道不?
}

for (var i = 0, len = toLoop.length; i < len; i++) {
    // 会过日子 - 长度只计算一次,然后缓存了
}

例外

如果你对一个数组做循环来查找并删除某个元素,这就会改变数组长度。任何时候你只要会在循环内部增加或删除元素来改变数组的长度,你就给自己带来了麻烦。这种情况下,你要么每次改变后重新设置数组长度,要么就别缓存它了。

循环的性能 - 使用 ‘break;’ 和 ‘continue;’

跳过和跳出循环的能力对于避免开销很大的循环周期是非常有用的。

如果你是在循环内部查找,查找成功以后你会做什么?比如1000个元素的循环执行到一半,你就找到了你要的东西。你不管三七二十一,即使知道后面的if语句不会再有符合的机会,还是让循环继续把剩下的500个元素迭代完么?不!你应该跳出循环,必须的!

var bigArray = new Array(1000);

for (var i = 0, len = bigArray.length; i < len; i++) {
    if (i === 500) {
        break;
    }
    console.log(i); // 这样只会输出 0 - 499
}

另一个问题是跳过某个特定的迭代,然后继续循环。虽然说类似于奇偶数这样的条件可以通过把 i++ 替换成 i + 2 的办法来管理,有些条件还是需要具体检测,然后触发跳过操作。任何能够避免执行完整的迭代过程的东西都是很有用的。

var bigArray = new Array(1000);

for (var i = 0, len = bigArray.length; i < len; i++) {
    if (condition) {
        continue;
    }
    doCostlyStuff();
}

函数调用不要传输太多的参数

对于可读性而不是其他因素来说,下面这种方式真是糟透了:

function greet(name, language, age, gender, hairColour, eyeColour) {
    alert(name);
}

下面的例子预先构建了一个对象作为参数,或者把内联对象传递过去,这样就好多了。

function greet(user) {
    alert(user.name);
}

greet({
    name: "Bob",
    gender: "male"
});
把 ‘this’ 映射为 ‘self’

在编写面向对象(OO)Javascript代码的时候, 必须了解 this 的作用范围. 不管你用来构建伪类的设计模式是什么,对 this 的引用是指向一个实例的最简单办法。当你开始把jQuery的helper方法和你的伪类集成的时候,你就会注意到 this 的作用范围变化。

Bob.findFriend("Barry");

Person.prototype.findFriend = function(toFind) {
    // this = Bob
    $(this.friends).each(function() {
        // this = Bob.friends[i]
        if (this.name === toFind) {
            // this = Barry
            return this;
        }
    });
}

在上面的例子里, this 经历了从对 Bob 的引用,变成对他的朋友 Barry 的引用的过程。 了解 this 的取值在一段时间发生的变化是很重要的。在原型函数内部, this 指向所在伪类的当前实例(这里是 Bob )。而一旦我们进入 $.each() 循环, this 就会重新映射为被解析数组的第 i 个元素。

解决办法是把 this 的值重新映射为 self 或者 _self。虽然 self (不带下划线)并不是 保留字, 但它 确实是 window 对象的一个属性。虽然我上面用到 self 的例子是从jQuery源代码中挑的,但他们也认识到了这个错误,正打算 修正目前的状况 ,也就是改用 _self。我个人还是喜欢用 self ,不为别的,就因为它的简洁 – 不过它可能会冒出一些非常令人困惑的bug。总之,用 self 有风险,使用需谨慎。

在下面的例子中,我会更好地利用在 $.each() helper 中提供的参数,同时重新映射 this 的值。

Bob.findFriend("Barry");

Person.prototype.findFriend = function(toFind) {

    // 就这一次用到了 "this"
    var _self = this;

    $(_self.friends).each(function(i,item) {
        if (item.name === toFind) {
            return item;
        }
    });

}
我能用 Boolean 吗?

布尔变量必须能够很容易通过命名来识别。可以用类似于 iscan 或者 has 的前缀来形成一个问句。

isEditing = true;

obj.canEdit = true;

user.hasPermission = true;  
尽量减少重新绘制和重新布局

重新绘制和重新布局与重新渲染DOM的过程关联,这个过程会在特定属性或元素被改变时发生。重新

真题解析、进阶学习笔记、最新讲解视频、实战项目源码、学习路线大纲
详情关注公中号【编程进阶路】

绘制是在某个元素的外观被改变但没有对布局进行调整的情况下触发的。 Nicole Sullivan 在一篇全面的 博文 中把这些改变描述为诸如是否可见或背景色变化之类的样式改变。重新布局则是开销更大的操作,由调整页面布局的一些改变引发。例如增加或删除元素,改变某个元素的宽度或高度,甚至是改变浏览器窗口的大小。最糟糕的情况是重新布局导致先辈、兄弟和孩子节点元素也需要重新布局的多米诺骨牌效应。

毫无疑问,重新绘制和重新布局应该尽量避免,但是如何做到呢?

重新布局的例子

其实也不是说下面的代码就很糟糕啦。不过我们先假定数组 arr 有10个元素

var myList = document.getElementById("myList");

for (var i = 0, len = arr.length; i < len; i++) {

    myList.innerHTML += "<li>" + arr[i].title + "</li>"; //重新布局 -- 增加到元素

}

在上面的 for 循环里,每次迭代会触发一次重新布局。10次迭代就是10次重新布局。

现在考虑下面的代码:

var constructedHTML = "";

for (var i = 0, len = arr.length; i < len; i++) {
    constructedHTML += "<li>" + arr[i].title + "</li>"; //没有重新布局 - 增加到字符串
}

document.getElementById("myList").innerHTML = constructedHTML; //在这里重新布局

在这个场景里,需要增加的元素是在一个字符串里构建的。循环里边没有产生任何重新布局,因为DOM并没有变化。只有当数组被完全循环完毕,构建的字符串被应用到某个对象的 innerHTML ,这才产生函数里唯一的一次重新布局。

有无数种重新布局和重新绘制是可以避免的,希望你幸运地了解了那些诀窍。这方面的阅读材料汗牛充栋,不过大部分的材料都会引用到 Nicole Sullivan的这篇 博文 ,这是一个完美的起点。除了这里的经验,在涉及到"web 3.0"和HTML5时代的多种技术术语的时候,还有其他重要的经验教训值得汲取。上面的分析直接适用于写jQuery代码。在捣腾 canvas 的时候这些原则也很重要,另外尽量保持帧频在30-60的范围内。

不要用微秒来产生唯一的ID

自打web开发早期开始,就流行一种产生唯一ID的方法。具体做法是把从1970年1月1日开始计算的微秒数加到你的静态ID后面,如下所示:

var myID = "static" + new Date().getTime();

这本来是相当万无一失的方法,因为即便两段这样的代码连续执行,在它们执行的间隙也会有几毫秒。可是现在新的浏览器带着新的Javascript引擎,伴随着一直在提升的主频。到现在,上面的代码产生相同的毫秒数的可能性会比产生间隙的可能性更大。

这会导致传统方法难以debug的bug。因为你的DOM是在运行中创建的,对页面源代码进行传统的测试无法确定多个重复ID的错误。Javascript和jQuery的错误处理机制会把第一个匹配的作为ID并忽略其他的重复ID。所以它甚至都不会抛出JS错误!

这样不行,唯一真正的方法是逐行设断点和log,但是如果断点的位置不对,你的毫秒数又不会冲突了!

好消息是有很多产生唯一ID的替代方法。学究气一点的说法是,计算机的随机数函数其实并不是真正随机的,因为它还是来源于系统时间,虽然这一点值得注意,但是随机数冲突的可能性是微乎其微的。

var myID = "static" + Math.round(Math.random() * 10000);

我个人更偏爱人工产生GUID方法。从技术角度说,GUID是根据你的硬件创建的,不过下面的Javascript函数做得相当棒。这是我从 stack overflow 的一个帖子 里偷来的,相当顺手的一个函数。

function S4() {
   return (((1+Math.random())*0x10000)|0).toString(16).substring(1);
}
function guid() {
   return (S4()+S4()+"-"+S4()+"-"+S4()+"-"+S4()+"-"+S4()+S4()+S4());
}
var myID = "static" + guid();
检测特性,而不是检测浏览器类型

用户的浏览器是否支持地理信息?用户的浏览器是否支持web works?HTML5 视频?HTML5 音频?答案曾经是这样的:

if ($.browser.msie) {
    // 哦,是IE啊,那肯定不支持
}

但是世界在快速变化。最新版的IE几乎能算是现代浏览器了,但它依旧给前端开发带来痛苦。更早版本的IE基本上和它之前的版本一样烂,这就让偷懒的Javascript程序员习惯于检测 if (ie) 然后执行一些微软专用的破语法。现在IE9已经废弃了这些专用函数,那些原来的 if (ie) 老古董就反而会坏事了。

那么,如果能检测每个特性而不用检测(既不可靠又能伪装的)user-agent,你觉得咋样?

如果你的回答是 “那相当靠谱”, 那你就说对了。

用 Modernizr 吧,这是行业梦幻级大师Paul Irish参与开发的一个Javascript库。该库集广泛应用、轻量级和海量文档三大优势于一身,实施无需动脑,实为居家旅行、杀人灭口必备。它会产生一个 Modernizr 对象,其中包含了它所有检测测试的结果,这样检测某个特性的支持与否就和下面的例子一样简单:

// 检测浏览器是否支持canvas的老办法
if (!!document.createElement('canvas').getContext) { ... }

// 用 Modernizr 检测
if (Modernizr.canvas) { ... }
使用可读的毫秒数

毫秒数的一种方便的写法是写成可读的。对于初学者这很棒,但是大部分情况下其实只是一个噱头。

// 这是3秒,30秒还是300秒啊?
var timeout = 30000;

// 增加了额外的计算开销,但是读和修改会更容易
var timeout = 30 * 1000;

关于jQuery代码

像疯狗一样串接

jQuery最好的特性之一就是它的函数串接。你可能已经用过一点,也许把一些简单的调用一个接一个串起来…但是你是否曾经像头疯狗一样在DOM里上蹿下跳地遍历呢?还是花点时间来熟悉一下 .end()") 函数。等你从起始选择器开始在DOM里上蹿下跳的时候,这个函数会很关键。

$(".quote")
    .hide()
    .find("a").text("Click here").bind("click",doStuff).end()
    .parent().removeClass().addClass("testimonial").draggable().end()
    .fadeIn("slow");

上例中,每次我们完成对某个DOM对象的操作,要反向遍历DOM返回我们引用的原始对象的时候,就需要使用 .end()") 函数。然后我们就顺藤摸瓜扎回原来DOM里的位置了。

使用 data-* 属性

你们当中那些已经写了很长时间Javascript(原生的,不是jQuery)代码的同学,很可能都熟悉各种属性吧。你们想办法设置它们,获取它们,或者滥用 rel 和 title …

别说HTML5 或者 jQuery 没帮上忙哦。新的描述中允许在HTML元素中使用 data- 前缀来指明包含数据的属性,jQuery会把指定的字符串转换成正确的Javascript数据类型,这活干的非常漂亮。我们来创建一个带有某些数据属性的 DIV 。

<div id="test" data-is-bool="true" data-some-number="123"></div>

现在,即使我们的值被包装在引号里面,它们也不会被当做字符串处理:

typeof $("#test").data("isBool"); // boolean

typeof $("#test").data("someNumber"); // number

特殊的大小写

要注意,要让这些代码片段正常工作,(HTML里的属性定义)必须使用小写字母,这很重要。不过如果你是一位很强的前端开发者,你还是会想用驼峰法来命名你的数据变量。正如在Javascript里很多地方出现的,前置的连接符意味着下一个字母会适用于驼峰法大写。不过,下面的例子里在HTML属性定义中使用驼峰法是 不行的 ,会让上面的Javascript代码返回 undefined

不好使 😦

<div id="test" data-isBool="true" data-someNumber="123"></div>

好使 😃

<div id="test" data-is-bool="true" data-some-number="123"></div>
‘.stop()’ 停止协作和监听

把jQuery动画效果和鼠标事件绑定是基于web的现代用户交互方式中的关键部分,可是这方面即便某些最有名的网站也做得很蹩脚。这篇文章 提供了一个实现动画的直接例子并且演示了这些动画放在一起在视觉上会产生多么不和谐的效果。 好在这个问题可以利用一个函数前缀或在 $.animate 调用中加入一个参数来轻松解决。

在使用  . a n i m a t e ∗ ∗  的时候,可以在参数中加入  ∗ ∗ q u e u e : f a l s e ∗ ∗  来避免串接。诸如  ∗ ∗ .animate** 的时候, 可以在参数中加入 **queue: false** 来避免串接。诸如 ** .animate 的时候,可以在参数中加入 queue:false 来避免串接。诸如 .fadeIn 或  . s l i d e D o w n ∗ ∗  这样的动画快捷方式不接受  ∗ ∗ q u e u e ∗ ∗  设置,你必须用  ∗ ∗ .slideDown** 这样的动画快捷方式不接受 **queue** 设置,你必须用 ** .slideDown 这样的动画快捷方式不接受 queue 设置,你必须用 .stop 这个方法预先停止这些动画.。 在特定的场景下,需要某个动画直接停下,或跳转到变换的最终状态。推荐你先熟悉有关 clearQueue 和 jumpToEnd 这两个参数的相关 文档 ,因为老天在上,我没有其他办法帮你。

$("selector").stop(true,true).fadeOut();

$("selector").animate({
    property: value
}, {
    duration: 1000,
    queue: false
}
优化你的选择器

jQuery 很高冷。它几乎无所不能,不过它目前还没法给你冲咖啡,我听说在2.0版的路线图里有才这个特性。你需要当心的一件事是别滥用它的 sizzleJS 选择器引擎的能力。想避免这种问题可以有两个策略:缓存选择器结果 以及 使用高效率的选择器

缓存选择器结果

是每次你要修改一点东西的时候都先进行开销巨大的DOM查询,还是保存一份元素的索引?选择一目了然。

// before
$(".quote a").bind("click", doStuff); // DOM查询

// now
$(".quote a").addClass("quoteLink"); // DOM查询!!

// later
$(".quote a").fadeIn("slow"); // 又一次DOM查询!!!

忽略串接,这样做更好:

// before
var $quoteLinks = $(".quote a");  // 只需一次DOM查询
$quoteLinks.bind("click", doStuff);

// now
$quoteLinks.addClass("quoteLink");

// later
$quoteLinks.fadeIn("slow");

使用高效率的选择器

好了,jQuery/sizzleJS 可以轻松使用CSS3选择器,但是真正的开销是什么? 在这种场景下浏览器有可能会使用 document.querySelector(), 但是它也有可能分拆你的选择器字符串,然后手工去查询DOM。

// ID搜索是最快的查询方式,然后它获取孩子节点的列表,匹配其中class为'quotes'的元素
$("#quoteList").children(".quotes");

// 只在预先确定的bar元素下查找'foo'class
$(".foo",bar); 

‘for’ 循环总是比 ‘each()’ 循环快

不管未来几年在浏览器开发领域会发生什么,本地的 for 循环永远会比jQuery的 $.each() 循环快。 当你思考jQuery到底是什么(把本地JS函数包装起来的一个库)这种高大上问题的时候,你就会开始认识到本地原生Javascript代码永远会更快。用库还是用原生,这是一个运行速度和编程速度之间的权衡。

很重要的一点是,对那些可能每秒调用数百次的性能关键的函数,总是要使用 for 循环。例如:

  • 鼠标移动
  • 时间间隔
  • 循环内部的循环

CSS

理解盒子模型是关键

"盒子模型"对于理解浏览器如何渲染页面是关键性决定性的因素。对其复杂性的全面理解有助于奇迹般地简化你的工作。盒子模型描述了对HTML元素的物理维度进行计算的方式。如果一个块元素具有固定宽度,比如说100px,那么应该如何确定它的 padding, border 和 margin 呢?

很多网站都有深入的描述,但咱们简单点说:在遵循标准的浏览器中,border和padding是被放在指定宽度之外的。最好是用图形来解释。比如下列代码:

.foo {
    width: 150px;
    height: 150px;
    padding: 25px;
    border: 25px solid;
    margin: 20px;
}

你可能估计的情况(Quirks 模式)

padding 和 border 都是往里算的,结果保持高度和宽度都是150px。

你看到的情况(遵循标准模式)

可是,实际上出来的宽度和高度都是250px。 也就是150px + (2 * 25) + (2 * 25)。

如果你觉得这个结果很奇怪,那你不是一个人(呃,你是人,只是说还有其他人也会这么想)。 现在手头有个修复办法,需要引入一个CSS属性叫 box-sizing,这个属性对于 IE8 及以上版本 都适用。它允许你选择计算元素维度的确切方式,这样就能救你于危难之中。具体支持的参数因浏览器而异,另外需要用到浏览器厂商的前缀,具体细节请参阅 caniuse.com 。

/* 旧方法 (178 + 20 + 2 = 200) */
.foo {
    width: 178px;
    padding: 10px;
    border: 1px;
}

/* 更好的方法 */
.foo {
    width: 200px;
    padding: 10px;
    border: 1px;
        -webkit-box-sizing: border-box;
        -moz-box-sizing: border-box;
        box-sizing: border-box;
}

虽然说你也总是可以对宽度进行心算,在各个像素数中减来减去(就像第一个方法做的那样),但在涉及到不同的宽度单位时(比如百分比或者EM),就没人能搞清楚到底该怎么做了。目前,除了把元素包在父元素中,以确保宽度和 padding/margin/borders 可以全部分开之外,也没有别的解决办法。

知道什么时候用float,什么时候用position

用table进行布局的时代过去了。现在要承认我们可以集中精力去理解float和position的工作原理。这里需要掌握一套特别的思维模型,我相信这件事最好是通过动手练习来进行。

用float从DOM中提取元素并强制它们靠到左边或右边,那是相当靠谱。它们已成为前端开发的后table布局时代的万金油,这可能是因为以前浏览器对于 display: inline 和 inline-block 的支持不力,还有对position的支持中冒出的 z-index bug。可现在就真的没有借口了。 inline-block 已经支持得很好了,简单的一点修正就能让它在 IE7 里应用。

谢天谢地,以前那些阻挠用CSS对元素进行绝对定位的争论都消亡了。理论上,定位属性可以让你在页面上以X和Y坐标放置元素,这种方式简单直接,Flash开发者们都应该很熟悉。

理解 Position

用CSS定位元素的时候,理解一个事实非常重要:定位的位置总是相对于离它最近的有定位属性的父元素而言的。人们刚开始用CSS的时候会有一个常见的误解,认为 position: absolute; 是相对页面的root元素定位的。 我觉得这种误解来源于某些情况下,元素没有任何父元素具备position样式 – 在这种情况下,他们的结论是对的。这样向上遍历DOM树没有找到任何有定位样式的元素,就会定位到页面的根元素上。

那么,如果 position: absolute; 是把元素从他们所在的流中抽取出来,那你如何相对一个元素的父元素对它进行定位呢? 方法很直接。父元素需要定义 position: relative; 样式,然后所有的孩子元素就会按上、右、下、左的顺序依次摆放。利用这个知识,你会如何实现下面很直观的布局呢?

web浏览器中的javascript

  • 客户端javascript
  • 在html里嵌入javascript
  • javascript程序的执行
  • 兼容性和互用性
  • 可访问性
  • 安全性
  • 客户端框架

window对象

  • 计时器

  • 浏览器定位和导航

  • 浏览历史

  • 浏览器和屏幕信息

  • 对话框

  • 错误处理

  • 作为window对象属性的文档元素

  • 10
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值